linux:kernel:cgroup:cgmanagerの紹介

Introducing cgmanager

LXC はコンテナのリソースの追跡と制限に cgroups を使用する.階層構造の cgroups はファイルシステムを使うように管理されてきた.root が所有しているタスクは cgroup ファイルシステムをマウント可能で,自身の cgroup を変更したり,制限を変更したりできる.それゆえ LXC は AppArmor で cgroup のマウントを禁止し,必ずコンテナ自身の cgroup のみをコンテナ内にバインドマウントするようにしている.これは,新しいコンテナのために全ての新しい cgroup をたどって選択するために,それぞれの (cgroupの) コントローラに対する自身の cgroup を計算しなければいけないということでもある.他の複雑化の要因に加えて,このことにより cgroup に対応するための LXC 内のコードの量を大量に増やしていた.

これに対応しやすくするために,cgmanager という cgroup マネージャを書いた.この第一の目的は,いかなるタスクもシームレスに (ホストの安全性の観点から) セキュアに自身の cgroup を管理できることである.第二の目的は LXC がネストしているかどうかに関わらず,同じようにシンプルに cgroup に対応出来る事を保証することである.

cgmanager は cgroup 管理リクエストを作成するために D-Bus インターフェースを提供している.リクエストはそれぞれリクエストするタスクの現在の cgroup に関係して作成される.それゆえ 'lxc-start' は,現在どの cgroup に属するのかを心配する必要なしに,簡単に cgroup u1 を作成するリクエストが可能である.

この操作を行うために,D-Bus ソケットを通してリクエストしているタスクの (書き換えできない) プロセスのクレデンシャルを読んでいる./proc/pid/cgroup を使ってタスクの現在の cgroup をチェックしたり,/proc/pid/status,/proc/pid/uid_map をチェックしたりすることが可能である.「cgroup を作成する」というようなシンプルなリクエストのためには,これが必要な全ての情報である.

他のタスク (「このタスクを他の cgroup に移動する」) や権限 (「その userid に対する所有権を変更する」) といったリクエストに対しては,2 つのケースがある.もしリクエストする側が cgmanager と同じ名前空間にいる場合 (最近のカーネルでは確認可能) は,リクエストする側はそのまま整数 (訳注: 多分 uid/pid) として値を渡すことが可能である.リクエストする側がそのアクセスを行う特権を持っているかどうかを /proc を使って確認できる.

しかし,もしリクエスト側が異なる名前空間にいる場合,uid と pid を変換する必要がある.これは,リクエスト側がファイルディスクリプタを使って SCM_CREDENTIALS を渡すことにより行う.これが渡された時,カーネルは (a)リクエストタスクはこれらのクレデンシャルを書き込む特権を持つことを保証するか,(b)リクエスト側の名前空間から読み込み側(cgmanager)への変換を行う.

SCMエンハンスドな D-Bus コールは,通常の D-Bus コールより少し使うのが複雑であり,(パッチの当たっていない) dbus-send で作成することはできない.なので我々は cgmanager proxxy(cgproxy) を提供する.これは名前空間が同じのタスクから D-Bus リクエストを受け取り,エンハンスドなメッセージに変換する.そしてTrusty のコンテナホストを起動したとき,cgmanager も起動するでしょう.ホスト上のコンテナはそれぞれ cgmanager の D-bus ソケットをバインドし,cgproxy を実行します.(cgmanager の upstart ジョブは起動時に正しいデーモンを起動します) LXC はコンテナの内部で実行されても,ホストで実行されても,同じような方法で cgroup を管理します.

cgmanager は trusty では main 入りしました.trusty デスクトップにログインしたら,logind があなたをあなた自身の cgroup 内に入れます.あなたは /proc/self/cgroup を見てそれを確認できます.もしエントリが以下のようになっていたら,

2:cpuset:/user/1000.user/c2.session

あなたは自身の権限を委任された cgruop を持っていることになります.その代わりに以下のようであればそうでないことになります.

2:cpuset:/

dbus-send で長い呼び出しをする代わりにそれをラップするスクリプトである cgm を使って自身の cgroup を作ることも可能です.

sudo cgm create all $USER
sudo cgm chown all $USER $(id -u) $(id -g)

次に,自分のシェルを新しいグループに以下のように入れます.

cgm movepid all $USER $$

これで,あなたは https://www.stgraber.org/2014/01/17/lxc-1-0-unprivileged-containers/ にあるように自身の非特権コンテナを実行したりできますし,私は時々実行中のジョブを独立した freezer cgroup に入れて,CPU のクールダウンが必要な時は freeze させたいと思ったりします.

cgm create freezer cc
bash docompile.sh &
cgm movepid freezer cc $!

これは,私がやりたいときにジョブを手動で freeze させることもできますし,以下のようなスクリプトで CPU の温度を監視するスクリプトで実行することもできます.

state="thawed"
while [ 1 ]; do
	d=`cat /sys/devices/virtual/thermal/thermal_zone0/temp` || d=1000;
	d=$((d/1000));
	if [ $d -gt 93 -a "$state" = "thawed" ]; then
		cgm setvalue freezer cc freezer.state FROZEN
		state="frozen"
	elif [ $d -lt 89 -a "$state" = "frozen" ]; then
		cgm setvalue freezer cc freezer.state THAWED
		state="thawed";
	fi;
	sleep 1;
done
  • linux/kernel/cgroup/cgmanagerの紹介.txt
  • 最終更新: 2014/03/26 11:47
  • by tenforward