今回は、cgroupを操作したり、コンテナ特有の値の/proc以下のファイルを提供したりするLXC用のソフトウェアを紹介したいと思います。
LXCでは設定ファイル内でcgroupの設定を行い、コンテナに対するリソース制限を行います。この場合、cgroup操作はコンテナの外で行われますので、必ずしもコンテナ内でcgroupを操作する必要はありません。
しかし、LXCではコンテナ内でさらにコンテナを起動する「コンテナのネスト」をサポートしています。この場合、コンテナ内で起動するコンテナに対してリソース制限を行うために、コンテナ内でcgroupを操作する必要がでてきます。つまりコンテナ内でcgroupfsツリーを操作しなければなりません。
LXCでは、最初に第11回で説明したlxc.mount.auto
という設定を使用して、ホストのcgroupfsをバインドマウントすることにより、コンテナ内にcgroupfsを提供しました。
しかし、LXCは一般ユーザで起動する非特権コンテナをサポートしています。非特権コンテナの場合、ホスト上にマウントされているcgroupfsを直接操作することになるlxc.mount.auto
は使用できません。
そこでLXC 1.0リリース時点(Ubuntu 14.04LTS)では、cgmanagerというソフトウェアを使い、コンテナ内からcgroupの操作を行いました。
その後、cgmanagerでは解決できない問題が出てきたので、2015年初頭からLXCFSというソフトウェアの開発がスタートしました。LXC 1.1リリース時点ではcgmanagerとともに、LXCFSの使用もサポートされました。Ubuntu 15.04では、LXC 1.1とLXCFSの組み合わせでコンテナ内でcgroup操作が行えるようになっていました。
それでは、このcgmanagerとLXCFSについてもう少し詳しく見ていきましょう。
cgmanager
cgmanagerは、LXCでcgroupを管理するために2013年末に開発がスタートし、Ubuntu 14.04 LTSでLXC 1.0とともにインストールされました。この連載でも第10回で簡単に紹介しました。
cgroupはファイルシステムをマウントし、ファイルに値を書き込むことで簡単に利用できます。しかし、この頃から直接cgroupfsに存在するファイルを操作するのではなく、cgroupを管理する仕組みを通してcgroupを管理すべきという議論がなされるようになっていました。
cgmanagerは、D-Busを経由でcgroupに関する操作を受け付けcgroupを操作するデーモンで、この流れにも沿った実装でした。cgmanagerが独自のマウント名前空間を作成し、その中でcgroupfsをマウントし、受け付けたコマンドに沿った操作をcgmanagerで行います。
LXCコンテナは、cgmanager経由でcgroupに関わる操作を行うため、ホストで直接cgroupfsをマウントしていなくてもコンテナ向けのcgroupに関わる操作が行えました。
また、cgmanagerを使うことにより、コンテナ内でLXCを使ってコンテナを作成し、起動できるようになりました。コンテナ内ではcgmanagerへのプロキシが起動し、コンテナ内からはプロキシに対してコマンドを送って、ホスト上で起動しているcgmanagerへコマンドが伝達できました。この機能を使って、コンテナ内でも自身に関わるcgroupが操作でき、コンテナ内でcgroupを使用する必要があるLXCコンテナが起動できました。
ところがコンテナの利用が進み、コンテナを取り巻く環境が変化するとともに、cgmanagerでは対応できない問題が生じてきました。その問題のうち最も大きな問題は、systemdが広く使われるようになったことです。
LXCをインストールする最も主要なディストリビューションであるUbuntuでもinitがUpstartからsystemdに変更されましたので、cgmanagerで対応できない問題はLXCにおいても大きな問題になりました。systemdはcgroupを積極的に活用するため、initがsystemdである場合、cgroupfsがマウントされていることは必須です。
つまりUbuntuをはじめとして、ほとんどのディストリビューションが採用したsystemdがinitとして採用されている場合、コンテナ内でも、通常のcgroupfsと同様のインターフェースを利用してcgroupを操作できることが必須となり、cgmanagerでは対応できなくなりました。
また、systemdは起動してくるプログラムをcgroupを用いて管理するため、cgroupが頻繁に利用されます。このように頻繁にcgroupを参照するようなソフトウェアから使用する場合、D-Busという比較的遅いインターフェースを使っていると、パフォーマンス的にも問題となります。
そこで、LXCプロジェクトではcgmanagerに代わってこの後紹介するLXCFSが開発されました。これに伴い、cgmanagerはこれまでにリリースされた、cgmanagerがインストールされる環境をサポートするために保守のみが続けられるようになります。今後、cgmanagerが必要なレガシーな環境がなくなると、開発は終了となるでしょう。
LXCFS
前述のようなcgmanagerが持つ問題を解決するとともに、別に懸案となっていた問題を解決するために開発されたソフトウェアがLXCFSです。
LXCFSはふたつの機能を持っています。
- コンテナ向けのcgroupfsツリーの提供
- コンテナ向けの/proc以下のファイルの提供
LXCFSはホスト上で実行されます。ホスト上でどのようにLXCFSが実行され、FUSEファイルシステムがマウントされているかを見てみましょう。以下はUbuntu 14.04LTSに、LXCのオフィシャルなPPAから最新版LTSのLXC、LXCFSをインストールした環境で試しています。
LXCFSがどのように起動しているかを確認してみましょう。
以上のように/var/lib/lxcfs
にマウントされています。/var/lib/lxcfs
を見てみると、
以上のように/var/lib/lxcfs
以下にはcgroup
とproc
というふたつのディレクトリが存在し、cgroup
以下は各サブシステムごとのディレクトリと、systemd用のディレクトリが存在します。proc
以下は、LXCFSによって仮想化されるファイルが存在します。
LXCコンテナでのLXCFSの利用
以上のように起動したLXCFSが、LXCからどのように利用されるのかを簡単に見ておきましょう。
lxcfsパッケージをインストールすると、LXCコンテナから共通して読み込まれる設定ファイルとして/usr/share/lxc/config/common.conf.d/00-lxcfs.conf
というファイルがインストールされます。このファイルには第23回と第24回で説明したフックが設定されています。
このうちコンテナ起動時に読み込まれる/usr/share/lxcfs/lxc.mount.hook
を見てみると、/var/lib/lxcfs以下にマウントされたlxcfsをコンテナにバインドマウントしていることがわかります。
以上で挙げた部分は/proc
以下でLXCFSが対象とするファイルをバインドマウントしている部分ですが、同様にcgroupをバインドマウントする処理も記述されています。
それでは、先に紹介したふたつの機能を少し詳しく見ていきましょう。
コンテナへのcgroupfsツリーの提供
ひとつめの機能は、cgmanagerが解決できなかったコンテナ向けのcgroupfsツリーをFUSEを使って提供します。
バインドマウントされたcgroupfsツリーが、コンテナ内から参照された際には、そのコンテナに関係するcgroupのみを見せるように提供します。これによりsystemdなどのcgroupfsツリーが必要なソフトウェアに対して、実際にcgroupfsをマウントした時のようなツリーを見せられます。
ただし、cgmanagerはD-Busを使った汎用的な仕組みであったのに対し、LXCFSはLXC向けのソフトウェアであり汎用性はありません。
それではLXCFSがどのようにcgroupfsのツリーをコンテナに見せているかを見てみましょう。
まずはコンテナを起動します。ここではxenial01
という名前の非特権コンテナを起動してみました。
まず、コンテナ内から見たcgroupとホスト上から見たcgroupを比較した時にわかりやすいよう、ホスト上で"test01"というcgroupをcpuサブシステム以下に作成しておきます。
起動したコンテナ内でcpuサブシステム以下のcgroupがどのようになっているかを見てみましょう。
非特権コンテナですので、起動したユーザが書き込めるcgroupであるuser/1000.user/1.session/lxc/xenial01
に、コンテナ用のcgroupができています。そして、自身用のcgroupであるxenial01
というグループ以下にはcgroup用のファイルが存在しますが、本来各ディレクトリに存在すべきcgroup用のファイルが存在せず、ディレクトリだけが存在しています。先ほど作成した"test01"グループは存在しません。
このように、自身以外用のcgroupを見たり操作したりできないようになっています。この機能自体は第11回で説明したlxc.mount.auto
でcgroup:mixed
を指定した場合と同じです。
ここでホストからcpuサブシステム以下に存在する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のエラーが多数記録されています。
コンテナへの/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搭載です。
このホスト上で実行するコンテナには以下のようなcgroup関連の設定を行っています。
LXCFSが動作していない場合
まずは比較のためにLXCFSを停止させた状態で確認してみましょう。lxcfsパッケージがインストールされた状態では、コンテナ起動時にLXCFS関係のフックが動くように設定されていますので、フックが動かないようにしておく必要があります。
コンテナ内でいくつか/proc
以下のファイルを見てみましょう。
以上のようにホストと同じ値が見えています。/proc/uptime
ファイルの中身とfreeコマンドを実行した結果も見ておきましょう。
コマンドを実行したタイミングが違いますのでぴったり同じにはなりませんが、/proc/uptime
の中身はホストと同じようですし、freeコマンドを実行した結果もホストと同じ値が見えているようです。
LXCFSが動作している場合
では、LXCFSを起動した状態でどのようになるかを確認してみましょう。
以上のようにCPU数、メモリ搭載量共にコンテナ向けに設定したcgroupの値が反映されています。
ホストとコンテナの/proc/uptime
ファイルの中身を見てみると、明らかにホストとコンテナで異なることがわかります。
freeコマンドもコンテナの値を出力していますね。totalだけでなくusedやfreeの値も異なります。
以上のようにCPU数、メモリ搭載量共にコンテナ向けに設定したcgroupの値が反映されています。
ホストとコンテナの/proc/uptime
ファイルの中身を見てみると、明らかにホストとコンテナで異なることがわかります。
freeコマンドもコンテナの値を出力していますね。totalだけでなくusedやfreeの値も異なります。
以上のようにLXCFSにより、/proc以下のファイルがコンテナ向けの値を提供していることがわかります。
コンテナ上でリソースの消費状況などをモニタリングする際に、ホスト上でcgroupのファイルを見ることなく、ホストと同じコマンドが使えるので便利ですね。
まとめ
今回はLXCコンテナ内でcgroupを操作するための仕組みの変遷と、cgmanagerに代わって登場したLXCFSの動作を紹介しました。
LXCFSは今回説明したように、コンテナにcgroupfsと/proc以下のいくつかのファイルを提供するソフトウェアです。ところが、LXCFSのcgroupfs関連機能は、Ubuntuの現時点の長期サポート版である16.04では使われていません。
これは同様の機能がカーネルに実装されたためです。次回はこの機能について紹介したいと思います。
第10回 コンテナ型仮想化の情報交換会@東京
筆者が主催している「コンテナ型仮想化の情報交換会」の第10回目を、10月29日(土)に株式会社インターネットイニシアティブ本社にて開催しました。
勉強会を始めたころは、まさか10回も勉強会が続くとは思っていなかったのですが、最近のコンテナの盛り上がりもあり、勉強会で扱うネタが尽きることはありません。
今回もWindowsのコンテナのお話や、Goでコンテナをライブコーディングするといったセッションまで、色々な幅広いお話を聞くことができました。
当日の動画の公開や資料へのリンクを以下にまとめてありますので、ぜひご覧ください。