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

第24回 LXCの構築・活用[10]─ フック(2)

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

コンテナ開始前のフック

コンテナを開始させる前にはいくつかの場面でフックを指定できます。コンテナ"ct01"を作成し,フックを以下のように設定してみましょう。

lxc.hook.pre-start = /var/lib/lxc/ct01/hook

/var/lib/lxc/ct01/hookは以下のような内容です。引数を順番に表示し,その後フックで使える環境変数を表示しています。

#!/bin/bash
cat << EOF > /var/log/ct.log
The number of args: $#
Container name: $1
Section: $2
Hook type: $3
Additional arg: $4

LXC_ROOTFS_MOUNT: $LXC_ROOTFS_MOUNT
LXC_CONFIG_FILE: $LXC_CONFIG_FILE
LXC_SRC_NAME: $LXC_SRC_NAME
LXC_NAME: $LXC_NAME 
LXC_ROOTFS_PATH: $LXC_ROOTFS_PATH
EOF

これでコンテナを起動してみましょう。

$ sudo lxc-start -n ct01 -d 
$ sudo lxc-ls -f
NAME  STATE    IPV4       IPV6  AUTOSTART  
-----------------------------------------
ct01  RUNNING  10.0.3.87  -     NO         

lxc.hook.pre-startはコンテナのルートファイルシステムが設定されるよりも前ですので,/var/log/clone.logはホストOSから見たパスになります。ホスト上で見てみましょう。

$ sudo cat /var/log/ct.log 
The number of args: 3
Container name: ct01
Section: lxc
Hook type: pre-start
Additional arg: 

LXC_ROOTFS_MOUNT: /usr/lib/x86_64-linux-gnu/lxc
LXC_CONFIG_FILE: /var/lib/lxc/ct01/config
LXC_SRC_NAME: 
LXC_NAME: ct01 
LXC_ROOTFS_PATH: /var/lib/lxc/ct01/rootfs

先に説明した通り,引数はコンテナ名("ct01"),"lxc",フックタイプ("pre-start")の順で3つ渡っており,環境変数も期待通りの値になっています。

コンテナ開始前に実行されるlxc.hook.pre-startlxc.hook.pre-mountlxc.hook.mountlxc.hook.autodevは,コンテナの/(ルート)を移動させる前の処理ですので,/(ルート)はホストOSの/(ルート)と同じです。フックスクリプトのパスもスクリプト内でのパスもホストOS上で見たパスと同じになります。

ただしlxc.hook.pre-startだけはホストOSの名前空間で実行されますので,ここで行った処理はホスト上から見えてしまいます。コンテナ内に隔離したい処理はここで行わないようにしましょう。lxc.hook.pre-mount以降はコンテナの名前空間上での実行になりますので,ホストから見えることはありません。

コンテナ起動時のフックのうちlxc.hook.startだけは,コンテナのルートファイルシステムが移動した後の処理になりますので,ホストOS上の/var/lib/lxc/ct01/hookにスクリプトを置いてもコンテナからは見えませんので,指定するスクリプトはコンテナイメージ内に置いておく必要があり,パスの指定もコンテナ内のパスで指定する必要があります。

実際に見てみましょう。

$ sudo ls -lF /var/lib/lxc/ct01/rootfs/hook  (コンテナのルート以下にスクリプトを置く)
-rwxr-xr-x 1 root root 286 Mar 31 18:33 /var/lib/lxc/ct01/rootfs/hook*
$ sudo grep 'lxc.hook.start' /var/lib/lxc/ct01/config  (hookの指定はコンテナ内のパスで記述)
lxc.hook.start = /hook

以上のように,先ほどと同じスクリプトをコンテナのルートファイルシステム内に置きフックを設定して,コンテナを起動させてみましょう。

$ sudo lxc-start -n ct01 -d  (コンテナの起動)
$ sudo lxc-ls -f  (コンテナの起動を確認)
NAME  STATE    IPV4       IPV6  AUTOSTART  
-----------------------------------------
ct01  RUNNING  10.0.3.87  -     NO         
$ sudo lxc-attach -n ct01 -- cat /var/log/ct.log  (コンテナ内の/var/log/ct.logを確認)
The number of args: 3
Container name: ct01
Section: lxc
Hook type: start
Additional arg: 

LXC_ROOTFS_MOUNT: /usr/lib/x86_64-linux-gnu/lxc
LXC_CONFIG_FILE: /var/lib/lxc/ct01/config
LXC_SRC_NAME: 
LXC_NAME: ct01 
LXC_ROOTFS_PATH: /var/lib/lxc/ct01/rootfs

コンテナイメージ内に置いたスクリプト/hookが実行され,ログもコンテナ内に出力されていることがわかります。環境変数はきちんと渡っていますが,いずれもホストOS上のパスですので使い道はないかもしれませんね。

コンテナ終了後のフック

コンテナ終了時はフックは一つだけです。ホストOSの名前空間とホストOS上でのパスでフックが実行されます。lxc-start-ephemeralで設定されていたように,コンテナ終了後の後始末に使えますね。

コンテナ開始時と同じスクリプトを実行させると,フックタイプの表示が"post-stop"となる以外は先に示した出力と同じになります。

コンテナのクローン時のフック

クローン元となるコンテナにあらかじめフックを設定しておくと,クローン時に必要な処理が実行できます。ベースとなるコンテナを作成しておき,それを何度もクローンして実際に使うコンテナを作成する場合に便利ですね。

クローン時にはコンテナ開始時と終了時のフックで使えた引数,環境変数に加えて追加の引数を与え,スクリプト内でその引数を使って処理を行えます。lxc.hook.cloneに先ほどのスクリプトを与えてみましょう。

lxc.hook.clone = /var/lib/lxc/ct01/hook

以上のように設定した上で,lxc-cloneコマンドに追加の引数"test"を与えて実行してみます。

$ sudo lxc-clone -o ct01 -n clone01 -s -B overlayfs -- test
Created container clone01 as snapshot of ct01

出力されたファイルを見てみましょう。

$ sudo cat /var/log/ct.log
The number of args: 4
Container name: clone01
Section: lxc
Hook type: clone
Additional arg: test

LXC_ROOTFS_MOUNT: /usr/lib/x86_64-linux-gnu/lxc
LXC_CONFIG_FILE: /var/lib/lxc/clone01/config
LXC_SRC_NAME: ct01
LXC_NAME: clone01 
LXC_ROOTFS_PATH: overlayfs:/var/lib/lxc/ct01/rootfs:/var/lib/lxc/clone01/delta0

コンテナ開始時は引数が3つでした。一方,クローンの場合はコンテナ開始時に済っていた引数に加えて,追加で与えた引数 "test" も渡っています。クローン時はこのようにLXCが必ず渡す引数に加えて,追加の引数が4番目以降の引数として渡ります。

overlayfsを使ったクローンですので,LXC_ROOTFS_PATHの値はクローン先でoverlayfsを使う場合のlxc.rootfsの値になっています。

まとめ

今回はLXCで指定できるフックを紹介しました。また,フックを使う際に使える引数や環境変数にどのような値が渡るのかを紹介しました。

フックはコンテナの起動時のいくつかの場面と,終了時,クローン時に実行できます。前回説明したlxc-start-ephemeralコマンドのように,フックを使えば運用時に必要な処理が実行できます。有効に活用できる場面も多いでしょう。

フックを使う場合は,ホストOSの名前空間で実行されるのか,コンテナの名前空間で実行されるのか,その際の/(ルート)はどこなのかを意識しなければいけません。

LXC 1.1.2

今回の記事を書いている途中にLXC 1.1.2がリリースされています。リリースアナウンス日本語訳にもあるように変更点は多くなく,バグフィックスが中心のリリースとなっています。

著者プロフィール

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

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

Plamo Linuxメンテナ

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