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

第33回 cgmanagerとLXCFS ─ コンテナ内のcgroup管理[1]

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

コンテナへのcgroupfsツリーの提供

ひとつめの機能は,cgmanagerが解決できなかったコンテナ向けのcgroupfsツリーをFUSEを使って提供します。

バインドマウントされたcgroupfsツリーが,コンテナ内から参照された際には,そのコンテナに関係するcgroupのみを見せるように提供します。これによりsystemdなどのcgroupfsツリーが必要なソフトウェアに対して,実際にcgroupfsをマウントした時のようなツリーを見せられます。

ただし,cgmanagerはD-Busを使った汎用的な仕組みであったのに対し,LXCFSはLXC向けのソフトウェアであり汎用性はありません。

それではLXCFSがどのようにcgroupfsのツリーをコンテナに見せているかを見てみましょう。

まずはコンテナを起動します。ここではxenial01という名前の非特権コンテナを起動してみました。

$ lxc-start -n xenial01
$ lxc-ls -f
NAME     STATE   AUTOSTART GROUPS IPV4      IPV6 
xenial01 RUNNING 0         -      10.0.3.77 -    

まず,コンテナ内から見たcgroupとホスト上から見たcgroupを比較した時にわかりやすいよう,ホスト上で"test01"というcgroupをcpuサブシステム以下に作成しておきます。

$ sudo mkdir /sys/fs/cgroup/cpu/test01 ("test01" cgroupを作成)
$ ls -d /sys/fs/cgroup/cpu/test01      (作成されたことを確認)
/sys/fs/cgroup/cpu/test01

起動したコンテナ内でcpuサブシステム以下のcgroupがどのようになっているかを見てみましょう。

$ lxc-attach -n xenial01 -- find /sys/fs/cgroup/cpu -type f
(/sys/fs/cgroup以下の全ファイルを表示)
/sys/fs/cgroup/cpu/user/1000.user/1.session/lxc/xenial01/cpu.stat
/sys/fs/cgroup/cpu/user/1000.user/1.session/lxc/xenial01/cpu.cfs_period_us
/sys/fs/cgroup/cpu/user/1000.user/1.session/lxc/xenial01/cpu.cfs_quota_us
/sys/fs/cgroup/cpu/user/1000.user/1.session/lxc/xenial01/cpu.shares
/sys/fs/cgroup/cpu/user/1000.user/1.session/lxc/xenial01/notify_on_release
/sys/fs/cgroup/cpu/user/1000.user/1.session/lxc/xenial01/tasks
/sys/fs/cgroup/cpu/user/1000.user/1.session/lxc/xenial01/cgroup.clone_children
find: ‘/sys/fs/cgroup/cpu/user/1000.user/1.session/lxc/xenial01/cgroup.event_control’: Permission denied
/sys/fs/cgroup/cpu/user/1000.user/1.session/lxc/xenial01/cgroup.procs
(コンテナ用のcgroup以下にのみcgroup用ファイルが存在している)
$ lxc-attach -n xenial01 -- ls /sys/fs/cgroup/cpu/
user
$ lxc-attach -n xenial01 -- ls /sys/fs/cgroup/cpu/user
1000.user
(他のcgroupには本来存在するはずのcgroup用のファイルがない)

非特権コンテナですので,起動したユーザが書き込めるcgroupであるuser/1000.user/1.session/lxc/xenial01に,コンテナ用のcgroupができています。そして,自身用のcgroupであるxenial01というグループ以下にはcgroup用のファイルが存在しますが,本来各ディレクトリに存在すべきcgroup用のファイルが存在せず,ディレクトリだけが存在しています。先ほど作成した"test01"グループは存在しません。

このように,自身以外用のcgroupを見たり操作したりできないようになっています。この機能自体は第11回で説明したlxc.mount.autocgroup:mixedを指定した場合と同じです。

ここでホストからcpuサブシステム以下に存在するcgroupを見てみます。

$ find /sys/fs/cgroup/cpu -type d (cpu以下のcgroupを確認)
/sys/fs/cgroup/cpu
/sys/fs/cgroup/cpu/test01 (コンテナ内から見えなかったcgroupが存在している)
/sys/fs/cgroup/cpu/lxc    (コンテナ内から見えなかったcgroupが存在している)
/sys/fs/cgroup/cpu/user
/sys/fs/cgroup/cpu/user/1000.user
/sys/fs/cgroup/cpu/user/1000.user/1.session
/sys/fs/cgroup/cpu/user/1000.user/1.session/lxc
/sys/fs/cgroup/cpu/user/1000.user/1.session/lxc/xenial01
/sys/fs/cgroup/cpu/user/1000.user/c1.session
$ ls /sys/fs/cgroup/cpu
cgroup.clone_children  cgroup.procs          cpu.cfs_period_us  cpu.shares  lxc                release_agent  test01
cgroup.event_control   cgroup.sane_behavior  cpu.cfs_quota_us   cpu.stat    notify_on_release  tasks          user
(各cgroup直下にもcgroup用ファイルが存在している)

cpu以下には,コンテナ内から見たときには存在していなかったlxcや,さきほど作成したtest01というcgroupが存在しており,各cgroupを表すディレクトリ直下にはcgroup用のファイルが存在します。

このようにホスト上に存在するコンテナと関係のないcgroupは見せずに,コンテナ向けのcgroupだけを操作できるようにcgroupfsを提供する機能をLXCFSが提供しています。

それでは,第11回で説明した,lxc.mount.autoで提供されるcgroupと,LXCFSが提供するcgroupの違いは何でしょう?

筆者はLXCFSの実装をきちんと読んでないのではっきりとはわからないのですが,LXCFSにはsystemd依存の処理が入っているようです。そのため,LXCFSを使って起動した非特権コンテナ内では,systemdが出力するエラーが少し記録されているだけですが,LXCFSを使わずにlxc.mount.autoで起動したコンテナでは,systemdが出力するcgroupのエラーが多数記録されています。

$ lxc-attach -n xenial01 -- journalctl -b -p 4 (コンテナ内のsystemdのログを見てみる)
-- Logs begin at Mon 2016-11-21 12:17:16 UTC, end at Mon 2016-11-21 12:17:16 UTC. --
Nov 21 12:17:16 xenial01 systemd[1]: Failed to reset devices.list on /user/1000.user/1.session/lxc/xenial01/system.slice/systemd-journal-flush.service: Operation not permitted
Nov 21 12:17:16 xenial01 systemd[1]: Failed to reset devices.list on /user/1000.user/1.session/lxc/xenial01/system.slice/networking.service: Operation not permitted
Nov 21 12:17:16 xenial01 systemd[1]: Failed to reset devices.list on /user/1000.user/1.session/lxc/xenial01/system.slice/systemd-tmpfiles-setup.service: Operation not permitted
Nov 21 12:17:16 xenial01 systemd[1]: Failed to reset devices.list on /user/1000.user/1.session/lxc/xenial01/system.slice/systemd-journal-flush.service: Operation not permitted
(同様のエラーが多数記録されている)

コンテナへの/proc以下のファイルの提供

ふたつめの機能は,/proc以下に存在するファイルのいくつかをコンテナ向けカスタマイズして提供します。

これまでもPIDやマウント名前空間により,コンテナ向けの/procが提供できました。しかし,リソースの状態を提供するようなファイルの中身はホストと同じ値が提供されていました。このため,メモリの消費状況を表示するためにリソース表示系のコマンドを使った場合,ホスト上で実行した際と同じ値がそのまま表示されていました。

このため,コンテナ内で消費されているリソースをモニタリングする際は,ホスト上でcgroupが提供するファイルから値を読み取る必要がありました。

LXCFSを使うと,LXCFSがコンテナのcgroupから値を読み取り,コンテナ内で/proc以下の対象となるファイルが読まれた場合に,コンテナごとの値を表示します。この機能により,コンテナ内でもホスト上と同じようにコマンドを実行して,コンテナ内のリソース状態をチェックできます。

LXCFSでは以下のファイルでコンテナ向けの値を提供します。

  • /proc/cpuinfo
  • /proc/diskstats
  • /proc/meminfo
  • /proc/stat
  • /proc/swaps
  • /proc/uptime

では,この機能が有効に働いていることを確認してみましょう。

ホストは以下のようにCPUが2つ,メモリは1GB搭載です。

$ grep processor /proc/cpuinfo 
processor   : 0
processor   : 1
$ grep MemTotal /proc/meminfo 
MemTotal:        1017724 kB

このホスト上で実行するコンテナには以下のようなcgroup関連の設定を行っています。

$ sudo grep cgroup /var/lib/lxc/xenial01/config
lxc.cgroup.memory.limit_in_bytes = 512M (メモリ制限を512MBに)
lxc.cgroup.cpuset.cpus = 0              (CPUは0番のみ使用)

LXCFSが動作していない場合

まずは比較のためにLXCFSを停止させた状態で確認してみましょう。lxcfsパッケージがインストールされた状態では,コンテナ起動時にLXCFS関係のフックが動くように設定されていますので,フックが動かないようにしておく必要があります。

$ service lxcfs status
lxcfs stop/waiting
$ sudo lxc-start -n xenial01

コンテナ内でいくつか/proc以下のファイルを見てみましょう。

$ sudo lxc-attach -n xenial01 -- grep processor /proc/cpuinfo 
processor   : 0
processor   : 1
$ sudo lxc-attach -n xenial01 -- grep MemTotal /proc/meminfo
MemTotal:        1017724 kB

以上のようにホストと同じ値が見えています。/proc/uptimeファイルの中身とfreeコマンドを実行した結果も見ておきましょう。

$ cat /proc/uptime ; sudo lxc-attach -n xenial01 -- cat /proc/uptime
1322.19 563.45
1322.22 563.45
$ free -m (ホスト上で実行)
             total       used       free     shared    buffers     cached
Mem:           993        724        269          0         43        583
-/+ buffers/cache:         97        896
Swap:         1019          0       1019
$ sudo lxc-attach -n xenial01 -- free -m (コンテナ上で実行)
             total       used       free     shared    buffers     cached
Mem:           993        725        268          0         43        583
-/+ buffers/cache:         98        895
Swap:         1019          0       1019

コマンドを実行したタイミングが違いますのでぴったり同じにはなりませんが,/proc/uptimeの中身はホストと同じようですし,freeコマンドを実行した結果もホストと同じ値が見えているようです。

LXCFSが動作している場合

では,LXCFSを起動した状態でどのようになるかを確認してみましょう。

$ service lxcfs status (lxcfsの起動を確認)
lxcfs start/running, process 7965
$ sudo lxc-start -n xenial01
$ sudo lxc-attach -n xenial01 -- grep processor /proc/cpuinfo
processor   : 0
$ sudo lxc-attach -n xenial01 -- grep MemTotal /proc/meminfo
MemTotal:         524288 kB

以上のようにCPU数,メモリ搭載量共にコンテナ向けに設定したcgroupの値が反映されています。

ホストとコンテナの/proc/uptimeファイルの中身を見てみると,明らかにホストとコンテナで異なることがわかります。

$ cat /proc/uptime ; sudo lxc-attach -n xenial01 -- cat /proc/uptime
839.24 563.43
217.0 217.0

freeコマンドもコンテナの値を出力していますね。totalだけでなくusedやfreeの値も異なります。

$ free -m
             total       used       free     shared    buffers     cached
Mem:           993        215        778          0         37        118
-/+ buffers/cache:         59        934
Swap:         1019          0       1019
$ sudo lxc-attach -n xenial01 -- free -m
             total       used       free     shared    buffers     cached
Mem:           512          6        505          0          0          0
-/+ buffers/cache:          6        505
Swap:         1019          0       1019

以上のようにCPU数,メモリ搭載量共にコンテナ向けに設定したcgroupの値が反映されています。

ホストとコンテナの/proc/uptimeファイルの中身を見てみると,明らかにホストとコンテナで異なることがわかります。

$ cat /proc/uptime ; sudo lxc-attach -n xenial01 -- cat /proc/uptime
839.24 563.43
217.0 217.0

freeコマンドもコンテナの値を出力していますね。totalだけでなくusedやfreeの値も異なります。

$ free -m
             total       used       free     shared    buffers     cached
Mem:           993        215        778          0         37        118
-/+ buffers/cache:         59        934
Swap:         1019          0       1019
$ sudo lxc-attach -n xenial01 -- free -m
             total       used       free     shared    buffers     cached
Mem:           512          6        505          0          0          0
-/+ buffers/cache:          6        505
Swap:         1019          0       1019

以上のようにLXCFSにより,/proc以下のファイルがコンテナ向けの値を提供していることがわかります。

コンテナ上でリソースの消費状況などをモニタリングする際に,ホスト上でcgroupのファイルを見ることなく,ホストと同じコマンドが使えるので便利ですね。

まとめ

今回はLXCコンテナ内でcgroupを操作するための仕組みの変遷と,cgmanagerに代わって登場したLXCFSの動作を紹介しました。

LXCFSは今回説明したように,コンテナにcgroupfsと/proc以下のいくつかのファイルを提供するソフトウェアです。ところが,LXCFSのcgroupfs関連機能は,Ubuntuの現時点の長期サポート版である16.04では使われていません。

これは同様の機能がカーネルに実装されたためです。次回はこの機能について紹介したいと思います。

第10回 コンテナ型仮想化の情報交換会@東京

筆者が主催している「コンテナ型仮想化の情報交換会」の第10回目を,10月29日(土)に株式会社インターネットイニシアティブ本社にて開催しました。

勉強会を始めたころは,まさか10回も勉強会が続くとは思っていなかったのですが,最近のコンテナの盛り上がりもあり,勉強会で扱うネタが尽きることはありません。

今回もWindowsのコンテナのお話や,Goでコンテナをライブコーディングするといったセッションまで,色々な幅広いお話を聞くことができました。

当日の動画の公開や資料へのリンクを以下にまとめてありますので,ぜひご覧ください。

著者プロフィール

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

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

Plamo Linuxメンテナ

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