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

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

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

今回は,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をインストールした環境で試しています。

$ sudo add-apt-repository ppa:ubuntu-lxc/lxc-lts
$ sudo apt-get update
$ sudo apt-get install lxc lxcfs
$ sudo apt-get remove cgmanager (cgmanagerは削除する)

LXCFSがどのように起動しているかを確認してみましょう。

$ grep lxcfs /proc/self/mounts
lxcfs /var/lib/lxcfs fuse.lxcfs rw,nosuid,nodev,relatime,user_id=0,group_id=0,allow_other 0 0

以上のように/var/lib/lxcfsにマウントされています。/var/lib/lxcfsを見てみると,

$ ls /var/lib/lxcfs
cgroup  proc
$ ls /var/lib/lxcfs/cgroup/
blkio  cpuacct  devices  hugetlb  name=systemd
cpu    cpuset   freezer  memory   perf_event
$ ls /var/lib/lxcfs/proc
cpuinfo  diskstats  meminfo  stat  swaps  uptime

以上のように/var/lib/lxcfs以下にはcgroupprocというふたつのディレクトリが存在し,cgroup以下は各サブシステムごとのディレクトリと,systemd用のディレクトリが存在します。proc以下は,LXCFSによって仮想化されるファイルが存在します。

LXCコンテナでのLXCFSの利用

以上のように起動したLXCFSが,LXCからどのように利用されるのかを簡単に見ておきましょう。

lxcfsパッケージをインストールすると,LXCコンテナから共通して読み込まれる設定ファイルとして/usr/share/lxc/config/common.conf.d/00-lxcfs.confというファイルがインストールされます。このファイルには第23回第24回で説明したフックが設定されています。

$ cat /usr/share/lxc/config/common.conf.d/00-lxcfs.conf
lxc.hook.mount = /usr/share/lxcfs/lxc.mount.hook
lxc.hook.post-stop = /usr/share/lxcfs/lxc.reboot.hook

このうちコンテナ起動時に読み込まれる/usr/share/lxcfs/lxc.mount.hookを見てみると,/var/lib/lxcfs以下にマウントされたlxcfsをコンテナにバインドマウントしていることがわかります。

  :(略)
if [ -d /var/lib/lxcfs/proc/ ]; then
    for entry in /var/lib/lxcfs/proc/*; do
        [ -e "${LXC_ROOTFS_MOUNT}/proc/$(basename $entry)" ] || continue
        mount -n --bind $entry ${LXC_ROOTFS_MOUNT}/proc/$(basename $entry)
    done
fi
  :(略)

以上で挙げた部分は/proc以下でLXCFSが対象とするファイルをバインドマウントしている部分ですが,同様にcgroupをバインドマウントする処理も記述されています。

それでは,先に紹介したふたつの機能を少し詳しく見ていきましょう。

著者プロフィール

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

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

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

Twitter:@ten_forward
技術系のブログ:http://d.hatena.ne.jp/defiant/

コメント

コメントの記入