目次

FreeBSD 11でjail環境を作る

用語

jail [監獄]
FreeBSDのjail機能そのものを指したり、同機能を用いて構築された(仮想)システム[=hosted/prisoner]を指したりする。要はサンドボックス。
hosted
jailシステムで隔離されたシステム、プロセス、サービスを表す。
host
jailシステムが動いているシステム、プロセス、サービスを表す。名前の通りの意味。
prisoner [囚人]
hostedに同じ
jailer [看守]
hostに同じ

試した環境

種jailの準備

jailの有効化

お馴染rc.confでjailを有効にする。

/etc/rc.conf
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 Installerの画面が出てくる。lib32だけ入れとけば問題ないと思う。portsはnullfsでjailerのツリーを共用すれば容量の節約になる。packagesしか使わねーぜ!!ってんならportsすら不要。その他設定は以下のとおりだが、種jailなのでなるべくクリーンな状態の方針で。

jailの追加と動作確認

試しに、作成した種jailにjailerと同じIPアドレスを割り当て、監獄の中から通信できるか試してみる。

/etc/jail.confに設定を書く。

/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などの使わないであろう機能のビルドオプションをデフォルトオフにしておく。

/jail/_seed/etc/make.conf
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
</code>
 
==== 種jailの設定 ====
 
再び種jailの中に入り、諸々設定する。
 
''freebsd-update''をしておく。srcは更新対象から外しておく(src込みでインストールしたならこの限りではない)。
 
<file conf /etc/freebsd-update.conf>
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も使っていい感じの値を設定してくだしあ。

/etc/pw.conf
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の記述を追加する。