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

第31回LXC 1.1[2]

LXC 1.1をのんびり紹介しているうちに、Ubuntu 16.04 LTSに向けて、次のバージョンのリリースが間近になってしまいました。うかうかしているとLXC 1.1の紹介が終わらないうちに、LXC 1.1がEOLになってしまいそうなので、慌てて今回の記事を書きました。

LXC 1.1の次は1.2かと思っていたら、linuxcontainers.org関連のプロダクトであるLXC、LXD、LXCFSすべてをバージョン2.0で揃えてリリースするようです。もうひとつ、cgmanagerというプロダクトがありましたが、こちらはLXCFSの進化に伴い不要となりましたので、今後は開発が終息していくようです。

1.1から2.0はそれほど大きな変更はなく、ライブラリについてもABIレベルでの互換性が維持されるようです。もちろん第29回と今回、LXC 1.1の新機能として紹介した機能はそのまま2.0でも使えるはずです。

今回はLXC 1.1の新機能や変更点のうち、設定ファイルに関係する部分を紹介します。

ディレクトリのinclude

LXCの設定ファイルでは、第11回で紹介したように、lxc.includeを用いて、他の設定ファイルをincludeできました。

LXC 1.1では、ファイルに加えて、lxc.includeにディレクトリを指定できるようになりました。

たとえば、LXCがインストールするcommon.confでは、デフォルトで以下のような設定が書かれています。

lxc.include = /usr/share/lxc/config/common.conf.d/

ここに設定したい内容を書いたファイルを置けば、デフォルトの設定ファイルを変更せずに全コンテナで有効にしたい設定ができます。

UbuntuにLXC 1.1をインストールすると、依存関係でLXCFSがインストールされます。その際、LXCコンテナがLXCFSを使うよう、フックを設定するためにファイルが置かれます。

コンテナがinitとして実行するプログラム

コンテナを起動する際に使うlxc-startコマンドで、コンテナ名だけを指定してコンテナを起動すると、システムコンテナが起動しました。これはlxc-startは、デフォルトでコンテナ内の/sbin/initをコマンドとして実行するためでした。

一方lxc-startコマンドを実行する際に、コマンドを指定してアプリケーションコンテナを起動できました。

$ sudo lxc-start -n ct01 -F -- /bin/bash
  :(略)
root@ct01:/#

LXC 1.1からは、lxc-startが実行するコマンドが設定で指定できるようになりました。上記の例と同じ指定を設定ファイルで行う場合は、コンテナの設定ファイルで以下のように設定します。

lxc.init_cmd = /bin/bash

lxc-startを実行すると、以下のように指定通りにbashが実行できていますね。

$ sudo grep lxc.init_cmd /var/lib/lxc/ct01/config
lxc.init_cmd = /bin/bash
$ sudo lxc-start -n ct01 -F
  :(略)
root@ct01:/# 

柔軟なlxc.cap.keepの設定

第12回で紹介したlxc.cap.keepは、コンテナで保持したいケーパビリティを指定するための設定項目でした。ここで指定したケーパビリティ以外はすべて削除されます。

この設定にnoneというキーワードを指定できるようになりました。

LXCは設定ファイルを順に読んでいきますので、lxc.cap.keepnoneを設定すると、それまでに許可されているケーパビリティを一旦すべて削除できます。その後に許可したいケーパビリティをlxc.cap.keepに指定すれば、コンテナに許可されているケーパビリティを一旦すべて削除したあとで、許可したいケーパビリティを設定できます。

lxc.includeなどを使って、全コンテナで共通の設定がなされている場合に、特定のコンテナだけではケーパビリティの設定を変えたい場合に便利ですね。

lxc.cap.keep = none      # この設定以前に許可されていたケーパビリティをすべて削除
lxc.cap.keep = net_admin # 許可したいケーパビリティを指定

以上の設定でCAP_NET_ADMINのみが許可されたコンテナになります。lxc.cap.keepの最後にnoneが設定されると、すべてのケーパビリティが削除された状態になります。

これまでは紹介していませんでしたが、LXCではケーパビリティ、cgroup、マウント、UID/GIDのマッピングといった複数の値を設定できる項目で空の値を設定すると、その時点でなされている設定値をクリアできます。

lxc.cap.drop = mac_admin mac_override sys_time sys_module
lxc.cap.drop =

ケーパビリティを削除する場合のlxc.cap.dropでは、以上のように設定すると、1行目で設定されている削除したい4つのケーパビリティが、2行目ですべてクリアされます。lxc.cap.dropでは、この空の値を設定する方法ですべてのケーパビリティを許可できました。

この設定をクリアする方法はlxc.cap.keepでも使えます。しかし、lxc.cap.keepの設定をクリアすると、すべてのケーパビリティが許可されてしまいます。つまり、LXC 1.0では、すべてのケーパビリティを削除するという設定を書くのは大変でした。

lxc.cap.keepnoneが指定できるようになり、一旦すべてのケーパビリティを削除してから、許可したいケーパビリティを簡単に設定できるようになりました。

コンテナのinitへ渡す環境変数

LXC 1.1では、lxc.environmentという設定が追加され、コンテナのinitに任意の環境変数を渡せるようになりました。

$ sudo grep lxc.environment /var/lib/lxc/ct01/config
lxc.environment = APP_ENV=production

たとえば、以上のようにAPP_ENVという環境変数にproductionという値を設定するように指示してみましょう。そして、コンテナを起動後にinitに設定されている環境変数を表示させてみます。

$ sudo lxc-start -n ct01
$ sudo lxc-attach -n ct01 -- sed -e 's/\x0/\n/g' /proc/1/environ
(environファイルは環境変数をNULL区切りで格納しているので改行に置き換えて表示)
APP_ENV=production
container=lxc
container_ttys=/dev/pts/0 /dev/pts/1 /dev/pts/2 /dev/pts/3

以上のように、lxc.environmentで設定したAPP_ENV=productionという環境変数が設定されています。

このlxc.environmentを使うと、コンテナの起動時に環境変数を参照して何らかの処理を行えます。

ちなみに、上記の例のcontainercontainer_ttysはLXCが内部的に設定している環境変数です。

LXC 1.0では、内部的には環境変数containerlxcという値が設定されているだけでした。Ubuntuの起動スクリプトでは、この環境変数を参照して、コンテナ内で実行されているかどうかを判定している部分があります。

container_ttysという環境変数はLXC 1.1になってから設定されるようになった変数で、systemdが要求するようです。この環境変数については、systemdのContainer Interfaceという文書に記載があります。

lxc.pivotdirの無効化

LXC 1.0では、pivot_rootシステムコールを使ってコンテナのルートファイルシステムを設定する際、lxc.pivotdirという設定の値を使用していました。

LXC 1.1では、pivot_rootを行う部分のコードがシンプルに書き換えられました。その際にlxc.pivotdirの値は使われなくなりました。

lxc.pivotdirを設定してもエラーにはなりませんが、設定は無視され、警告が出ます。

lxc.autodev処理の変更

lxc.autodevは、コンテナの起動時に、/dev以下に最小限必要なデバイスファイルを作成するための設定です。

LXC 1.0では、lxc.autodevはデフォルトで0(無効)になっていました。LXC 1.0で、この機能がどのような処理を行っていたのか、筆者はよくわかっていませんが、ホストの/dev/.lxc以下にコンテナ用のディレクトリを作成し、コンテナの/devにバインドマウントするというような処理を行っていました。

LXC 1.1では、このlxc.autodevの処理が書き直され、コンテナの/devはtmpfsでマウントされ、LXCが最小限のデバイスを作成しています。コードも非常にシンプルでわかりやすくなりました。

LXC 1.0では、非特権コンテナでlxc.autodevを使用すると問題が起こっていたようですが、これがLXC 1.1の実装で解消されたため、lxc.autodevはデフォルトでは1(有効)になりました。

これに伴い、いくつかのテンプレートファイルで、lxc.autodevが1で動作するように修正が行われています。

lxc.kmsgのデフォルト値の変更

lxc.kmsgは、コンテナの/dev/kmsg/dev/consoleへのシンボリックリンクとするための設定です。

1.0では、lxc.kmsgのデフォルト値は1(有効)でしたが、1.1で0(無効)がデフォルトになりました。コンテナのinitがUpstartの場合に、boot時のメッセージを見るために、この値を1にしていたようです。

このようなリンクは有害であると指摘されていたようですし、Ubuntuでinitがsystemdへ移行するのに伴い、デフォルト値が変更されました。

lxc.mount.auto の sys の変更

lxc.mount.auto第11回で説明した通り、コンテナ内で、proc、sysfs、cgroupの各ファイルシステムを自動的にマウントするための設定でした。

それぞれのファイルシステムをマウントする際のオプションが指定でき、より安全にコンテナ内でこれらのファイルシステムを利用できるようにマウントできました。

オプションは読み込み専用のro読み書き可能のrw書き込みさせたくないファイルは読み込み専用で、それ以外は書き込みできる形でマウントするmixedの中から選択できました。

たとえばlxc.mount.auto = proc:mixedという指定は、procファイルシステムを読み書き可能でマウントしますが、/proc/sys/proc/sysrq-triggerは読み込み専用でマウントしました。

1.0ではこの3つのファイルシステムのうち、sysfsをマウントする指定であるsysのみ、mixedオプションは指定できませんでした。

1.1で、sysmixedというオプションが新設されました。mixedを指定すると、sysfsを/sys以下に読み込み専用でマウントする一方で、/sys/devices/virtual/net/以下は書き込み可能でマウントします。これによりネットワークインターフェースの設定を変更できます。

sysでオプションを指定しない場合のデフォルト値は、1.0ではroでしたが、1.1ではmixedとなります。

sys:mixedまたはsys
sysを読み込み専用でマウントします。ただし、/sys/devices/virtual/net/は読み書き可能でマウントします。
sys:ro
/sysを読み込み専用でマウントします。
sys:rw
/sysを読み書き可能でマウントします。

1.0では、いくつかのディストリビューション用のデフォルトの設定ファイルでlxc.mount.autoが、それぞれのディストリビューションに適した値で指定されていました。1.1では、全ディストリビューション共通の設定ファイル内で、lxc.mount.autoの値がcgroup:mixed proc:mixed sys:mixedと指定されるようになりました。

まとめ

今回はLXC 1.1の新機能や変更点のうち、設定ファイルに関係する部分を紹介しました。

第29回と今回紹介した機能は、どちらかというと細かい改良ばかりです。

これらの細かい改良の中には、コンテナでのsystemdのサポートを考慮してなされた変更があります。その積み重ねで、LXC 1.1ではコンテナのinitとしてsystemdがサポートされるようになりました。

LXC 1.1はこのような細かい改良ばかりでなく、まだ紹介していないCRIUを使ったチェックポイント・リストアの機能が追加されています。この機能はLXC 1.1の新機能として紹介するつもりでしたが、間に合いませんでしたので、今後LXC 2.0と一緒に紹介していくつもりです。

おすすめ記事

記事・ニュース一覧