前回説明したように、lxc-start-ephemeral
コマンドはLXCの持つフック機能をコンテナの準備と後始末に利用していました。lxc-start-ephemeral
コマンドが使っていたフックは3つだけでしたが、それ以外にもいろいろな場面でフックが実行できるようになっています。
今回は、前回紹介できなかったフックを紹介しながら、もう少しフックについて詳しくみていきましょう。
フックの仕様
LXCで使用できるフックの一覧を表1に示します。
表1 フックの一覧
フック(設定項目) |
説明 |
実行される名前空間 |
lxc.hook.pre-start |
コンテナのTTY、コンソールの作成、マウントが実行される前に実行 |
ホスト |
lxc.hook.pre-mount |
コンテナのrootfsがマウントされる前に実行 |
コンテナ |
lxc.hook.mount |
マウントが完了後、pivot_root前に実行 |
コンテナ |
lxc.hook.autodev |
lxc.autodev=1の場合、lxc.hook.mountが実行された後、pivot_rootの前に実行 |
コンテナ |
lxc.hook.start |
コンテナのinitが実行される直前に実行 |
コンテナ |
lxc.hook.post-stop |
コンテナがシャットダウンされた後に実行 |
ホスト |
lxc.hook.clone |
新しいコンテナにクローンされる際に実行 |
コンテナ |
lxc.hook.clone
以外は、コンテナが起動してから終了するまでのある時点で実行されます。
コンテナのフックが実行される際に、コマンドライン引数として以下の値が順に渡されます。この引数をフックとして指定したプログラムから使用できます。
- コンテナ名
- セクション(常に'lxc')
- フックのタイプ
- 追加の引数(クローン時のみ)
またフック実行時には表2の環境変数が設定されます。
表2 フック実行時に設定される環境変数
環境変数 |
内容 |
LXC_NAME |
コンテナ名 |
LXC_ROOTFS_MOUNT |
rootファイルシステムをマウントする/したパス |
LXC_CONFIG_FILE |
コンテナ設定ファイルのパス |
LXC_SRC_NAME |
クローン時、元のコンテナの名前 |
LXC_ROOTFS_PATH |
lxc.rootfsの値 |
コンテナのルートファイルシステムのマウント処理
ここで、LXCがコンテナを起動する際にルートファイルシステムをどのように準備するかにふれておきましょう。これはフックが実行される際に設定される環境変数LXC_ROOTFS_MOUNT
に関係します。
コンテナのルートファイルシステムは、コンテナの設定ファイル中でlxc.rootfs
により設定されます。Ubuntuの場合、デフォルトだとlxc.rootfs
の値は/var/lib/lxc/(コンテナ名)/rootfs
となります。
しかし、コンテナを起動する際にはこのパスを直接使うわけではなく、lxc.rootfs
を別のディレクトリにバインドマウントします。このrootfsをマウントするディレクトリはlxc.rootfs.mount
に設定されたディレクトリが使われます。このlxc.rootfs.mount
の値がフックでLXC_ROOTFS_MOUNT
という環境変数で参照できます。
前回説明したlxc.hook.pre-mount
は、このマウント処理が行われる前に実行されます。
lxc.rootfs.mount
は特に設定しなければコンパイル時のデフォルト値が使われます。Ubuntuのx86_64環境の場合は/usr/lib/x86_64-linux-gnu/lxc
です。
このマウントが済んだ後に、pivot_rootシステムコールによりルートファイルシステムが変更され、コンテナのルートファイルシステムが設定されます。
lxc.hook.mount
とlxc.hook.autodev
は、マウント処理が済んだ後、pivot_rootによりルートファイルシステムが変更される前に実行されます。
それではコンテナを開始する前、終了した後、クローン時のフックで引数や環境変数がどのように渡っているのかを簡単に見てみましょう。
コンテナ開始前のフック
コンテナを開始させる前にはいくつかの場面でフックを指定できます。コンテナ"ct01"を作成し、フックを以下のように設定してみましょう。
/var/lib/lxc/ct01/hook
は以下のような内容です。引数を順番に表示し、その後フックで使える環境変数を表示しています。
これでコンテナを起動してみましょう。
lxc.hook.pre-start
はコンテナのルートファイルシステムが設定されるよりも前ですので、/var/log/clone.log
はホストOSから見たパスになります。ホスト上で見てみましょう。
先に説明した通り、引数はコンテナ名("ct01")、"lxc"、フックタイプ("pre-start")の順で3つ渡っており、環境変数も期待通りの値になっています。
コンテナ開始前に実行されるlxc.hook.pre-start
、lxc.hook.pre-mount
、lxc.hook.mount
、lxc.hook.autodev
は、コンテナの/(ルート)を移動させる前の処理ですので、/(ルート)はホストOSの/(ルート)と同じです。フックスクリプトのパスもスクリプト内でのパスもホストOS上で見たパスと同じになります。
ただしlxc.hook.pre-start
だけはホストOSの名前空間で実行されますので、ここで行った処理はホスト上から見えてしまいます。コンテナ内に隔離したい処理はここで行わないようにしましょう。lxc.hook.pre-mount
以降はコンテナの名前空間上での実行になりますので、ホストから見えることはありません。
コンテナ起動時のフックのうちlxc.hook.start
だけは、コンテナのルートファイルシステムが移動した後の処理になりますので、ホストOS上の/var/lib/lxc/ct01/hook
にスクリプトを置いてもコンテナからは見えませんので、指定するスクリプトはコンテナイメージ内に置いておく必要があり、パスの指定もコンテナ内のパスで指定する必要があります。
実際に見てみましょう。
以上のように、先ほどと同じスクリプトをコンテナのルートファイルシステム内に置きフックを設定して、コンテナを起動させてみましょう。
コンテナイメージ内に置いたスクリプト/hook
が実行され、ログもコンテナ内に出力されていることがわかります。環境変数はきちんと渡っていますが、いずれもホストOS上のパスですので使い道はないかもしれませんね。
コンテナ終了後のフック
コンテナ終了時はフックは一つだけです。ホストOSの名前空間とホストOS上でのパスでフックが実行されます。lxc-start-ephemeral
で設定されていたように、コンテナ終了後の後始末に使えますね。
コンテナ開始時と同じスクリプトを実行させると、フックタイプの表示が"post-stop"となる以外は先に示した出力と同じになります。
コンテナのクローン時のフック
クローン元となるコンテナにあらかじめフックを設定しておくと、クローン時に必要な処理が実行できます。ベースとなるコンテナを作成しておき、それを何度もクローンして実際に使うコンテナを作成する場合に便利ですね。
クローン時にはコンテナ開始時と終了時のフックで使えた引数、環境変数に加えて追加の引数を与え、スクリプト内でその引数を使って処理を行えます。lxc.hook.clone
に先ほどのスクリプトを与えてみましょう。
以上のように設定した上で、lxc-clone
コマンドに追加の引数"test"を与えて実行してみます。
出力されたファイルを見てみましょう。
コンテナ開始時は引数が3つでした。一方、クローンの場合はコンテナ開始時に済っていた引数に加えて、追加で与えた引数 "test" も渡っています。クローン時はこのようにLXCが必ず渡す引数に加えて、追加の引数が4番目以降の引数として渡ります。
overlayfsを使ったクローンですので、LXC_ROOTFS_PATH
の値はクローン先でoverlayfsを使う場合のlxc.rootfs
の値になっています。
まとめ
今回はLXCで指定できるフックを紹介しました。また、フックを使う際に使える引数や環境変数にどのような値が渡るのかを紹介しました。
フックはコンテナの起動時のいくつかの場面と、終了時、クローン時に実行できます。前回説明したlxc-start-ephemeral
コマンドのように、フックを使えば運用時に必要な処理が実行できます。有効に活用できる場面も多いでしょう。
フックを使う場合は、ホストOSの名前空間で実行されるのか、コンテナの名前空間で実行されるのか、その際の/(ルート)はどこなのかを意識しなければいけません。
LXC 1.1.2
今回の記事を書いている途中にLXC 1.1.2がリリースされています。リリースアナウンス(日本語訳)にもあるように変更点は多くなく、バグフィックスが中心のリリースとなっています。