20191223のLinuxに関する記事は13件です。

コマンドから環境変数に追加しましょう~

はじめに

私は開発する時にWindowsとLinuxを使っています。時々他の方が作ったライブラリーを使う事があります。その時はできるだけインストーラーを使わずにZIPやTARでダウンロードしてから使うようにしています。インストーラーを使うと環境変数に新しい情報追加されたり、実行ファイルを色々な場所にコピーされたりします。一時的に動かしたいのに既存の環境に影響与えるのなんか気持ち悪いです。そのため、タミナルを起動して一時的に環境変数を変更してから使うようにしています。変更の影響はそのタミナルのみなのでほかのシステムには何の影響も与えません。そのタミナルを閉じれば、設定も全部元通りになります。

それぞれの環境で以下のようにPATH変数に実行ファイルがあるフォルダーのパスを追加してから使います。

Linux

export PATH=$PATH:/opt/dakc/bin

Windows

1. Command Promt

set PATH=%PATH%;C:\dakc\bin

2. Powershell

$env:Path += ";C:\dakc\bin"
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MySQLにLinuxコマンドからエクスポート、インポートする方法

よく忘れるのでメモ用。

特定のデータベースの中身を全てエクスポート

以下のコマンドをクリック。

mysqldump -u root -p testdb > dump.sql

以上の例では、
rootユーザー、testdbというデータベース名になります。
tesdbの中身を「dump.sql」というファイル名で出力します。

以上のコマンドを打った後、パスワードが求められます。

特定にデータベースsqlファイルをインポート

以下のコマンドをクリック。

mysql -u root -p testdb < dump.sql

以上の例では、
rootユーザー、testdbというデータベース名になります。
dump.sqlのファイルを、testdbにインポートします。

以上のコマンドを打った後、パスワードが求められます。

以上

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerの再入門

仕事でDockerを使うのは2016年から4年近く経ちました。会社の技術雑談会のきっかけで今まで、断片的に習うDockerについての知識を整理してみます。この文章はdockerの操作コマンドやDockerfileの書き方より本来はなんでdockerというものが作られるのか、dockerの後ろに使われる技術を掘り下げます。

目次

  • ITインフラの進化を振り返り
  • 仮想化
  • Docker
  • Dockerの特徴

〜ITインフラの進化を振り返り〜

ITインフラがコンピューターの発明から約70年となっていろんな進化を遂げた。その中に、ITインフラのリソースをいかに効率的に利用できるよう、いろんな技術が誕生しました。現在のサーバ仮想化の原点は1970年代にメインフレームに使われる仮想化技術となり、そのあと、1999ごろにVMWare社の誕生によるx86 CPUサーバ仮想化も一気に進めることになりました。

alt
図は[1]を参考しています。

クラウド時代において不可欠の〜仮想化〜

仮想化といっても、いろんな仮想化が存在しております。ネットワーク仮想化する、サーバ仮想化、アプリケーション仮想化などの多数のキーワードがあります。ここでサーバー仮想化をメインにまとめます。

サーバ仮想化

サーバ仮想化とは、1台の物理サーバ上に複数のサーバとみなしで稼働させることです。
サーバ仮想化をすることで、サーバ台数の減少でコスト削減につながります。
では、サーバ仮想化はどういう手法があるでしょう。ネットで仮想化を検索すると、必ずホスト型とハイパーバイザー型があるという言葉が出てきます。
しかし、wikipediaのハイパーバイザーの定義をみると、実際にはこの二つ型全部ハイパーバイザーとなるといえるでしょう。
そもそも、ハイパーバイザー[2]とはコンピュータ用語における、コンピュータの仮想化技術のひとつである仮想機械(バーチャルマシン)を実現するための、制御プログラムである。仮想化モニタや仮想化OSと呼ばれることもある。
wikipediaの定義によると、ハイパーバイザーは二つのタイプがあります。

  • Type 1(「ネイティブ」または「ベアメタル」)ハイパーバイザ

ハイパーバイザがハードウェア上で直接動作し、全てのOS(ゲストOS)はそのハイパーバイザ上で動作する方式を指す。狭義の「ハイパーバイザ」はこちらのみを指す。

製品:Microsoft Hyper-V、Citrix XenServer

alt

  • Type 2(「ホスト」)ハイパーバイザ

ハードウェア上でまず別のOSが稼働し(このOSをホストOSと呼ぶ)、その上でハイパーバイザが(ホストOSのアプリケーションとして)稼働し、更にはハイパーバイザの上で更に別のOS(このOSをゲストOSと呼ぶ)を稼働させる方法である。狭義においては、Type 2はハイパーバイザには含まれない。

製品:オラクルのVirtualBox、パラレルスのParallels WorkstationとParallels Desktop

alt

よく言われるホスト型仮想化はハイパーバイザーのType2、ハイパーバイザーはType1ということでしょう。

Type 1はリソースの完全分離し、各仮想サーバは直接ハードウェアとやりとりするので、処理スピードが早いというメリットがあります。一方で、導入コストが高いというデメリットもあります。

Type 2は仮想化ソフトウェアをホストOSにインストールすれば、すぐに仮想サーバを構築できることで、導入コストが少ないメリットがありますが、仮想サーバはホストOSを介してハードウェアとやりとりので、オーバヘッドが大きくなて処理スピードが落ちるというデメリットがあります。

Linux container (LXC)

通常、物理サーバー上にインストールしたホストOSでは、1つのOS上で動く複数のアプリケーションは、同じシステムリソースを使います。このとき、動作する複数のアプリケーションは、データを格納するディレクトリを共有し、サーバーに設定された同じIPアドレスで通信します。そのため、複数のアプリケーションで使用しているミドルウェアやライブラリのバージョンが異なる場合などは、お互いのアプリケーションが影響を受けないよう注意が必要です[3]。
サーバ仮想化をすることで、OS丸ごとに分離し、各仮想OSに一個のアプリケーションを実装することは完全に上記の課題を解決するのが可能ですが、そうすると、物理サーバの利用率が非常に悪いでしょう。そのため、ここでハイパーバイザーによりハイレベルで軽量の仮想化技術が誕生しました。

LXC(英語: Linux Containers)[4]は、1つのLinuxカーネルを実行しているコントロールホスト上で、複数の隔離されたLinuxシステム(コンテナ)を走らせる、OSレベル仮想化のソフトウェアである。

Linuxカーネルがcgroupsという機能を提供を利用することで、リソース(CPU、メモリ、ブロックI/O、ネットワークなど)の制限と優先順位付けが可能になっており、そのために仮想マシンを使用する必要がない。また、名前空間の隔離機能を利用すれば、アプリケーションから見たオペレーティング・システムの環境を完全に隔離することができるため、プロセスツリー、ネットワーク、ユーザー識別子、マウント(英語版)されたファイルシステムを仮想化することができる。

LXCはカーネルのcroupsと隔離された名前空間のサポートを組み合わせることで、アプリケーションのために隔離された環境を提供する。

cgroup

cgroups (control groups) [5]とは、プロセスグループのリソース(CPU、メモリ、ディスクI/Oなど)の利用を制限・隔離するLinuxカーネルの機能。"process containers" という名称で Rohit Seth が2006年9月から開発を開始し、2007年に cgroups と名称変更され、2008年1月に Linux カーネル 2.6.24 にマージされた。それ以来、多くの機能とコントローラが追加された。

Linux man[6]の説明は以下の通りです。

Control groups, usually referred to as cgroups, are a Linux kernel feature which allow processes to be organized into hierarchical groups whose usage of various types of resources can then be limited and monitored. The kernel's cgroup interface is provided through a pseudo-filesystem called cgroupfs. Grouping is implemented in the core cgroup kernel code, while resource tracking and limits are implemented in a set of per-resource-type subsystems (memory, CPU, and so on).

Subsystemsはカーネルのリソースモジュールとして理解すればいいだと思います。cgroupがコントロールするSubsystemsは以下の通りです。

  cpu (since Linux 2.6.24; CONFIG_CGROUP_SCHED)
          Cgroups can be guaranteed a minimum number of "CPU shares"
          when a system is busy.  This does not limit a cgroup's CPU
          usage if the CPUs are not busy.  For further information, see
          Documentation/scheduler/sched-design-CFS.txt.

          In Linux 3.2, this controller was extended to provide CPU
          "bandwidth" control.  If the kernel is configured with CON‐
          FIG_CFS_BANDWIDTH, then within each scheduling period (defined
          via a file in the cgroup directory), it is possible to define
          an upper limit on the CPU time allocated to the processes in a
          cgroup.  This upper limit applies even if there is no other
          competition for the CPU.  Further information can be found in
          the kernel source file Documentation/scheduler/sched-bwc.txt.

   cpuacct (since Linux 2.6.24; CONFIG_CGROUP_CPUACCT)
          This provides accounting for CPU usage by groups of processes.

          Further information can be found in the kernel source file
          Documentation/cgroup-v1/cpuacct.txt.

   cpuset (since Linux 2.6.24; CONFIG_CPUSETS)
          This cgroup can be used to bind the processes in a cgroup to a
          specified set of CPUs and NUMA nodes.

          Further information can be found in the kernel source file
          Documentation/cgroup-v1/cpusets.txt.

   memory (since Linux 2.6.25; CONFIG_MEMCG)
          The memory controller supports reporting and limiting of
          process memory, kernel memory, and swap used by cgroups.

          Further information can be found in the kernel source file
          Documentation/cgroup-v1/memory.txt.

   devices (since Linux 2.6.26; CONFIG_CGROUP_DEVICE)
          This supports controlling which processes may create (mknod)
          devices as well as open them for reading or writing.  The
          policies may be specified as allow-lists and deny-lists.
          Hierarchy is enforced, so new rules must not violate existing
          rules for the target or ancestor cgroups.

          Further information can be found in the kernel source file
          Documentation/cgroup-v1/devices.txt.

   freezer (since Linux 2.6.28; CONFIG_CGROUP_FREEZER)
          The freezer cgroup can suspend and restore (resume) all pro‐
          cesses in a cgroup.  Freezing a cgroup /A also causes its
          children, for example, processes in /A/B, to be frozen.

          Further information can be found in the kernel source file
          Documentation/cgroup-v1/freezer-subsystem.txt.

   net_cls (since Linux 2.6.29; CONFIG_CGROUP_NET_CLASSID)
          This places a classid, specified for the cgroup, on network
          packets created by a cgroup.  These classids can then be used
          in firewall rules, as well as used to shape traffic using
          tc(8).  This applies only to packets leaving the cgroup, not
          to traffic arriving at the cgroup.

          Further information can be found in the kernel source file
          Documentation/cgroup-v1/net_cls.txt.

   blkio (since Linux 2.6.33; CONFIG_BLK_CGROUP)
          The blkio cgroup controls and limits access to specified block
          devices by applying IO control in the form of throttling and
          upper limits against leaf nodes and intermediate nodes in the
          storage hierarchy.

          Two policies are available.  The first is a proportional-
          weight time-based division of disk implemented with CFQ.  This
          is in effect for leaf nodes using CFQ.  The second is a throt‐
          tling policy which specifies upper I/O rate limits on a
          device.

          Further information can be found in the kernel source file
          Documentation/cgroup-v1/blkio-controller.txt.

   perf_event (since Linux 2.6.39; CONFIG_CGROUP_PERF)
          This controller allows perf monitoring of the set of processes
          grouped in a cgroup.

          Further information can be found in the kernel source file
          tools/perf/Documentation/perf-record.txt.

   net_prio (since Linux 3.3; CONFIG_CGROUP_NET_PRIO)
          This allows priorities to be specified, per network interface,
          for cgroups.

          Further information can be found in the kernel source file
          Documentation/cgroup-v1/net_prio.txt.

   hugetlb (since Linux 3.5; CONFIG_CGROUP_HUGETLB)
          This supports limiting the use of huge pages by cgroups.

          Further information can be found in the kernel source file
          Documentation/cgroup-v1/hugetlb.txt.

   pids (since Linux 4.3; CONFIG_CGROUP_PIDS)
          This controller permits limiting the number of process that
          may be created in a cgroup (and its descendants).

          Further information can be found in the kernel source file
          Documentation/cgroup-v1/pids.txt.

   rdma (since Linux 4.11; CONFIG_CGROUP_RDMA)
          The RDMA controller permits limiting the use of RDMA/IB-spe‐
          cific resources per cgroup.

          Further information can be found in the kernel source file
          Documentation/cgroup-v1/rdma.txt.

例:CPU利用率を制限

cgroupの操作はcgroupfsというファイルシステムを経由で行います。基本的にLinuxが起動する際に、cgroupfsを自動的にmountをする。

$ mount | grep cgroup
cgroup on /sys/fs/cgroup/unified type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)

ここから、cgroupでアプリのCPU使用率を制限する操作を行います。すべての操作はubuntu18.04で行います。

  1. まず、簡単な無限ループのcプログラムを作成します。
loop_sample_cpu.c
#include <stdio.h>

int main(){
        while(1){
        }
}

プログラムをコンパイルします。

$ gcc -o loop_sample_cpu loop_sample_cpu.c

実行します。

$./loop_sample_cpu

CPU利用率を確認する。loop_sample_cpuの利用率はほぼ100%に近いです。

zhenbin@zhenbin-VirtualBox:~$ top

top - 14:51:45 up 28 min,  1 user,  load average: 0.29, 0.08, 0.02
Tasks: 175 total,   2 running, 140 sleeping,   0 stopped,   0 zombie
%Cpu(s): 98.6 us,  1.4 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  8345424 total,  6421164 free,   875200 used,  1049060 buff/cache
KiB Swap:  2097148 total,  2097148 free,        0 used.  7187568 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND      
10403 zhenbin   20   0    4372    764    700 R 95.0  0.0   0:19.75 loop_sample_cpu  
 9547 zhenbin   20   0 3020252 278368 108992 S  2.3  3.3   0:09.34 gnome-shell  
10342 zhenbin   20   0  870964  38352  28464 S  1.0  0.5   0:00.88 gnome-termi+ 
 9354 zhenbin   20   0  428804  95048  61820 S  0.7  1.1   0:02.25 Xorg         
  922 root      20   0  757084  82776  45764 S  0.3  1.0   0:00.50 dockerd      
    1 root      20   0  159764   8972   6692 S  0.0  0.1   0:01.06 systemd      
    2 root      20   0       0      0      0 S  0.0  0.0   0:00.00 kthreadd     
    3 root       0 -20       0      0      0 I  0.0  0.0   0:00.00 rcu_gp       
    4 root       0 -20       0      0      0 I  0.0  0.0   0:00.00 rcu_par_gp   
    6 root       0 -20       0      0      0 I  0.0  0.0   0:00.00 kworker/0:0+ 
    7 root      20   0       0      0      0 I  0.0  0.0   0:00.15 kworker/u2:+ 
    8 root       0 -20       0      0      0 I  0.0  0.0   0:00.00 mm_percpu_wq 
    9 root      20   0       0      0      0 S  0.0  0.0   0:00.13 ksoftirqd/0  
   10 root      20   0       0      0      0 I  0.0  0.0   0:00.16 rcu_sched    
   11 root      rt   0       0      0      0 S  0.0  0.0   0:00.00 migration/0  
   12 root     -51   0       0      0      0 S  0.0  0.0   0:00.00 idle_inject+ 
   13 root      20   0       0      0      0 I  0.0  0.0   0:00.11 kworker/0:1+ 

  1. cgroupにCPU制限を追加する /sys/fs/cgroup/cpu,cpuacctの下に、フォルダを作成する。
$ cd /sys/fs/cgroup/cpu,cpuacct
$ mkdir loop_sample_cpu
$ cd loop_sample_cpu

loop_sample_cpuのPIDをcgroupに追加する。ここで、rootユーザしか行われない。

$ sudo su
$ echo 10403 > cgroup.procs

CPUの制限を追加する。loop_sample_cpuのフォルダにいくつかリソースの制限タイプがありますが、今回には操作対象はこの二つです。ほかの項目の意味は[7]をご参考となります。

  • cpu.cfs_period_us
       cgroup による CPU リソースへのアクセスを再割り当てする一定間隔をマイクロ秒単位 (µs、ただしここでは "us" と表示) で指定します。cgroup 内のタスクが 1 秒あたり 0.2 秒間、単一の CPU にアクセスできる必要がある場合には、cpu.cfs_quota_us を 200000に、cpu.cfs_period_us を 1000000 に設定してください。cpu.cfs_quota_us パラメーターの上限は 1 秒、下限は 1000 マイクロ秒です。

  • cpu.cfs_quota_us
       cgroup 内の全タスクが (cpu.cfs_period_us で定義された) 一定の期間に実行される合計時間をマイクロ秒単位 (µs、ただしここでは "us" と表示) で指定します。クォータによって指定された時間を cgroup 内のタスクがすべて使い切ってしまうと、その期間により指定されている残りの時間はタスクがスロットリングされ、次の期間まで実行を許可されなくなります。cgroup 内のタスクが 1 秒あたり 0.2 秒間、単一の CPU にアクセスできる必要がある場合には cpu.cfs_quota_us を 200000 に、cpu.cfs_period_us を 1000000 に設定します。クォータおよび期間のパラメーターは CPU ベースで動作する点に注意してください。プロセスが 2 つの CPU を完全に使用できるようにするには、たとえば、cpu.cfs_quota_us を 200000 に、 cpu.cfs_period_us を 100000 に設定します。
    cpu.cfs_quota_us の値を -1 に設定すると、cgroup が CPU 時間制限を順守しないことを示します。これは、全 cgroup のデフォルト値でもあります (root cgroup は除く)。

CPUを1コアに20%に制限します。(50msごとに10msのCPU時間をしか利用できない)

$ echo 10000 > cpu.cfs_quota_us
$ echo 50000 > cpu.cfs_period_us

loop_sample_cpuのCPU利用率が20%に制限されています。

zhenbin@zhenbin-VirtualBox:~$ top

top - 15:06:05 up 42 min,  1 user,  load average: 0.40, 0.72, 0.57
Tasks: 181 total,   2 running, 146 sleeping,   0 stopped,   0 zombie
%Cpu(s): 23.8 us,  1.0 sy,  0.0 ni, 75.2 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  8345424 total,  6366748 free,   912068 used,  1066608 buff/cache
KiB Swap:  2097148 total,  2097148 free,        0 used.  7134248 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND      
10403 zhenbin   20   0    4372    764    700 R 19.9  0.0  12:16.90 loop_sample_cpu  
 9547 zhenbin   20   0 3032212 287524 111556 S  1.7  3.4   0:18.14 gnome-shell  
 9354 zhenbin   20   0  458868 125556  77832 S  1.3  1.5   0:06.06 Xorg         
10342 zhenbin   20   0  873156  40500  28464 S  1.0  0.5   0:03.34 gnome-termi+ 
 9998 zhenbin   20   0 1082256 120516  36164 S  0.3  1.4   0:01.92 gnome-softw+ 
    1 root      20   0  159764   8972   6692 S  0.0  0.1   0:01.12 systemd      
    2 root      20   0       0      0      0 S  0.0  0.0   0:00.00 kthreadd     
    3 root       0 -20       0      0      0 I  0.0  0.0   0:00.00 rcu_gp       
    4 root       0 -20       0      0      0 I  0.0  0.0   0:00.00 rcu_par_gp   
    6 root       0 -20       0      0      0 I  0.0  0.0   0:00.00 kworker/0:0+ 
    7 root      20   0       0      0      0 I  0.0  0.0   0:00.24 kworker/u2:+ 
    8 root       0 -20       0      0      0 I  0.0  0.0   0:00.00 mm_percpu_wq 
    9 root      20   0       0      0      0 S  0.0  0.0   0:00.16 ksoftirqd/0  
   10 root      20   0       0      0      0 I  0.0  0.0   0:00.22 rcu_sched    
   11 root      rt   0       0      0      0 S  0.0  0.0   0:00.00 migration/0  
   12 root     -51   0       0      0      0 S  0.0  0.0   0:00.00 idle_inject+ 
   14 root      20   0       0      0      0 S  0.0  0.0   0:00.00 cpuhp/0      

Namespace

名前空間[8]は、 グローバルシステムリソースを抽象化層で覆うことで、 名前空間内のプロセスに対して、 自分たちが専用の分離されたグローバルリソースを持っているかのように見せる仕組みである。 グローバルリソースへの変更は、 名前空間のメンバーである他のプロセスには見えるが、 それ以外のプロセスには見えない。 名前空間の一つの利用方法はコンテナーの実装である。

例:Network Namespace

Network Namespaceを利用して一個のNICに二つ仮想のネットワークを作り出すことが可能です。

  1. Network Namespaceを作成する
zhenbin@zhenbin-VirtualBox:~$ sudo unshare --uts --net /bin/bash
root@zhenbin-VirtualBox:~# hostname container001
root@zhenbin-VirtualBox:~# exec bash
root@container001:~# ip link set lo up
root@container001:~# ifconfig
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
root@container001:~# echo $$ # $$はコマンド自身の PID (プロセスID)が設定される変数
1909
  1. 仮想ネットワークインターフェースリンクを作成します。仮想ネットワークインターフェスの説明は[9]をご参考。 新しいshellを立ち上げる。リンクペーアを作成する。
$ sudo ip link add veth0 type veth peer name veth1

veth1を先ほど作成したnetwork namespaceに割り当て。

$ sudo ip link set veth1 netns 1909

veth0のセットアップする

$ sudo ip address add dev veth0 192.168.100.1/24
$ sudo ip link set veth0 up

container001のshellでveth1をセットアップする。

$ sudo ip address add dev veth1 192.168.100.2/24
$ sudo ip link set veth1 up

ホストとcontainer001の間に通信できるようになりました。

zhenbin@zhenbin-VirtualBox:~$ ping 192.168.100.2
PING 192.168.100.2 (192.168.100.2) 56(84) bytes of data.
64 bytes from 192.168.100.2: icmp_seq=1 ttl=64 time=0.019 ms
64 bytes from 192.168.100.2: icmp_seq=2 ttl=64 time=0.037 ms
^C
--- 192.168.100.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.019/0.028/0.037/0.009 ms

LXCを本格に活用するDockerの登場

初期のバージョンのDockerはLXCをコンテナ実行ドライバとして利用していたが、Docker v0.9ではオプションとなり、Docker v1.10でサポートが終了した。それ以降のDockerはDocker社が開発したlibcontainerというライブラリを利用してcgroupとnamespaceをコントロールします。

ここで、一つ重要なポイントがあります。Dockerというものが仮想化の技術ではないこと!どちらというと、cgroupとnamespaceの管理ツールとしての存在です。開発者やサーバ運用の人がもっと簡単にlinuxカーネルが提供している仮想化機能を利用できるようなツールです。
さらに、DockerfileとDocker Hubの存在による、アプリケーションのカプセル化と移植性にも向上させました!

ここで、dockerの一般的なコマンドよりdockerのリソースの隔離とコントロールの特性を強調したいと思います。

例:dockerでcontainerのCPU使用率を制限する。

  1. アプリケーションを含むdocker containerを作成する。

先ほどで作成したloop_sample_cpu.cというプログラムを含むubuntuベースのdocker imageを作成する。

FROM ubuntu

RUN apt update && apt install -y gcc

WORKDIR /src

COPY loop_sample_cpu.c .

RUN gcc -o loop_sample_cpu loop_sample_cpu.c

CMD ./loop_sample_cpu

docker imageをビルドする。

docker build -t ubuntu_cpu .
  1. CPU制限しないコンテナを起動する。
docker run -d ubuntu_cpu 

CPU利用率をみてみましょう。

zhenbin@zhenbin-VirtualBox:~/workspace/presentation$ top

top - 17:06:45 up 43 min,  1 user,  load average: 0.89, 0.56, 0.37
Tasks: 178 total,   2 running, 142 sleeping,   0 stopped,   0 zombie
%Cpu(s): 99.0 us,  1.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  8345424 total,  6156972 free,   894060 used,  1294392 buff/cache
KiB Swap:  2097148 total,  2097148 free,        0 used.  7184360 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                                              
 8853 root      20   0    4372    804    740 R 94.0  0.0   0:15.97 loop_sample_cpu                                                      
 1253 zhenbin   20   0 3020528 278012 108704 S  2.0  3.3   0:31.41 gnome-shell                                                          
 1056 zhenbin   20   0  424560  90824  55364 S  1.3  1.1   0:09.92 Xorg                                                                 
 1927 zhenbin   20   0  877384  44356  28584 S  1.3  0.5   0:08.01 gnome-terminal-                                                      
    1 root      20   0  225292   9040   6724 S  0.0  0.1   0:01.62 systemd                                                              
    2 root      20   0       0      0      0 S  0.0  0.0   0:00.00 kthreadd                                                             
    3 root       0 -20       0      0      0 I  0.0  0.0   0:00.00 rcu_gp                                                               
    4 root       0 -20       0      0      0 I  0.0  0.0   0:00.00 rcu_par_gp                                                           
    6 root       0 -20       0      0      0 I  0.0  0.0   0:00.00 kworker/0:0H-kb                                                      
    8 root       0 -20       0      0      0 I  0.0  0.0   0:00.00 mm_percpu_wq                                                         
    9 root      20   0       0      0      0 S  0.0  0.0   0:00.29 ksoftirqd/0                                                          
   10 root      20   0       0      0      0 I  0.0  0.0   0:00.31 rcu_sched                                                            
   11 root      rt   0       0      0      0 S  0.0  0.0   0:00.00 migration/0                                                          
   12 root     -51   0       0      0      0 S  0.0  0.0   0:00.00 idle_inject/0                                                        
   14 root      20   0       0      0      0 S  0.0  0.0   0:00.00 cpuhp/0                                                              
   15 root      20   0       0      0      0 S  0.0  0.0   0:00.00 kdevtmpfs                                                            
   16 root       0 -20       0      0      0 I  0.0  0.0   0:00.00 netns                                                                

  1. CPUを制限するコンテナを起動する。
docker run -d --cpu-period=50000 --cpu-quota=10000 ubuntu_cpu 

CPUの利用率をチェックしてみましょう。

zhenbin@zhenbin-VirtualBox:~$ top

top - 17:08:50 up 45 min,  1 user,  load average: 0.77, 0.68, 0.45
Tasks: 178 total,   2 running, 141 sleeping,   0 stopped,   0 zombie
%Cpu(s): 25.8 us,  2.3 sy,  0.0 ni, 71.9 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  8345424 total,  6160808 free,   892384 used,  1292232 buff/cache
KiB Swap:  2097148 total,  2097148 free,        0 used.  7188556 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND      
 9066 root      20   0    4372    800    740 R 19.9  0.0   0:04.36 loop_sample+ 
 1253 zhenbin   20   0 3017968 275536 106144 S  3.0  3.3   0:32.83 gnome-shell  
 1056 zhenbin   20   0  422000  88336  52876 S  2.7  1.1   0:10.59 Xorg         
 1927 zhenbin   20   0  877380  44468  28584 S  2.0  0.5   0:08.54 gnome-termi+ 
  580 root      20   0  776548  46696  24888 S  0.3  0.6   0:02.71 containerd   
 1202 zhenbin   20   0  193504   2912   2536 S  0.3  0.0   0:03.92 VBoxClient   
 1461 zhenbin   20   0  441756  22836  17820 S  0.3  0.3   0:00.09 gsd-wacom    
 1475 zhenbin   20   0  670048  23676  18316 S  0.3  0.3   0:00.29 gsd-color    
    1 root      20   0  225292   9040   6724 S  0.0  0.1   0:01.65 systemd      
    2 root      20   0       0      0      0 S  0.0  0.0   0:00.00 kthreadd     
    3 root       0 -20       0      0      0 I  0.0  0.0   0:00.00 rcu_gp       
    4 root       0 -20       0      0      0 I  0.0  0.0   0:00.00 rcu_par_gp   
    6 root       0 -20       0      0      0 I  0.0  0.0   0:00.00 kworker/0:0+ 
    8 root       0 -20       0      0      0 I  0.0  0.0   0:00.00 mm_percpu_wq 
    9 root      20   0       0      0      0 S  0.0  0.0   0:00.30 ksoftirqd/0  
   10 root      20   0       0      0      0 I  0.0  0.0   0:00.32 rcu_sched    
   11 root      rt   0       0      0      0 S  0.0  0.0   0:00.00 migration/0  

/sys/fs/cgroup/cpu,cpuacctをチェックすると、dockerというフォルダが作られることがわかりました。

zhenbin@zhenbin-VirtualBox:/sys/fs/cgroup/cpu,cpuacct$ ls
cgroup.clone_children  cpuacct.usage             cpuacct.usage_percpu_user  cpu.cfs_quota_us  notify_on_release  user.slice
cgroup.procs           cpuacct.usage_all         cpuacct.usage_sys          cpu.shares        release_agent
cgroup.sane_behavior   cpuacct.usage_percpu      cpuacct.usage_user         cpu.stat          system.slice
cpuacct.stat           cpuacct.usage_percpu_sys  cpu.cfs_period_us          docker            tasks

ここで、dockerでcgroupとnamespaceを利用することでアプリケーションがランタイムのリソースを制限することがわかりました。

Dockerの特徴

  • 上記の説明のようにdockerはあくまで管理ツールで、つまり、OSの一つのプロセスということです。そのため、バーチャルマシーンより起動が早い。
  • 移植性がいい。Dockerfileがアプリケーションが実行するような環境(ライブラリ、パラメータ)を記載するので、どこでも同じアプリケーションを再現できること
  • 一個のコンテナに一個のプロセスを実行すること。基本的にはdocker containerには複数のプロセスを実行させるのがおすすめしません。複数プロセスを実行させると、結局、アプリケーションをホストに同じ環境に実行することと変わらない、リソースの分離ができなくなる。
  • kernelやハードウェアの変更ができない。ホスト上に実行するcontainerはホストのカーネルを共有するので、カーネルモジュールの変更を行うと、すべてのcontainerに影響があります。あと、ハードウェアに対しても制限が多い。例えば、usbなどの操作にはかなり問題があります。
  • docker container内部のファイルシステムはメモリ上に保存するので、containerが削除されると、データも削除されますので、データ永続化をしたい場合にはホストのファイルシステムをcontainerにマウントしないといけない。でも、一般的にdockerに実行するアプリケーションがstatelessにするのがおすすめです。

参考URL

[1] https://blogs.itmedia.co.jp/itsolutionjuku/2017/10/1it_1.html
[2] https://ja.wikipedia.org/wiki/%E3%83%8F%E3%82%A4%E3%83%91%E3%83%BC%E3%83%90%E3%82%A4%E3%82%B6
[3] https://codezine.jp/article/detail/11336
[4] https://ja.wikipedia.org/wiki/LXC
[5] https://ja.wikipedia.org/wiki/Cgroups
[6] http://man7.org/linux/man-pages/man7/cgroups.7.html
[7] https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/6/html/resource_management_guide/sec-cpu
[8] https://linuxjm.osdn.jp/html/LDP_man-pages/man7/namespaces.7.html
[9] https://gihyo.jp/admin/serial/01/linux_containers/0006

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Chrome OSで開発環境を構築

はじめに

今年のブラックフライデーでGoogle Pixel Slateが$350割引に純正キーボード + Pixelbook Penが無料でついてくるということで、Google信者の自分としてはこの機会を逃すわけにはいかないと思い購入することに決めた。
Pixel SlateはGoogle製のChrome OSのタブレットで12.3インチとタブレットとしては少し大きめだが、2 in 1のタブレットとしてはちょうどいい大きさだろう。重量は700グラムほどで、iPad Proと比べると重たいが持ち運ぶのに支障はないと言える。
このChrome OSはその名前からわかるように、メインはChromeブラウザ上で作業することが想定されていてとても軽量なOSなのだが、AndroidやLinuxのアプリも使うことができる。そこでChrome OSで軽く開発してみたくなったので、そのときの作業内容をまとめる。

スペック

Pixel Slate

  • プロセッサ: 第8世代Core i5
  • RAM: 8GB
  • 内部ストレージ: 128GB

OSのバージョン

  • Chrome OS: 79.0.3945.86
  • Android: 9.0
  • Linux(Debian): 9.9

Linuxのセットアップ

Chrome OSでLinuxのコマンドラインツールやコードエディタ、IDEをインストールすることができる。ただし、デフォルトではオフになっているため、設定で有効にする必要がある。

設定から[Linux(ベータ版)] > [オンにする]

Screenshot 2019-12-23 at 15.24.43.png

しばらくセットアップに時間を取られた後にターミナルウィンドウが立ち上がるので、これでLinuxを利用することができる。
現時点ではこの機能はベータ版で、問題が発生する可能性があるが、自分で解決できる範疇ではあると思う。

ターミナルでのセットアップ

ターミナル自体の設定

ターミナルが立ち上がっている状態でCtrl + Shift + pで設定画面が表示される。
Screenshot 2019-12-23 at 12.25.37.png

パッケージの更新

パッケージを最新のバージョンに保つために以下のコマンドを実行する。

$ sudo apt update -y
$ sudo apt upgrade -y
$ sudo apt full-upgrade -y

Gitを最新版に更新

デフォルトでインストールされているgitのバージョンは2.11.0なので、最新のバージョンに更新する。

ソースをダウンロードしてインストールする方法とリポジトリをクローンしてインストールする方法があるので、どちらも紹介しておく。

【共通】依存パッケージをインストール

$ sudo apt install -y autoconf gettext libcurl4-gnutls-dev libexpat1-dev libghc-zlib-dev libssl-dev make

リポジトリから最新版に更新

常に最新版に更新したい場合は、リポジトリをクローンすることで簡単にインストール、更新することができる。

gitのインストール

$ git clone https://github.com/git/git.git ~/git
$ cd ~/git
$ make prefix=/usr/local all
$ sudo make prefix=/usr/local install

gitの更新

$ cd ~/git
$ git pull origin master
$ make prefix=/usr/local all
$ sudo make prefix=/usr/local install

ソースをダウンロードして更新

最新版のgitを利用したくない場合は、バージョンを指定してソースをダウンロードするこちらの方法を利用するとよい。
gitのリリースページから最新のバージョンを確認する。ここでは最新版のv2.24.1を使用するが、それ以外のバージョンでも問題ない。

FireShot Capture 002 - Releases · git_git - github.com.png

gitのソースをダウンロードするために以下のコマンドを実行する。

# v2.24.1の部分はダウンロードしたバージョンに置き換える
$ wget https://github.com/git/git/archive/v2.24.1.tar.gz
$ tar -zxf v2.24.1.tar.gz
$ cd git-2.24.1

あとはmakeコマンドを使ってインストールするだけである。インストール場所をprefix=/usr/localで指定しているが、これも各自好きな場所にインストールしても問題ない。

$ make prefix=/usr/local all
$ sudo make prefix=/usr/local install

Visual Studio Codeをインストール

普段からNeovimやVisual Studio Code(VSCode)で開発を行っているため、Chrome OSでも利用できるようにする。
公式サイトからダウンロードしたDebian用のインストーラ(.deb)を実行することでVSCodeを起動することができる。

Screenshot 2019-12-23 at 14.16.35.png

Docker関連ツールをインストール

Chrome OS上のLinuxがVM上で動いているとはいえ、最小限のアプリケーションのみで動かしたいという考えと、Dockerは開発を行う上で必要不可欠なものなのでDockerとDocker Composeをインストールする。

Dockerをインストール

公式ページ通りにインストールすると失敗しないだろう。

# Dockerを以前にインストールしている場合はアンインストール
$ sudo apt remove --purge docker docker-engine docker.io containerd runc

$ sudo apt update -y
# 依存パッケージをインストール
$ sudo apt install -y \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg2 \
    software-properties-common

# DockerのGPGキーを追加
$ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
$ sudo apt-key fingerprint 0EBFCD88

# Dockerの安定版(stable)のリポジトリを追加
$ sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/debian \
   $(lsb_release -cs) \
   stable"

# Dockerをインストール
$ sudo apt update -y
$ sudo apt install -y docker-ce docker-ce-cli containerd.io

# インストールできたことを確認
$ sudo docker run --rm hello-world

sudoせずにDockerを実行

このままだとDockerを実行するたびにsudoする必要があるため、現在のユーザにdockerグループを追加し一般ユーザの権限でも実行できるようにする。

# 現在のユーザのグループに`docker`を追加
$ sudo usermod -aG docker `whoami`
# Chrome OSを再起動
$ docker run --rm hello-world

Docker Composeをインストール

こちらも公式サイトの手順にそってインストールする。

# 最新版のDocker Composeをダウンロード
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 実行できるように権限を変更
$ sudo chmod +x /usr/local/bin/docker-compose
# Docker Composeがインストールできたことを確認
$ docker-compose --version

おわりに

初めてChrome OSを触ったがAndroidアプリが使えてPixelbook Penで直感的な操作が可能なのがすごく面白い。Linuxもベータ版ではあるが使い勝手も悪くなく、開発環境としては問題なく使用できるレベルだと感じた。
ただ、ストレージが128GBしかないため、外部ストレージやクラウドサービスなどを利用する必要があるだろう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

テキストファイルをgrepしたらBinary file (standard input) matchesとなった時の対応方法

  • 環境
    • Windows10 Pro 64bit
    • grep (GNU grep) 3.1

事象 : テキストファイルをgrepしたらBinary file (standard input) matchesと言われた

$ grep hoge text_file.txt
Binary file (standard input) matches

原因 : grepが最初の数バイトとを見てバイナリファイルだと思ったから

Linuxのgrep検索で「バイナリー・ファイル(標準入力)は一致しました」と表示される原因と解決方法 - r_nobuホームページ

対応方法 : -aオプションをつけてテキストファイルであることを明示する

$ grep -a hoge text_file.txt
hoge
fugahoge
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

インストールMemo

[ステップ0]
sudo apt install nodejs npm
sudo npm instal -g n
n --stable
sudo npm install yarn

[lintとformat]
// eslint
・eslint
・eslint-plugin-import
・eslint-config-prettier
// prettier
・prettier
・prettier-eslint

[インストール]
yarn add eslint eslint-config-prettier eslint-plugin-import eslint-plugin-prettier prettier prettier-eslint
.eslintrc
{
  "parserOptions": {
    "ecmaVersion": 2017,
    "sourceType": "module"
  },
  "env": {
    "es6": true,
    "browser": true,
    "node": true
  },
  "extends": ["plugin:prettier/recommended"],
  "plugins": ["prettier"],
  "rules": {
    "prettier/prettier": ["error"],
    "no-unused-vars": "warn"
  }
}
.pretteirrc
{
  "printWidth": 120,
  "tabWidth": 2,
  "singleQuote": true,
  "trailingComma": "none",
  "semi": false
}
[vscode]settings.json
// ==== html ===========================================================
    "html.format.contentUnformatted": "pre, code, textarea, title, h1, h2, h3, h4, h5, h6, p", // フォーマットしないタグ
    "html.format.extraLiner": "", // headとbody要素の調節
    "html.format.preserveNewLines": false, // 指定タグ間にスペースを入れない
    "html.format.indentInnerHtml": true, // headとbodyをインデントする 
    "html.format.unformatted": null, // 再フォーマットしてはならないタグ 
    // === json
    "json.maxItemsComputed": 10000,
    // ==== javascript =====================================================
    "[javascript]": {
        "editor.tabSize": 2,
        "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    // === pretteir ========================================================
    "prettier.singleQuote": true,
    "prettier.tabWidth": 2,
    // ==== ESLint =========================================================
    "eslint.enable": true,
    "eslint.packageManager": "npm",
    "eslint.nodePath": "./node_modules",
    "editor.codeActionsOnSave": {
        "source.fixAll": true,
    },
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

topコマンドの見方を間違えてた話

背景

仕事柄、たまにVPSのメモリ使用量をtopコマンドなどで確認することがあります。
(下はUbuntu 18.04 LTSのもの)

top - 13:40:39 up  1:44,  0 users,  load average: 0.52, 0.58, 0.59
Tasks:   5 total,   1 running,   3 sleeping,   1 stopped,   0 zombie
%Cpu(s):  3.6 us,  5.6 sy,  0.0 ni, 88.6 id,  0.0 wa,  2.2 hi,  0.0 si,  0.0 st
KiB Mem :  8290600 total,  2456796 free,  5604452 used,   229352 buff/cache
KiB Swap: 25165824 total, 25094400 free,    71424 used.  2552416 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    1 root      20   0    8304    136    108 S   0.0  0.0   0:00.10 init
    4 kitakou   20   0   17620   2020   1492 T   0.0  0.0   0:04.10 top
    5 root      20   0    8308    100     60 S   0.0  0.0   0:00.00 init
    6 kitakou   20   0   16788   3396   3312 S   0.0  0.0   0:00.09 bash
   10 kitakou   20   0   17620   2032   1500 R   0.0  0.0   0:00.03 top

主に4,5行目の実メモリとswao領域について確認するのですが、swapに関する行の最右の値、これは環境によってcachedやavail Memと表示されています。
ここで
「swap領域のcacheって何…? なんでavail Memと指し変わったりするの…?」
という疑問が湧いてきました。
cache領域は他のアプリケーションの要求に応じて開放されるため、swap領域にもある程度のcache領域があるならば主記憶の不足を補えるので好ましい状態ではありませんが一応動作はします。(そもそもswap領域に移ってる時点で処理速度が落ちているので)

ですが今度は「なぜ高速化のためのcache領域がわざわざ遅いswap領域に…?」という疑問が現れます、
複数の記事を見てみても「cacheされたswap領域」などと記載されておりんにゃぴ…となってしまったのですが、ようやく解消したのでいろいろ調べてみた結果をまとめたいと思います。

結果

そもそもswap領域上の値じゃありませんでした
topコマンドのメモリ上の値は下図のように分かれており、
image.png
青の部分が物理メモリ上の数値、黄色が仮想メモリ(つまりswap領域の話)に関わる値になるそうです。
man topコマンドで確認してみると、

 2c. MEMORY Usage
       This portion consists of two lines which may express values in kibibytes (KiB) through exbibytes (EiB) depend‐
       ing on the scaling factor enforced with the 'E' interactive command.

       As a default, Line 1 reflects physical memory, classified as:
           total, free, used and buff/cache

       Line 2 reflects mostly virtual memory, classified as:
           total, free, used and avail (which is physical memory)

       The avail number on line 2 is an estimation of physical memory available for starting new applications,  with‐
       out  swapping.   Unlike  the  free field, it attempts to account for readily reclaimable page cache and memory
       slabs.  It is available on kernels 3.14, emulated on kernels 2.6.27+, otherwise the same as free.

となっており、確かに(which is physical memory)と補足されています。
でもそれはそれとしてわかりにくいよ!!!!!!!!!!swap行に書いてあったらswao領域の話だと思うでしょ!!!!!

お世話になったサイト

https://piro.sakura.ne.jp/latest/blosxom/topics/2018-11-13_top-cached.htm
上記サイト末尾のドはまりケースにめちゃくちゃ合致してました…複数の記事を確認することと英語にビビらないこと、肝に銘じていきたいです…

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

topコマンドのswap行の見方を間違えてた話

背景

仕事柄、たまにVPSのメモリ使用量をtopコマンドなどで確認することがあります。
(下はUbuntu 18.04 LTSのもの)

top - 13:40:39 up  1:44,  0 users,  load average: 0.52, 0.58, 0.59
Tasks:   5 total,   1 running,   3 sleeping,   1 stopped,   0 zombie
%Cpu(s):  3.6 us,  5.6 sy,  0.0 ni, 88.6 id,  0.0 wa,  2.2 hi,  0.0 si,  0.0 st
KiB Mem :  8290600 total,  2456796 free,  5604452 used,   229352 buff/cache
KiB Swap: 25165824 total, 25094400 free,    71424 used.  2552416 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    1 root      20   0    8304    136    108 S   0.0  0.0   0:00.10 init
    4 kitakou   20   0   17620   2020   1492 T   0.0  0.0   0:04.10 top
    5 root      20   0    8308    100     60 S   0.0  0.0   0:00.00 init
    6 kitakou   20   0   16788   3396   3312 S   0.0  0.0   0:00.09 bash
   10 kitakou   20   0   17620   2032   1500 R   0.0  0.0   0:00.03 top

主に4,5行目の実メモリとswao領域について確認するのですが、swapに関する行の最右の値、これは環境によってcachedやavail Memと表示されています。
ここで
「swap領域のcacheって何…? なんでavail Memと指し変わったりするの…?」
という疑問が湧いてきました。
cache領域は他のアプリケーションの要求に応じて開放されるため、swap領域にもある程度のcache領域があるならば主記憶の不足を補えるので好ましい状態ではありませんが一応動作はします。(そもそもswap領域に移ってる時点で処理速度が落ちているので)

ですが今度は「なぜ高速化のためのcache領域がわざわざ遅いswap領域に…?」という疑問が現れます、
複数の記事を見てみても「cacheされたswap領域」などと記載されておりんにゃぴ…となってしまったのですが、ようやく解消したのでいろいろ調べてみた結果をまとめたいと思います。

結果

そもそもswap領域上の値じゃありませんでした
topコマンドのメモリ上の値は下図のように分かれており、
image.png
青の部分が物理メモリ上の数値、黄色が仮想メモリ(つまりswap領域の話)に関わる値になるそうです。
man topコマンドで確認してみると、

 2c. MEMORY Usage
       This portion consists of two lines which may express values in kibibytes (KiB) through exbibytes (EiB) depend‐
       ing on the scaling factor enforced with the 'E' interactive command.

       As a default, Line 1 reflects physical memory, classified as:
           total, free, used and buff/cache

       Line 2 reflects mostly virtual memory, classified as:
           total, free, used and avail (which is physical memory)

       The avail number on line 2 is an estimation of physical memory available for starting new applications,  with‐
       out  swapping.   Unlike  the  free field, it attempts to account for readily reclaimable page cache and memory
       slabs.  It is available on kernels 3.14, emulated on kernels 2.6.27+, otherwise the same as free.

となっており、確かに(which is physical memory)と補足されています。
でもそれはそれとしてわかりにくいよ!!!!!!!!!!swap行に書いてあったらswao領域の話だと思うでしょ!!!!!

お世話になったサイト

https://piro.sakura.ne.jp/latest/blosxom/topics/2018-11-13_top-cached.htm
上記サイト末尾のドはまりケースにめちゃくちゃ合致してました…複数の記事を確認することと英語にビビらないこと、肝に銘じていきたいです…

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

一瞬で忘れそうなコマンド備忘録

フィルタ系のコマンドは全然使わないからせめてまとめといて思い出しやすくしておこうと思ったので書き記す。。

フィルタ

標準入力を受け取って、適当な処理をして標準出力に出力するコマンドのこと

wc

オプション無しで引数にファイルを指定すると、行数 単語数 バイト数 を表示してくれる

(オプション)
-c バイト数を数えてくれる
-m 文字数を数えてくれる
-l 行数を数えてくれる
-w 文字数を数えてくれる

sort

sortしてくれる。オプション無しだとASCIIコードに則ってアルファベット順でsortしてくれる。正確には文字コード順に並び替えるだけなので、下の例みたいな順番になる。

(例)
A
Z
a
b
(オプション)
-n 数値順にソート
-r 逆順にソート

uniq

重複した行を除いて表示してくれるのが基本動作。

(オプション)
-c ある行が出現する回数をカウントする

cut

入力の一部を切り出せる

(書式)
cut -d 区切り文字 -f フィールド番号 ファイル名
(オプション)
-d 区切り文字の指定(ない場合はタブで区切られる)
-b 指定したバイト目だけを出力する
-c 指定した文字番目だけ表示する
-f 表示するフィールド番号を指定する
-s 区切り文字を含まない行を出力しない

cutコマンドでは-b -c -fのどれかひとつだけを選んで必ず使わなければならない。

tr

文字を置換してくれる。ファイルを引数に指定できないので入力リダイレクトで扱うか、適当なコマンドから出力をパイプしてくることで使える。

(使い方)
tr オプション SET1 SET2

SET1が置換される文字列でSET2が置換後の文字列。

(オプション)
-d 置換しないで置換対象をdeleteする
-s SET1 と SET2 の対応するn番目の文字を置換する
(SETで使える正規表現)
\b バックスペース
\n 改行
\t 水平タブ
a-d アルファベット順でaからdまでの文字
:cntrl: すべての制御文字
詳しくはhelpを読もう、日本語だったよ

tail

標準入力から末尾n行を出力する。オプションを指定しなければ10行出力される。

(オプション)
-n 引数で、表示する末尾から何行出力するかを指定
-f ファイルを監視し、内容が追記されたら表示する
-v ファイル名を一番上に表示してくれる

diff

2ファイルの差分を出力してくれる。出力形式にはデフォルトの形式の他にユニファイド形式というものがある。読み方に癖があるが、ここで解説はしない。gitで使われているのもユニファイド形式なので使うときはユニファイド形式で出力するのがいいだろう。ちなみにディレクトリも比較できる。

(オプション)
-q 2つのファイルの内容が異なるかどうかのみ出力する
-s 2つのファイルの内容が同じかどうかのみ出力する
-u ユニファイド形式で出力する
-a すべのファイルをテキストとして扱う
-w すべてのスペースを無視する
-b すべてのスペースによる違いを無視する
-Z 行末にあるスペースを無視する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

一瞬で忘れそうなフィルタコマンド備忘録

フィルタ系のコマンドは全然使わないからせめてまとめといて思い出しやすくしておこうと思ったので書き記す。。

フィルタ

標準入力を受け取って、適当な処理をして標準出力に出力するコマンドのこと

wc

オプション無しで引数にファイルを指定すると、行数 単語数 バイト数 を表示してくれる

(オプション)
-c バイト数を数えてくれる
-m 文字数を数えてくれる
-l 行数を数えてくれる
-w 文字数を数えてくれる

sort

sortしてくれる。オプション無しだとASCIIコードに則ってアルファベット順でsortしてくれる。正確には文字コード順に並び替えるだけなので、下の例みたいな順番になる。

(例)
A
Z
a
b
(オプション)
-n 数値順にソート
-r 逆順にソート

uniq

重複した行を除いて表示してくれるのが基本動作。

(オプション)
-c ある行が出現する回数をカウントする

cut

入力の一部を切り出せる

(書式)
cut -d 区切り文字 -f フィールド番号 ファイル名
(オプション)
-d 区切り文字の指定(ない場合はタブで区切られる)
-b 指定したバイト目だけを出力する
-c 指定した文字番目だけ表示する
-f 表示するフィールド番号を指定する
-s 区切り文字を含まない行を出力しない

cutコマンドでは-b -c -fのどれかひとつだけを選んで必ず使わなければならない。

tr

文字を置換してくれる。ファイルを引数に指定できないので入力リダイレクトで扱うか、適当なコマンドから出力をパイプしてくることで使える。

(使い方)
tr オプション SET1 SET2

SET1が置換される文字列でSET2が置換後の文字列。

(オプション)
-d 置換しないで置換対象をdeleteする
-s SET1 と SET2 の対応するn番目の文字を置換する
(SETで使える正規表現)
\b バックスペース
\n 改行
\t 水平タブ
a-d アルファベット順でaからdまでの文字
:cntrl: すべての制御文字
詳しくはhelpを読もう、日本語だったよ

tail

標準入力から末尾n行を出力する。オプションを指定しなければ10行出力される。

(オプション)
-n 引数で、表示する末尾から何行出力するかを指定
-f ファイルを監視し、内容が追記されたら表示する
-v ファイル名を一番上に表示してくれる

diff

2ファイルの差分を出力してくれる。出力形式にはデフォルトの形式の他にユニファイド形式というものがある。読み方に癖があるが、ここで解説はしない。gitで使われているのもユニファイド形式なので使うときはユニファイド形式で出力するのがいいだろう。ちなみにディレクトリも比較できる。

(オプション)
-q 2つのファイルの内容が異なるかどうかのみ出力する
-s 2つのファイルの内容が同じかどうかのみ出力する
-u ユニファイド形式で出力する
-a すべのファイルをテキストとして扱う
-w すべてのスペースを無視する
-b すべてのスペースによる違いを無視する
-Z 行末にあるスペースを無視する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

cron.logの容量が肥大化しないように、定期的にクリアさせる

はじめに

cronで実行したコマンド(つまり、crontab -eで設定したコマンド)を、rsyslogサービスを使って、/var/log/cron.logに定期的に書き込む設定をした後、このログファイルは永遠に書き込まれて行き、容量が肥大化しないだろうかと思い、定期的に、/var/log/cron.logのファイルをクリアする処理も、cronで設定する事にした。

環境

Ubuntu 16.04.5 LTS

試した事1

単純に、ログファイルを削除しようと思い、cronに下記のコマンドをスケジュールさせる。確かに、ログファイルは削除してくれたが、rsyslogサービスを再起動しないと、ログファイルは二度と作成されない事が判明する。しかも、root権限がないと削除できない。よって、この方法は没となる。

rm /var/log/cron.log

試した事2

/var/log/cron.logファイルを残したままで、中身をクリアして、0KBの空ファイルにするも、やはり、root権限がないと書込みができない事が判明。

cp /dev/null /var/log/cron.log

cronでsudoを指定したコマンドを実行するには(vimで躓く編)

visudoを編集する事で、cronでsudoを指定したコマンドが実行できるようになる事が判明したため、やってみる。

sudo visudo

Ubuntuでは、visudoを表示すると、デフォルトで、nanoが起動するようになっているため、vimに変更します。

sudo update-alternatives --config editor

参考記事
https://qiita.com/koara-local/items/35b999631b6ab41fdc9f

自分の環境では、vim.noxと、vim.tinyの2つのvimが入っているが、下記コマンドで、vim.noxが表示されたため、vim.noxの方を選ぶ事にする。(画面では3を選択)

ls -l /etc/alternatives/vi
/etc/alternatives/vi -> /usr/bin/vim.nox

vim.noxに変更した後、再度、確かに変更された事を確認する。

sudo update-alternatives --config editor

nanoではなく、vimで表示されるようになりました。

sudo visudo

cronでsudoを指定したコマンドを実行するには(やり方を考察編)

visudoを編集するには、visudoを直接編集する方法と、visudoは触らずに、ドロップインを作成する方法と2つの方法がある。下記のコマンドで、1つのファイルと、1つのディレクトリが検索されます。visudoを編集すると、/etc/sudoersファイルが編集されるが、/etc/sudoers.dというディレクトリの配下に、編集したい行だけ追加したファイルをセットすると、sudoersファイルを触る事なく、カスタマイズが行えるというのがドロップインの仕組みらしい。ドロップインを推奨する人もいるようだが、自分は、visudoを直接編集する事にした。

ls /etc | grep sudo

参考記事
https://www.teradas.net/archives/13222/

cronでsudoを指定したコマンドを実行するには(visudoを編集する編)

参考記事
https://www.bloguchi.info/1846
https://www.crossl.net/blog/crontab/

ググると、デフォルトで、Defaults:user requirettyが記載されているので、Defaults:user !requirettyを記述して、Defaults:user requirettyを無効にして下さいとあるが、RedHat系のディストリビューションでは、Defaults:user requirettyがデフォルトで記述されているのだが、Debian系のディストリビューションでは、デフォルトで、この記載はないとある。確かに、自分の環境にはなかった。

sudo visudo

なので、この1行のみ追加する。cpコマンドのパスは、which cpで探します。

user ALL=(root)   NOPASSWD: /bin/cp

参考記事
https://orebibou.com/2017/06/sudo%E3%81%A7%E8%A6%9A%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8F%E3%81%A8%E4%BE%BF%E5%88%A9%E3%81%AA%E8%A8%AD%E5%AE%9A%E3%83%BB%E4%BD%BF%E3%81%84%E6%96%B9/#Defaults

crontab -eで、テスト的に、sudo 付きのこの1行を追加する。

*/1 * * * * sudo cp /dev/null /var/log/cron.log

確かに、ファイル容量が小さくなっている事が確認できました。(sudo付のコマンドが実行された事が確認できた)

ls -l /var/log/cron.log

C'est fini :sweat_smile:

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

1870件以上のカーネルの不具合修正に貢献した再現用プログラムを自動生成する試験自動化技術

はじめに

この記事は Linux Advent Calendar 2019 の 23 日目の記事です。

自己紹介

こんにちは。OSSセキュリティ技術の会fujiihda です。これまで Linux カーネルを含む OSS に関連する技術調査、技術講演、開発、サポート等を経験してきました。最近では、技術コミュニティを設立する側や運営側に関わらせていただく機会も増えてきました。

本記事で扱うテーマ

カーネルの試験自動化技術として Google の Dmitry Vyukov さんが開発し OSS として公開した syzkaller (読み方:シスコーラー 1 ) について解説します。2019 年 12 月時点では、内部実装まで踏み込んで調査した日本語の記事は本記事が初となるはずです。なお、本記事の中身は OSSセキュリティ技術の会 第七回勉強会 の前半の内容 2 とほぼ同じです。厳密には、本記事ではソースコード調査の結果として得られたノウハウは載せていますが、ソースコード自体には言及せず、口頭補足していた説明等をマシマシにして、QA ほぼ全部載せにして記事にしました。

TL;DR

syzkaller では試験自動化にソースコードカバレッジを活用したハイブリッドアプローチを採用し、さらに従来であれば人が対応していた不具合修正に至るまでの一連の流れを自動化しました。その結果、リリースから 2 年間が経過してカバレッジを 7 %カバーした時点で、1500 件以上のカーネルの不具合修正に貢献した実績があります。

syzkaller では、自らが生成した複数の仮想マシンに対して問題の起きそうな入力を送り続けることで未発見の不具合を発見します。最小限の入力で不具合を再現させるための再試行を繰り返し、最終的には不具合を再現するための C 言語のプログラム生成を試みます。

syzkaller には、現在も機能が追加されており 3、いまこの瞬間にも不具合を発見し続けています。2019 年 12 月時点では 1870 件以上のカーネルの不具合修正に貢献しています。最新状況は https://syzkaller.appspot.com/upstream/fixed を参照してください。

本題

まずは動かしてみた

動かしてみた結果は次のとおりです。なお、動作確認には手元にあったモバイル向けノートパソコン上で動作する仮想マシン 4 を使用しました。

# ./bin/syz-manager -config=my.cfg
2019/06/05 03:53:20 loading corpus...
2019/06/05 03:53:20 serving http on http://127.0.0.1:56741
2019/06/05 03:53:20 serving rpc on tcp://[::]:37545
2019/06/05 03:53:20 booting test machines...
2019/06/05 03:53:20 wait for the connection from test machine...
2019/06/05 03:54:08 machine check:
2019/06/05 03:54:08 syscalls                : 1380/2699
2019/06/05 03:54:08 code coverage           : enabled
2019/06/05 03:54:08 comparison tracing      : CONFIG_KCOV_ENABLE_COMPARISONS is not enabled
2019/06/05 03:54:08 extra coverage          : extra coverage is not supported by the kernel
2019/06/05 03:54:08 setuid sandbox          : enabled
2019/06/05 03:54:08 namespace sandbox       : /proc/self/ns/user does not exist
2019/06/05 03:54:08 Android sandbox         : /sys/fs/selinux/policy does not exist
2019/06/05 03:54:08 fault injection         : CONFIG_FAULT_INJECTION is not enabled
2019/06/05 03:54:08 leak checking           : CONFIG_DEBUG_KMEMLEAK is not enabled
2019/06/05 03:54:08 net packet injection    : /dev/net/tun does not exist
2019/06/05 03:54:08 net device setup        : enabled
2019/06/05 03:54:08 corpus                  : 3844 (0 deleted)
2019/06/05 03:54:10 VMs 4, executed 0, cover 0, crashes 0, repro 0
2019/06/05 03:54:20 VMs 4, executed 36, cover 3836, crashes 0, repro 0
2019/06/05 03:54:30 VMs 4, executed 776, cover 20662, crashes 0, repro 0
(中略)
2019/06/05 04:10:00 VMs 4, executed 70734, cover 62967, crashes 0, repro 0
2019/06/05 04:10:05 vm-3: crash: no output from test machine
2019/06/05 04:10:10 VMs 3, executed 70918, cover 62967, crashes 1, repro 0
(中略)
2019/06/05 04:14:02 VMs 4, executed 87377, cover 63959, crashes 1, repro 0
2019/06/05 04:14:05 vm-2: crash: no output from test machine
2019/06/05 04:14:12 VMs 3, executed 87614, cover 63960, crashes 2, repro 0
(中略) 
2019/06/05 04:14:32 VMs 4, executed 87978, cover 63995, crashes 2, repro 0
2019/06/05 04:14:40 vm-3: crash: KASAN: use-after-free Read in blk_mq_free_rqs
2019/06/05 04:14:41 vm-1: running for 20m42.241115632s, restarting
2019/06/05 04:14:41 vm-0: running for 20m33.97704277s, restarting
2019/06/05 04:14:41 vm-2: running for 9.643775512s, restarting
2019/06/05 04:14:42 reproducing crash 'KASAN: use-after-free Read in blk_mq_free_rqs': 1158 programs, 4 VMs, timeouts [15s 1m0s 6m0s]
2019/06/05 04:14:42 VMs 0, executed 87978, cover 63995, crashes 3, repro 1
(以下略)
  • 2019/06/05 03:53:20 頃に syzkaller を起動しています。
  • 2019/06/05 04:10:05 および 2019/06/05 04:14:05 では、クラッシュ時に事象を取り逃しています。そういうことも多々あるようです。
  • 2019/06/05 04:14:40 に不具合らしいものを発見しています。ここまで、起動からわずか 20 分程です。
  • 2019/06/05 04:14:42 から事象の再現を試みています。

上記の結果、syzkaller によって自動生成された再現用のプログラムは次のとおりです。一応お伝えしておくと、この不具合は 既に修正されています

// autogenerated by syzkaller (https://github.com/google/syzkaller)

#define _GNU_SOURCE

#include <endian.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

uint64_t r[1] = {0xffffffffffffffff};

int main(void)
{
    syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
    intptr_t res = 0;
    memcpy((void *)0x20000040, "/dev/loop-control\000", 18);
    res = syscall(__NR_openat, 0xffffffffffffff9c, 0x20000040, 0x181000, 0);
    if (res != -1)
        r[0] = res;
    syscall(__NR_ioctl, r[0], 0x4c81, 0);
    return 0;
}

上記の実行時に使用したコンフィグファイルは次のとおりです。

{
    "target": "linux/amd64",
    "http": "127.0.0.1:56741",
    "workdir": "/root/gopath/src/github.com/google/syzkaller/workdir",
    "kernel_obj": "/root/kernel",
    "image": "/root/wheezy.img",
    "sshkey": "/root/wheezy.img.key",
    "syzkaller": "/root/gopath/src/github.com/google/syzkaller",
    "procs": 8,
    "type": "qemu",
    "vm": {
        "count": 4,
        "kernel": "/root/kernel/arch/x86/boot/bzImage",
        "cpu": 4,
        "mem": 4096
    }
}

なぜ syzkaller を調査してみたのか

なぜファジングを調べたのか、という質問に一言で回答するなら「面白そうだったから」です。細かく分けると、次のような理由になります。

  • 日本語の情報が存在しなかったために、逆に興味を持った
  • 最新技術が投入されているはずの仕組み、設計、実装に興味を持った
  • 考え方や技術が他分野に転用できるかもしれないと期待した
  • syzkaller を通じてカーネルのエンジニアとしてレベルアップしたかった
  • Go 言語の勉強 (それまでほぼ読んだことがなかったため)

ファジングと Linux のセキュリティ品質向上

ファジングは、未知の不具合や脆弱性の検出に適したテスト手法です。検査対象にランダムな入力データを送ることで意図的に例外を発生させます。ファジングがセキュリティ品質に与える影響は、世界で話題となっており、Open Source Summit Japan 2019 では、カーネルのリードメンテナの Greg Kroah-Hartman さんをはじめとする複数講演者がファジングの貢献に言及していました。

  • 2017 年前後を境としてファジングをはじめとする自動化された高度なテスト技術が普及
  • リリース前にセキュリティ脆弱性が修正されるようになり CVE の件数は減少傾向 5

ソフトウェア全体および Linux の CVE 件数の推移を図に示します。

ソフトウェア全体および Linux の CVE 件数の推移

ファジング技術の肝

高度なファジングの肝となる技術のひとつに、検査対象で問題が起きそうな入力データを生成する仕組みがあります。この仕組みの高度化が発見困難な不具合の発見を可能にします。ファジングの入力データを生成する仕組みを私の独断と偏見で分類した結果は次のとおりで、syzkaller はレベル 4 に該当すると考えます。なお、ファジングのターゲットはネットワーク越し限定からそうでないものまで多岐に渡ります。

表:ファジングの入力データを生成する仕組みの分類

レベル 仕組み 効率 網羅 備考
1 プロトコル等を考慮しない完全なランダム × 実際の入力とは程遠い入力パターンが生成される
2 キャプチャしたパケットをテンプレートとしてその一部を改変 × キャプチャした範囲内の入力パターンしか生成されない
3 プロトコル仕様や問題の起きそうな入力パターンを人間が実装しておき活用 主要な商用ツールで採用されている手法
4 レベル 3 に加えてソースコードのカバレッジを活用 syzkaller が採用している手法で、入力を変異させるときの分岐条件にソースコードを活用する

syzkaller とは

Google の Dmitry Vyukov さんによって開発されたカーネルのファジングツールです。冒頭でも触れましたが、2 年間でカバレッジを 7 %カバーした時点で、1500 件以上のカーネルの不具合修正に貢献した実績を持ちます。特徴は次のとおりです。

  • ハイブリッドな仕組みにより効率良くシステムコールのシーケンスを生成
    • 攻撃対象プロトコル (システムコール) のテンプレートが実装されている
    • ソースコードのコンパイル時にコンパイラが出力するカバレッジを利用して入力を変える
  • 不具合発見の一連の流れがほぼすべて自動化
    • 自らが生成した複数の試験対象の仮想マシンに対して問題の起きそうな入力を送り続けて、デバッグ支援機構を活用してその挙動を観測
    • 発見した不具合を最小限の入力で再現させるための再試行を自ら繰り返し、不具合を再現するための C 言語のプログラム生成を試みる

syzkaller の構成図

丁度良い syzkaller の構成図がなかったので作成してみました。

syzkaller の構成図

まずは、大まかな処理の流れだけ説明します。各コンポーネントの詳細は本記事の後半で説明します。

  • ユーザはコマンドラインで manager を起動します。
  • manager は ssh 経由で fuzzer のプロセスを立ち上げます。また、manager は試験対象となる VM の管理 (起動、監視、再起動) も行います。この VM は試験対象でもあることから、なにかあれば再起動されるため、いつ落ちてもおかしくない不安定な状態です。さらに、manager は workdir 配下のファイルの取得、作成、更新も行います。
  • fuzzer は試験対象となる VM の内部に存在するプロセスで、syzkaller 起動時の引数で指定された任意の数の executor を起動します。
  • executor は試験対象となる VM の内部に任意の数存在するプロセスで、fuzzer から syscalls のシーケンスを受け取り、ファジング対象のカーネルで syscalls のシーケンスを実行して結果を返します。

なお、一般的なアプリケーションの入力インターフェイスは API かもしれませんが、カーネルの入力インターフェイスはシステムコールです。システムコールは、ユーザ空間で動作するアプリケーションとカーネルを結ぶインターフェイスで、アプリケーションがカーネルの機能を安全に使用するために使用されます。ファイルをオープンする目的で使用される open() など、300 種類ほどのシステムコールとその引数の組合せで構成され、カーネルのファジングでは、何のシステムコールを選択し、どのような引数で、さらにはどのように組み合わせて、どの順番で送るかがポイントになります。

(参考) Sanitizer とは

syzkaller のコンポーネントではないですが、syzkaller の動作を理解する上で不可欠であるため、Sanitizer を簡単に紹介します。Sanitizer は、カーネルに存在する複数のデバッグ支援機構です。

  • 動的テストツール
  • コンパイラの機能 (gcc および C 言語で利用可能)
  • メモリを破壊したことや違反したことなどをはっきり示すもの
  • 不具合を示してくれるのでファジングを補助してくれる
  • エラーが起きたら、エラーの深刻度に関わらず、カーネルパニックを発生させる設定を使用する (コンソールにパニックメッセージを出力) 6

syzkaller が使用している Sanitizer の一例は次のとおりです。

  • KASAN (Kernel Address Sanitizer)
    • メモリアクセスエラーを検出
  • KMSAN (Kernel Memory Sanitizer)
    • 初期化されていない読み取りを検出
  • KTSAN (Kernel Thread Sanitizer)
    • 異なるスレッド間のデータの競合状態を検出
  • UBSAN (Undefined Behavior Sanitizer)
    • 未定義の動作を引き起こす機能の使用を検出

(参考) KCOV (Kernel Code Coverage) とは

syzkaller のコンポーネントではないですが、KCOV (Kernel Code Coverage) を簡単に紹介します。これは、コンパイラ (gcc) によって提供される機能です。有効化すると左の図から右の図のようになります。性能劣化を伴います。試験対象のカーネルではこれを有効化する必要があります。

  • カバレッジガイドファジングに適した形式でカーネルコードカバレッジ情報を生成
  • 使い方:CONFIG_KCOV = y
  • 条件:gcc 6.1.0 以降 (バージョン 231296 以降)

KCOV 無効時と KCOV 有効時のイメージ

syz-manager

  • 仮想化ホスト上に存在するプロセス
  • 試験対象としての VMs の管理 (起動、監視、再起動)
    • この VMs はカーネルパニックのたびに再起動
  • 試験対象としての VMs 内で syz-fuzzer プロセスを起動
  • syz-fuzzer プロセスに指示を送る
  • workdir 上のコーパスとクラッシュ (次節で説明) を更新

syz-manager

workdir/crashes/* と workdir/corpus/*

  • workdir/crashes/*

    • クラッシュに関わるアウトプット
    • アスタリスクにはハッシュ値が名前のフォルダが生成される
    • フォルダ内に次の情報を含む
      • description 事象を特定する件名
      • logN (N=0~99) syzkaller のログ
      • reportN (N=0~99) カーネルクラッシュレポート
      • repro.cprog 再現用の C 言語のプログラム
      • repro.log
      • repro.prog
      • repro.report
      • repro.stats
      • reproM (M=0~9)
  • workdir/corpus/*

    • コーパスは、個別ファイルとして格納されているファズターゲットの入力セット
    • 理想的なコーパスは、最大限のコードカバレッジを提供する最小限の入力セット

crashes と corpus

syz-fuzzer

  • 先述の不安定な試験対象 VMs 内に存在するプロセス
  • テストケース (入力) を生成、突然変異、最小化
  • 任意の数の syz-executor プロセスを起動
  • コーパスの有無で条件分岐して Generate 関数もしくは Mutate 関数のいずれかを呼び出すことでシステムコールのシーケンスを決める

syz-fuzzer

syz-executor

  • 先述の不安定な試験対象 VMs 内に任意の個数存在するプロセス
  • syz-fuzzer から syscalls のシーケンスを受け取る
  • syscalls のシーケンスを実行する
  • syscalls の実行結果を syz-fuzzer に送り返す
  • 単一の executor プロセスのことを Proc とも呼ぶ (ソースコードを読むときに役立つ知識)
    • Proc がカーネルに送るデータは ProgData とも呼ぶ (ソースコードを読むときに役立つ知識)

syz-executor

最後に

本記事では syzkaller の全体像と大まかな機能を説明しました。なお、ソースコード調査から得られた細かいノウハウは割愛したため、細かいところまで見たい人は、勉強会の資料 の 18 ページから 26 ページもあわせて参照してください。

おまけの QA

Q1:syzkaller は、Linux 以外では、どのような環境に対応していますか。
A1:Akaros、Darwin/XNU、FreeBSD、Fuchsia、NetBSD、OpenBSD、Windows、gVisor などなど

Q2:カーネルではなく、ユーザ空間で動作するアプリケーションをファジングしたいんですけど。
A2:ClusterFuzz を使うと幸せになれるかもしれません。そして、試したら記事を書いて私に教えてくれると嬉しいです。

お断りとお願い

本記事の掲載内容は個人の見解であり、所属する企業やコミュニティの立場、戦略、意見を代表するものではありません。また、この記事を読んで、ファジングしてみたいと思った場合は、次の点に注意し "必ず自己責任" で実施してください。

  • 社内/学内のネットワークではやらないでください
  • 社内/学内のマシンではやらないでください
  • プライベート環境などの完全に隔離された環境で "自己責任"

本記事によって、製品リリース前の試験段階で見つかる不具合数が増加し、リリースされる製品の品質が少しでも向上することを願っています。


  1. z が濁音にならないのは、開発者がロシア出身の方だからだと思います。 

  2. 当日の内容を uchan_nos さん にメモにしていただきました。ファジングツール syzkaller は何を検査するものなの? もあわせてご参照いただければと思います。uchan_nos さん ありがとうございます! 

  3. syzkaller 側だけでなく、カーネル側にも syzkaller に役立つ機能が追加 されています。セキュリティ・キャンプに参加できる年齢の方は、参加するとパッチ投稿者に会えるかもしれません。 

  4. なにを言いたいのかといいますと、大規模な物理サーバやベアメタルインスタンスなどに大量にお金を使わなくても十分に試せます。ただし、仮想化環境で試す際は、Nested virtualization の有効化が事実上ほぼ必須だと考えます。エミュレーションは私は試していません。 

  5. CVE の件数はあくまでも推移を測るための指標であり、CVE 件数 = 脆弱性の件数 ではありません。CVE 番号の付いていないセキュリティ脆弱性なんて、、、 うわなにをするやめr 

  6. 厳密には warning などの文字列を syzkaller が検出し、カーネルパニック前に止めることもあります。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CakePHP3をPHP7.2で動かすときは気をつけろ

PHP7.2は曲者!?

以下の記事でも書いたが、PHP7.2でCakePHP3を動かそうとすると思わぬ事態に遭遇する。
https://qiita.com/21century_girl_/items/5be2606b3bfa98514952

元はといえば、サーバー移行の依頼を受けたため、「どうせならPHPのバージョンを上げるか」と軽い気持ちで、PHP7.1→PHP7.2にバージョンアップしたのです。

phpコマンドが動かん…

php -v

いつものこれ。
phpのバージョンを確認するコマンドですが、これが

command not found

と出て動かないわけですな。

php72 -v

これで動きます。

一応、簡易的な対応としては以下の記事に載せているのでここでは割愛
https://qiita.com/21century_girl_/items/5be2606b3bfa98514952

cronに設定したshellが動かん..

/etc/cron.dに以下のように設定したのです。

* * * * * root /var/www/html/***/bin/cake test

通常のcron設定ですね。
上記の場合は、cakephpのshell内のTestShell.phpを動かすといったイメージです。

しかし以下のエラーが。。

Failed to find a CLI version of PHP; falling back to system standard php executable /var/www/html/service/bin/cake: line 72: exec: php: not found

どうやら該当のファイルの72行目を見ると、phpコマンドを叩いてる模様…

for TESTEXEC in php php-cli /usr/local/bin/php

ただし、phpコマンドが効かない状態なので、このエラーが出ているわけです。

ではどうするか?

cronファイルに環境変数を設定

以下のように設定

PATH=/usr/local/bin:/sbin:/bin:/usr/bin:/usr/sbin/sendmail:/opt/remi/php72/root/usr/bin:/opt/remi/php72/root/usr/sbin

* * * * * root /var/www/html/***/bin/cake test

これでphpコマンドも利用可能になり、cakephpのshellも実行されました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む