ejzailを使ったVIMAGE対応jailの作り方
背景
NFS サーバのメモリが余っているのが勿体無いので jail 環境を構築しようと思った.
しかしながら,通常の jail 環境の作り方では,ホスト OS の NIC に jail 環境用 IP アドレスを alias する必要があり,NFS は受け待ち IP アドレスを指定できないため,jail 環境用 IP アドレスで NFS サービスを待ち受けてしまう.これは意図しないことなのでよろしくない.
ということがわかったのでツイートしたら,VIMAGE でいけるよ,と教えてもらったので ezjail を使って VIMAGE 対応 jail を作ってみた.
(追記)
nfsd に -h [bindip] というオプションがあるらしい.これを使えばよかったかもしれない.
KVM との比較
KVM だと vnet インターフェースを自動で生成してくれるし,さらに libvirt を使えばブリッジまで行なってくれるが, jail や ezjail ではそこまでやってくれない.
vnet インターフェース相当である epair インタフェース(epair0a, epair0b の様なペアのインターフェースができる)を作って片方をゲスト OS に持って行けば,ホスト OS とゲスト OS をブリッジのように繋がる.また,ホスト OS 側の epair と外に繋がるインターフェースをブリッジすることでゲスト OS は外と繋がることができる.
ezjail のメモ
- ports は sysutils/ezjail
- 設定ファイルは /usr/local/etc/ezjail.conf
- デフォルトだと ezjail のルートは /usr/jails
- /usr/jails/basejail にバイナリがある.
- /usr/jails/newjail は各 jail のスケルトン.ツリー構造が重要.バイナリの実体は /usr/jails/basejail.必要なものだけをシンボリックリンクで持ってくる.
- /usr/jails/flavour は各 jail 毎に設定ファイル等を上書きするのに使う.puppet と連携させると便利と思った.
- jail の作り方:ezjail-admin create -f [flavour] [name] 0.0.0.0 (アドレスは最終的に消すので適当でOK)
- 各 jail の設定ファイル(各 jail のルートディレクトリや IP アドレス等):/usr/local/etc/ezjail/[name]
- jail 環境を作ったらすること
- /etc/fstab.[name] を編集./usr/ports, /home をマウントするようにする.
- /usr/local/etc/ezjail/[name] を編集.IP アドレスを消す.後は後述の変更をする.
問題点と課題の整理
ezjail のデフォルトでは以下3点の問題点があるために ejzail だけを使った VIMAGE 対応 jail の作成が出来ない.
- VIMAGE は対応 jail にするには jail に -c vnet オプションを渡す必要があるが,/etc/rc.d/jail は -c オプション指定時のフォーマットに対応していない*1ため,素の /etc/rc.d/jail は使えない.
- デフォルトの devfs のマウント方法は VIMAGE 対応を前提としていないため,jail 環境に /dev/*mem がなく,jail 環境でルーティングが出来ない.
- 通常の jail とは違って起動時に IP アドレスを割り当てない.そのためゲスト側で IP アドレス設定,ルーティング設定,サービス(sshd等)実行を jail 環境を立ち上げた後に行う必要がある.
ここでは課題としては以下の3点をあげた.
- /etc/rc.d/jail で -c vnet オプションを使えるようにして VIMAGE 対応 jail を作成できるようにする.
- jail 環境で /dev/*mem を使えるようにする.
- jail 環境が起動した後に epair インターフェースを渡して,IP アドレスの設定,ルーティングの設定,サービスの立ち上げを行うようにする.
以下で3つの課題に対する解決手順をまとめる.
解決策(1つ目):/etc/rc.d/jail で VIMAGE 対応 jail を作成できるようにする
まずは jail に渡すオプションを/etc/rc.conf に設定する.
- /etc/rc.conf
jail_flags="-c vnet"
次にこのオプションを解釈できるように /etc/rc.d/jail を書き換える.
デフォルトでは -c オプション無しなのでスペース区切りで path hostname [ip[,..] ] command を渡しているが,-c オプション指定時はparameter=value形式で指定する必要がある.
- /etc/rc.d/jail
> diff -u /etc/rc.d/jail /usr/src/etc/rc.d/jail --- /etc/rc.d/jail 2011-05-06 00:18:19.000000000 +0900 +++ /usr/src/etc/rc.d/jail 2010-12-22 02:09:25.000000000 +0900 @@ -635,10 +635,8 @@ i=$((i + 1)) done - eval ${_setfib} jail -J ${_tmp_jail}_ ${_flags} host.hostname=${_hostname} name=`echo ${_hostname} | cut -f 1 -d .` \ - path=${_rootdir} persist - cat ${_tmp_jail}_ | cut -f 1 -d " " | cut -f 2 -d = > ${_tmp_jail} - rm -f ${_tmp_jail}_ + eval ${_setfib} jail ${_flags} -i ${_rootdir} ${_hostname} \ + \"${_addrl}\" ${_exec_start} > ${_tmp_jail} 2>&1 if [ "$?" -eq 0 ] ; then _jail_id=$(head -1 ${_tmp_jail}) @@ -699,7 +697,9 @@ eval env -i /usr/sbin/jexec ${_jail_id} ${_exec_stop} \ >> ${_consolelog} 2>&1 fi - jail -r ${_jail_id} + killall -j ${_jail_id} -TERM > /dev/null 2>&1 + sleep 1 + killall -j ${_jail_id} -KILL > /dev/null 2>&1 jail_umount_fs echo -n " $_hostname"
解決策(2つ目):jail 環境で /dev/*mem を使えるようにする
devfs をマウントするときにどのデバイスを使えるようにするかは /etc/default/devfs.rules に書いているルールに従っている.どのルールを使うかは /usr/local/etc/ezjail/[name] の変数 jail_[name]_devfs_ruleset で指定している.
ルールを見ると devfsrules_unhide_basicにすれば /dev/*mem を使えそうなので, /usr/local/etc/ezjail/[name] を以下のように変更する.
- /usr/local/etc/ezjail/[name]
- i.e. /usr/local/etc/ezjail/cattleya02_osaka_remu
export jail_cattleya02_osaka_remu_devfs_ruleset="devfsrules_unhide_basic"
解決策(3つ目):jail 環境が起動した後に epair インターフェースを渡して,IP アドレスの設定,ルーティングの設定を行うようにする
/usr/local/etc/ezjail/[name] の jail_[name]_exec_xxx に設定することで jail 起動時にホスト OS 側,ゲスト OS 側で任意のコマンドを実行出来る.コレを使って epair インターフェースを渡したり,ゲスト OS 側の IP アドレス設定等を行う.
ゲスト OS 側で実行してくれる afterstart がうまく動かなかったので,ホスト OS 側から jexec コマンドを使ってゲスト OS 側の設定をする.以下の内容を /usr/local/etc/ezjail/[name] に追加した.
- /usr/local/etc/ezjail/[name]
- i.e. /usr/local/etc/ezjail/cattleya02_osaka_remu
export jail_cattleya02_osaka_remu_exec_prestart0="ifconfig epair0 create" export jail_cattleya02_osaka_remu_exec_prestart1="ifconfig epair0a up" export jail_cattleya02_osaka_remu_exec_prestart2="ifconfig bridge0 addm epair0a" export jail_cattleya02_osaka_remu_exec_poststart0="ifconfig epair0b vnet cattleya02" export jail_cattleya02_osaka_remu_exec_poststart1="jexec cattleya02 /sbin/ifconfig epair0b 10.3.2.21/24" export jail_cattleya02_osaka_remu_exec_poststart2="jexec cattleya02 /sbin/route add default 10.3.2.1" export jail_cattleya02_osaka_remu_exec_poststart3="jexec cattleya02 /etc/rc.d/sshd start" export jail_cattleya02_osaka_remu_exec_poststop0="ifconfig bridge0 deletem epair0a" export jail_cattleya02_osaka_remu_exec_poststop1="ifconfig epair0a destroy"
参考
hasegaw blog: FreeBSD VIMAGEを使ったTCP/IPのルーティング デモンストレーション
- VIMAGE 概要と設定例について参考にしました
http://www.jp.freebsd.org/cgi/mroff.cgi?subdir=man&lc=1&cmd=&man=jail&dir=jpman-5.2.0%2Fman§=8
- NFS サーバ上で jail 環境で構築するのがなぜよろしく無いのかを参考にしました
- prestart, poststart の実行環境/タイミングを参考にしました