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

第39回 Linuxカーネルのコンテナ機能 ― cgroupの改良版cgroup v2[3]

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

Ubuntuの次の長期サポート版のリリースが近づいています。それに合わせて,LXC関連のプロダクトもメジャーバージョンアップし,新しい長期サポート版をリリースしました。筆者はlinuxcontainers.orgやLXC/LXD関連の翻訳をやっていますので,一気に翻訳対象が増えて大変です。一度には出来ないので毎日少しずつ進めています。

さて,前回は,cgroup v2で使うファイルや,基本操作,親cgroupから子cgroupで使うコントローラを指定する方法を紹介しました。

今回も引き続き,cgroup v2が持つ基本的な機能を紹介していきましょう。

まずは,cgroup v2の特徴のひとつである,プロセスが末端のcgroupにしか所属できないことを紹介します。そのあと,cgroupが持つ状態通知機能について紹介します。この機能については,これまで連載で紹介していなかったv1の機能を含めて紹介します。

なお,この連載ではこれまでcgroupで各種のリソース制限を行う仕組みを「サブシステム」と呼んでいました。しかし,cgroup v2の文書では "Controller" が使われており,最近は「コントローラ」と呼ばれることが多いので,今回から「コントローラ」に統一しました。呼び方だけの話です。

今回の実行例は,cgroup v1についてはUbuntu 16.04LTS上で,cgroup v2については自由にcgroupがマウントできるPlamo Linux 6.2(カーネル4.11.12)上で実行しています。

子cgroupを持つ場合の制約

第37回で紹介したように,cgroup v1が持つ問題点のひとつであった「子cgroupのタスクと親cgroupの内部タスクの競合」問題を解決するために,リソース分配を行う場合は末端のcgroupにしかプロセスが所属できなくなりました。

この動きを紹介しましょう。

プロセスが所属した状態で子cgroupで使うコントローラを登録しようとした場合の動き

図1 root cgroupに子cgroupで使うコントローラを登録

図1 root cgroupに子cgroupで使うコントローラを登録

まずはroot cgroupで,子cgroupで使うコントローラを登録します図1)⁠

# echo "+io +memory +pids" > /sys/fs/cgroup/cgroup.subtree_control(子cgroupで使えるコントローラの登録)

上のようにio,memory,pidsコントローラを登録しました。続いてcgroupを作成します。

# mkdir /sys/fs/cgroup/test01(test01 cgroupの作成)
# cat /sys/fs/cgroup/test01/cgroup.controllers(test01で使えるコントローラの確認)
io memory pids

test01 cgroupを作成すると,先ほど登録したio,memory,pidsコントローラが使えるようになっています。

図2 子cgroupを作成しプロセスを追加

図2 子cgroupを作成しプロセスを追加

このtest01にプロセスを登録してみましょう図2)⁠

# echo $$ > /sys/fs/cgroup/test01/cgroup.procs(プロセスの追加)
# cat /sys/fs/cgroup/test01/cgroup.procs(追加したプロセスの確認)
3129
3139

無事に登録できましたね。ここまではこれまで紹介してきたcgroup v2で行う操作と同じです。

この状態で,test01の子cgroupで使うコントローラをcgroup.subtree_controlファイルに登録してみましょう。

# echo "+io +memory +pids" > /sys/fs/cgroup/test01/cgroup.subtree_control 
bash: echo: write error: Device or resource busy

エラーになりました図3)⁠

図3 プロセスが登録されているcgroupに子で使うコントローラは登録できない

図3 プロセスが登録されているので子cgroupで使うコントローラを登録しようとするとエラー

このように,自身にプロセスが所属している状態で,子cgroupでコントローラが使えるように設定しようとしてもエラーになります。

それでは,test01にプロセスが所属しない状態にして,再度コントローラを登録してみます。

# echo $$ > /sys/fs/cgroup/cgroup.procs(プロセスをrootに登録しtest01から削除)
# cat /sys/fs/cgroup/test01/cgroup.procs(test01にはプロセスがない状態)

test01に登録したプロセスをroot cgroupに移動させました図4)⁠

図4 

図4 cgroupからプロセスをroot cgroupに移動し削除

この状態で先ほどと同様にtest01に,子cgroupで使うコントローラを登録してみましょう。

# echo "+io +memory +pids" > /sys/fs/cgroup/test01/cgroup.subtree_control(登録してもエラーはでない)
# cat /sys/fs/cgroup/test01/cgroup.subtree_control(コントローラは登録されている)
io memory pids

無事,cgroup.subtree_controlファイルにコントローラが登録できました図5)⁠

図5 プロセスを削除したので子で使うコントローラが登録できた

図5 プロセスが所属していないcgroupに子で使うコントローラを登録

ここまでで,cgroupにプロセスが登録された状態では,子cgroupで使うコントローラを登録できないことが確認できました。

子cgroupで使えるコントローラを登録した状態でプロセスを登録しようとした場合の動き

次は,子cgroupでコントローラが使える状態では,そのcgroupにプロセスを登録できないことを確認してみましょう。

図6 子で使うコントローラが登録された状態で子cgroupを作成

図6 さらに子cgroupを作成

先ほどの例で作成したtest01に子cgroupを作ってみましょう。test01cgroup.subtree_controlファイルには,子cgroupで使えるコントローラが登録された状態のままです。

# mkdir /sys/fs/cgroup/test01/test02(test02の作成)
# cat /sys/fs/cgroup/test01/test02/cgroup.controllers
(test02ではtest01で登録したコントローラが使えるようになっている)
io memory pids

test02という名前のcgroupを作りました。test02で使えるコントローラを確認すると,test01cgroup.subtree_controlで設定したコントローラが表示されています図6)⁠

つまりtest01 cgroupは子孫にリソースを分配している状態です。

この状態で,test01にプロセスを登録してみます。

# echo $$ > /sys/fs/cgroup/test01/cgroup.procs
bash: echo: write error: Device or resource busy

プロセスを登録しようとすると,上のようにエラーとなります図7)⁠test01は子孫にリソースを分配しているからです。

図7 リソースを分配しているcgroupにはプロセスを登録できない

図7 リソースを分配しているcgroupにはプロセスを登録できない


ここまでの実行例で,次のような制約があることがわかりました。

  • 自身にプロセスが登録された状態で,子cgroupに対してコントローラが使えるように設定しようとするとエラーになる
  • 子cgroupに対してコントローラが使えるように設定した状態で,自身にプロセスを登録しようとするとエラーになる

第37回で紹介したとおり,コントローラを使ってリソース制限をする場合は,ツリー末端のcgroupにしかプロセスが登録できないようになっていることが確認できました。

子cgroupで使えるコントローラを登録していない場合の動き

それでは,子孫でリソース制限ができるように設定していない状態cgroup.subtree_controlにコントローラが登録されていない状態)で,ツリー末端以外のcgroupにプロセスを所属させようとしたらどうなるでしょう?

確認してみましょう。

# cat /sys/fs/cgroup/test01/cgroup.subtree_control(test01では子孫用にコントローラ登録なし)

このように,test01ではcgroup.subtree_controlは空で,子孫ではリソース制限はできない状態になっています。この状態でtest01の子cgroup test02にプロセスを登録します。

# echo 3129 > /sys/fs/cgroup/test01/test02/cgroup.procs(test01/test02にプロセスを登録)
# cat /sys/fs/cgroup/test01/test02/cgroup.procs(test02に登録されている)
3129

子cgroupであるtest02にプロセスが登録された状態で,その親であるtest01にプロセスを登録してみましょう。

# echo 3108 > /sys/fs/cgroup/test01/cgroup.procs(test01にもプロセスを登録)
# cat /sys/fs/cgroup/test01/cgroup.procs(エラーなく登録されている)
3108

上の実行例のように,特に制約を受けることなく,プロセスが登録できました図8)⁠つまり,子孫でコントローラが使えるように設定していない状態では,ツリー末端以外のcgroupにもプロセスが所属できます。

図8 子cgroupを持つがリソース分配をしていない場合はプロセスが所属可能

図8 子cgroupを持つがリソース分配をしていない場合はプロセスが所属可能


まとめると,

  • 自身にプロセスが所属していないときだけ,子孫にリソースを分配できる(子でコントローラが使えるように設定できる)
  • コントローラによるリソース制御を行わない場合は,ツリー末端以外の任意のcgroupにもプロセスが所属できる

という制約がcgroup v2には存在します。ただし,root cgroupにはデフォルトですべてのプロセスが所属しますし,rootでリソース制限をすることはありませんので制約はありません。つまり,

  • root cgroupには以上の制約はない

となります。

著者プロフィール

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

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

Plamo Linuxメンテナ。ファーストサーバ株式会社所属。

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

コメント

コメントの記入