LXCで学ぶコンテナ入門 -軽量仮想化環境を実現する技術

第4回 Linuxカーネルのコンテナ機能[3] ─cgroupとは?(その2)

この記事を読むのに必要な時間:およそ 6.5 分

devicesサブシステム

devicesサブシステムはこれまでに説明したような数値で表されるリソースを制限するサブシステムではなく,cgroupに対するアクセス権を設定する機能です。

Linuxカーネルの持つコンテナ機能では,デバイスはコンテナごとに仮想化されることはありません。そのため,ホストOSから見えているデバイスへのコンテナに対するアクセス権を設定できるようにdevicesサブシステムが存在します。

アクセス権の設定はcgroup内のdevices.allow(cgroupがアクセス可能なデバイスリスト)devices.deny(cgroupがアクセスできないデバイスリスト)ファイルに設定します。この2つのファイルに3つのフィールドからなるエントリを設定し,アクセス権を設定します。

タイプ
ブロックデバイス(b⁠⁠,キャラクタデバイス(c⁠⁠,両方(a)
デバイスノード番号
メジャー番号とマイナー番号をコロンで連結
アクセス権
読み取り(r⁠⁠,書き込み(w⁠⁠,デバイスファイルの作成(m)

以下はtest1グループに対して,まず全てのアクセスを拒否した後,/dev/nullに対するアクセスを許可している例です。

$ echo a | sudo tee /sys/fs/cgroup/devices/test1/devices.deny 
a
$ echo 'c 1:3 rwm' | sudo tee /sys/fs/cgroup/devices/test1/devices.allow
c 1:3 rwm
$ cat /sys/fs/cgroup/devices/test1/devices.list
c 1:3 rwm

devices.allow,devices.denyファイルは設定専用のファイルですので,設定した結果はdevices.listファイルで確認します。

詳しくはカーネル付属文書のdevices.txtをご覧ください。

freezerサブシステム

freezerサブシステムはcgroupのサブシステムの中では少し変わった存在です。freezerはリソースを制御するのではなく,cgroupに属するタスクそのものの制御を行います。この機能を使うとcgroup内のプロセスを一括で一時停止させたり,一括で再開させたりできます。

実行中のコンテナの状態を保存して停止させ,その後再開させるcheckpoint/restartという機能があり,そこに使うことを考えて実装されたようです。しかし,現在checkpoint/restart機能のメジャーな実装であるCRIUではいまのところ使われていないようです。Docker Engine中のdocker pause/unpauseコマンドではこの機能を使っています。

ではfreezerサブシステムの使い方を簡単に見ておきましょう。今までの例と同様に,freezerサブシステムを/sys/fs/cgroup/freezerにマウントし,そこにtest1グループを作った上で試しています。freezerサブシステムには以下のようなファイルが存在します。

$ ls /sys/fs/cgroup/freezer/test1
cgroup.clone_children  cgroup.procs   notify_on_release
cgroup.event_control   freezer.state  tasks

freezerサブシステムを使ってcgroup内のタスクの状態を変えたり,現在の状態を確認するにはfreezer.stateファイルを使います。以下の3つの状態が存在し,freezer.stateファイルに,そのcgroupの状態が書かれています。

FROZEN
タスクは一時停止中
FREEZING
タスクの一時停止処理を実行中
THAWED
タスクは実行中

状態を変更するにはfreezer.stateファイルに変化させたい状態の文字列を書きます。一時停止させたいときはFROZENを,再開させたいときはTHAWEDを書きます。FREEZINGは状態の確認専用の値であり,書き込みはできません。

まずは他のサブシステムと同様にcgroupのtasksにシェルのPIDを登録します。

$ echo $$ | sudo tee /sys/fs/cgroup/freezer/test1/tasks 
1732

ここで別のシェルを起動します。

$ ps u -p 1732
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
karma     1732  0.0  0.7  24916  7436 pts/0    S+   15:03   0:00 -bash
$ cat /sys/fs/cgroup/freezer/test1/freezer.state 
THAWED

プロセスの状態の変化を見るためにpsコマンドを実行しています。freezer.stateファイルで状態を確認するとTHAWEDとなっており,プロセスは実行状態であることがわかります。

この状態でfreezer.stateファイルにFROZENを書き込み,一時停止状態にします。

$ echo 'FROZEN' | sudo tee /sys/fs/cgroup/freezer/test1/freezer.state
FROZEN
$ cat /sys/fs/cgroup/freezer/test1/freezer.state 
FROZEN
$ ps u -p 1732
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
karma     1732  0.0  0.7  24916  7436 pts/0    D+   15:03   0:00 -bash

書き込んだ後にfreezer.stateファイルを確認するとFROZENとなっており,一時停止状態であることがわかります。登録したPIDのシェルは反応がないはずです。psコマンドのSTAT欄を見てもプロセスの状態が変化しているのがわかります。

再度実行状態にするにはfreezer.stateTHAWEDを書き込みます。

$ echo 'THAWED' | sudo tee /sys/fs/cgroup/freezer/test1/freezer.state
THAWED
$ cat /sys/fs/cgroup/freezer/test1/freezer.state 
THAWED

状態がTHAWEDに変わっており,シェルも反応するはずです。

なお,ルート直下のcgroupに対しては一時停止ができません。そのためfreezer.stateファイルは存在しません。

freezerサブシステムもカーネル付属文書にfreezer-subsystem.txtがありますのでご参照ください。

まとめ

今回は最初に現在カーネルに実装されているサブシステムの紹介を行いました。続くサブシステムのマウントやプロセスの登録について説明の部分で,いくつかcgroupの特徴を説明しましたので,ここでまとめておきましょう。

今回紹介した特徴をあげる前に,おさらいとして前回紹介した特徴を再度載せておきます。

  • cgroupはcgroupfsという特別なファイルシステムで管理する
  • cgroup はディレクトリで表される
  • cgroupfsをマウントするとデフォルトでは全てのプロセスがトップディレクトリのグループにデフォルトで登録される子プロセスはデフォルトでは親のプロセスと同じcgroupに属する
  • cgroupは階層構造を取り,グループ間の親子関係を構成できる
  • システム上のプロセスは必ずcgroupfsのトップディレクトリ以下のcgroupのどれか1つだけに属する

ここに今回紹介した特徴が加わります。

  • cgroupを使って制御を行いたい機能ごとに『サブシステム』が存在する
  • cgroupfsには単独でサブシステムをマウントすることも,任意の複数のサブシステムを同時にマウントこともできる
  • cgroupfsは複数の階層を持つことができる
  • 同一のサブシステムを同時に別のマウントポイントにマウントすることはできない

最初に紹介した通り,サブシステムにはたくさんの種類がありますので,今回で全部を紹介することはできませんでした。次回は残ったサブシステムの紹介を行い,その後にcgroup開発の現状について少し触れたいと思います。

著者プロフィール

加藤泰文(かとうやすふみ)

2009年頃にLinuxカーネルのcgroup機能に興味を持って以来,Linuxのコンテナ関連の最新情報を追っかけたり,コンテナの勉強会を開いたりして勉強しています。英語力のない自分用にLXCのmanページを日本語訳していたところ,あっさり本家にマージされてしまい,それ以来日本語訳のパッチを送り続けています。

Plamo Linuxメンテナ

Twitter:@ten_forward
技術系のブログ:http://tenforward.hatenablog.com/