====== FreeBSD 11でjail環境を作る ======
===== 用語 =====
? jail [監獄]
: FreeBSDのjail機能そのものを指したり、同機能を用いて構築された(仮想)システム[=hosted/prisoner]を指したりする。要はサンドボックス。
? hosted
: jailシステムで隔離されたシステム、プロセス、サービスを表す。
? host
: jailシステムが動いているシステム、プロセス、サービスを表す。名前の通りの意味。
? prisoner [囚人]
: hostedに同じ
? jailer [看守]
: hostに同じ
===== 試した環境 =====
* FreeBSD 10.1-RELEASE
* FreeBSD 11.1-RELEASE
===== 種jailの準備 =====
==== jailの有効化 ====
お馴染''rc.conf''でjailを有効にする。
jail_enable="YES"
jail_list=" "
==== jailのインストール ====
ZFSでjail用のFSを作り''/jail''にマウントする。もちろん、パスは任意でおk。
# zfs create -o mountpoint=/jail zroot/sys/jail
# cd /jails
jailディレクトリに展開されたシステムファイル群でしかないので、他のjailの種となるjailを1個用意しておけば、ただのディレクトリコピーで簡単にjailを増やすことができるのだ。ZFSのsnapshotなどと組み合わせれば、言わずもがな超高速かつ無駄を省いたjail環境を作ることも可能となる。
というわけで、種jailを作る。
''bsdinstall''でjail環境をインストールする。第二引数でインストールする場所≒jail名を指定するが、jail名にハイフンは含めないこと(詳しくは後述)。
# bsdinstall jail _seed
{{ :freebsd:jail:bsdinstall_jail_install.png |}}
これまたお馴染みのFreeBSD Installerの画面が出てくる。lib32だけ入れとけば問題ないと思う。portsはnullfsでjailerのツリーを共用すれば容量の節約になる。packagesしか使わねーぜ!!ってんならportsすら不要。その他設定は以下のとおりだが、種jailなのでなるべくクリーンな状態の方針で。
* rootのパスワード
* 何でもいいので取り敢えず設定。コピーjailを作った時に変更する。
* System Configuration
* チェックを全部外す(デフォでは何のデーモンも起動させない。)
* ユーザー追加
* 誰も追加しない。
==== jailの追加と動作確認 ====
試しに、作成した種jailにjailerと同じIPアドレスを割り当て、監獄の中から通信できるか試してみる。
''/etc/jail.conf''に設定を書く。
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.clean;
mount.devfs;
path = "/jail/$name";
host.hostname = $name;
_seed {
ip4.addr = ホストのIPアドレス;
allow.chflags;
allow.raw_sockets;
}
jail環境を起動。
# service jail start _seed
Starting jails: _seed.
ここで、jail名にハイフンが入っていると以下のようなエラーが大量に出る。上記設定の''ip4.addr''を処理する所でコケるようで、ハイフンは使えないっぽい?
/etc/rc.d/jail: WARNING: jail_extract_address: type not identified
expr: illegal option -- 2
expr: usage: expr [-e] expression
無事起動したら中に入ってみる。必要なのは''jexec''の行だけ。''uname''はjailerとprisonerの区別の為に入れてみたが、結果が似すぎてて分からん罠w
# jexec _seed /bin/sh
# uname -a
FreeBSD _seed 10.1-RELEASE-p10 FreeBSD 10.1-RELEASE-p10 #0: Wed May 13 06:54:13 UTC 2015 root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC amd64
# exit
$ uname -a
FreeBSD jail.example.com 10.1-RELEASE-p10 FreeBSD 10.1-RELEASE-p10 #0: Wed May 13 06:54:13 UTC 2015 root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC amd64
pingを打ってみる。
# ping decomo.info
PING decomo.info (59.106.13.158): 56 data bytes
64 bytes from 59.106.13.158: icmp_seq=0 ttl=56 time=17.167 ms
64 bytes from 59.106.13.158: icmp_seq=1 ttl=56 time=17.236 ms
64 bytes from 59.106.13.158: icmp_seq=2 ttl=56 time=17.215 ms
64 bytes from 59.106.13.158: icmp_seq=3 ttl=56 time=17.151 ms
^C
--- decomo.info ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 17.151/17.192/17.236/0.035 ms
jailから抜けてjailを止める
# service jail stop _seed
Stopping jails: _seed.
==== portsツリーの共有設定 ====
各jailでportsツリーを持つのは無駄なので、jail外に共有portsツリーを作りnullfsでマウントするようにする。
共有リソース用のFSを作る
# zfs create -o compression=gzip-5 zroot/sys/jail/_share
共有portsツリーを展開
$ cd /jail/_share
# mkdir ports distfiles
# portsnap -p ports fetch
# portsnap -p ports extract
# portsnap -p ports update
jail起動時に共有portsツリーをマウント、終了時にアンマウントするようにjail.confを修正。
exec.prestart += "mkdir -p /jail/${name}/usr/ports /jail/${name}/var/ports/distfiles"
exec.prestart += "mount -t nullfs -o ro /jail/_share/ports /jail/${name}/usr/ports";
exec.prestart += "mount -t nullfs -o rw /jail/_share/distfiles /jail/${name}/var/ports/distfiles";
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.poststop += "umount /jail/${name}/var/ports/distfiles";
exec.poststop += "umount /jail/${name}/usr/ports";
exec.clean;
mount.devfs;
path = "/jail/$name";
host.hostname = $name;
_seed {
ip4.addr = 218.251.112.107;
allow.chflags;
allow.raw_sockets;
}
portsの作業ディレクトリの設定
# mkdir /jail/_seed/usr/ports
# mkdir -p /jail/_seed/var/ports/distfiles
# mkdir -p /jail/_seed/var/ports/packages
make.confに作業ディレクトリの指定を追加。ついでに、Xなどの使わないであろう機能のビルドオプションをデフォルトオフにしておく。
WRKDIRPREFIX = /var/ports/
DISTDIR = /var/ports/distfiles/
PACKAGES = /var/ports/packages/
OPTIONS_UNSET=CUPS DEBUG DOCS FONTCONFIG NLS X11
WITHOUT_X11=yes
FORCE_MAKE_JOBS=yes
MAKE_JOBS_NUMBER=3
==== 種jailの設定 ====
再び種jailの中に入り、諸々設定する。
''freebsd-update''をしておく。srcは更新対象から外しておく(src込みでインストールしたならこの限りではない)。
Components world kernel # srcを消す
# freebsd-update fetch
# freebsd-update install
どのprisonerでもportmaster/pkgは使うことになると思うので、種に仕込んでおく。
# pkg
The package management tool is not yet installed on your system.
Do you want to fetch and install it now? [y/N]: y
Bootstrapping pkg from pkg+http://pkg.FreeBSD.org/freebsd:10:x86:64/latest, please wait...
(略)
# pkg install portmaster
他に同様のパッケージがあれば、この段階でインストールしておくと便利。参考までに自分が仕込んだのは以下の通り:autoconf automake bash emacs-nox gmake m4 perl5 sudo texinfo
一応、hostとjailでUID, GIDが被らないように設定。といっても、システムが自動で作るユーザー/グループ(rootとかwwwとかmysqlとか)には無力だし、ユーザー追加時に手動でいくらでも好きな数値が指定できるので、あんまり神経質なっても仕方がない。jail間の被りも避けたいなら、maxuid/maxgidも使っていい感じの値を設定してくだしあ。
minuid 30000
mingid 30000
===== 種jailから本番jailを生やす =====
ZFSのスナップショット&クローンを活用すれば、一瞬で種jailから本番jail環境を複製する事ができる。
まずはスナップショットを作る。
# zfs snapshot zroot/sys/jail/_seed@20180831
スナップショットは読み込み専用なので、cloneしてFSを作る。
# zfs clone zroot/sys/jail/_seed@20180831 zroot/sys/jail/www
こんな感じで本番jail環境が出来上がる。
$ zfs list
zfs list
NAME USED AVAIL REFER MOUNTPOINT
zroot 1.97G 36.5G 96K legacy
zroot/sys 1.96G 36.5G 96K legacy
zroot/sys/jail 1.96G 36.5G 104K /jail
zroot/sys/jail/_seed 1.20G 36.5G 1.20G /jail/_seed
zroot/sys/jail/_share 773M 36.5G 773M /jail/_share
zroot/sys/jail/www 8K 36.5G 1.20G /jail/www
あとは/etc/jail.confに作成したjailの記述を追加する。