jail+zfs

jailとzfsと組み合わせて、種になるjailを作成して、そのスナップショットをテンプレートにしてzfs cloneで作成します。
設定周りのスクリプトがあればezjailとかなくても良いかも…

場所の確保

# zfs create -o mountpoint=/jail tank01/jail
# zfs create tank01/jail/base

元となるjailの構築

入れるのはbaseとlib32でとりあえず大丈夫でしょう。

# bsdinstall jail /jail/base

※baseシステムをupdateしているとftpで10.0-RELEASE-p1ディレクトリにアクセスしようとして、失敗するので注意1) /usr/libexec/bsdinstall/mirrorselect ディレクトリ名に uname -r を使用しているため。9.0-p3あたりから改善要望が出ているが、今のところ未対応の模様
2015.05.20 直った模様(10.1-RELEASE-p10で確認)

※最初のサイト選択で、<Other> を選択して、-pn (nはパッチレベル)を取り除くことでも対応可能

元となるjailのupdate

必要に応じて元jailをupdateしておく2) -b でbaseディレクトリを -d でtempを指定している 3) jailが起動していなくてもOK

# freebsd-update -b /jail/base -d /jail/base/var/db/freebsd-update fetch
# freebsd-update -b /jail/base -d /jail/base/var/db/freebsd-update install

jail環境で

# sysctl security.jail.param.allow.chflags=1

とすることで、jail環境内でも freebsd-update を利用できる模様。4) 2014.05.07現在未確認

設定

/etc/jail.conf

# common variables
exec.prestart += "ifconfig ${nic} inet ${ip4.addr} add";
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.poststop += "ifconfig ${nic} inet ${ip4.addr} -alias";
exec.clean;
$nic = "xn0";
mount.devfs;
path = "/jail/$name";
host.hostname = $name;
# each jail
base { ip4.addr = 192.168.0.128; }

この例では、ホストと同じネットワークに接続する設定で、起動時にIP alias を振ってる。

ホストと同じIPならこんな感じ

# common variables
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.clean;
mount.devfs;
path = "/jail/$name";
host.hostname = $name;
# each jail
base {
ip4.addr = <ホストのIPアドレス>;
allow.chflags; <= chflagsの使用許可(freebsd-updateが実行できるようにするため)
allow.raw_sockets; <= RAW SOCKETの使用許可(ping等が使用できるようにするため)
}

/etc/rc.conf

jail_enable="YES"

起動するjailを指定する場合

jail_list="jail01 jail02 jail05"

並列起動5) 起動に失敗するケースが有ったのでOFFにしてる

jail_parallel_start="YES"

スナップショット

# zfs snapshot tank01/jail/base@10.0p1

スナップショットの一覧

# zfs list -t snapshot

新しい監獄をzfs cloneで作る

# zfs clone tank01/jail/base@10.0p1 tank01/jail/NewJail

/etc/jail.confを忘れないように

起動

# service jail start base

一覧

# service jail status
OR
# jls
JID IP Address Hostname Path
1 - yourjail.localdomain /path/to/yourjail

jailに入る

# jexec 1 /bin/sh
↑ ↑ ログイン用シェル
↑ jail ID (jail名でも可)

止める

# service jail stop base

削除

# service jail stop base
# chflags -R noschg /jail/base/*
# rm -R /jail/base/*

pkgngの利用

pkgコマンドはjailの外から利用可能です

# pkg -j jail名|jailID info

ただし、先にjail内でpkgのインストールが必要です6) 現在は不要。12.1で確認

jail# pkg ちなみに、jail内でpkgコマンドを使う場合、updateもしておかないと、動かないので注意 jail# pkg update

Host側のディレクトリをマウント

nullfsを利用します。7) 古い記述だとカーネルの再構築が必要となっていますが、10.0では不要でした
例：/usr/ports を jailで共有する
/etc/fstabに以下のような記述

/usr/ports/ /jail/jail名/usr/ports nullfs ro,noauto 0 0

mountすればjail側で使えるようになります

# mount /jail/jail名/usr/ports

/etc/jail.confだとこんな感じで書けば、jailの起動時にマウントして停止時にumountしてくれるはず

jail名 {
exec.prestart += "mount /jail/jail名/usr/ports";
exec.poststop += "umount /jail/jail名/usr/ports";
}

/etc/jail.confで完結させる場合8) 12.0からmount_nullfsを使用するようになりました

exec.prestart += "mount_nullfs -o ro /usr/ports/ /jail/$name/usr/ports"; exec.prestart += "mount_nullfs /var/cache/pkg/ /jail/$name/var/cache/pkg"; exec.poststop += "umount /jail/$name/usr/ports"; exec.poststop += "umount /jail/$name/var/cache/pkg";

/usr/portsの場合

リードオンリーでマウントしてるので、このままではビルドが失敗します。以下のように /etc/make.conf で作業用のディレクトリを指定します。

WRKDIRPREFIX = /var/ports
DISTDIR = /var/ports/distfiles
PACKAGES = /var/ports/packages

共有メモリは推奨されない

PostgreSQLのように共有メモリを使用するものはJAILでの動作は推奨されない http://www.jp.freebsd.org/QandA/HTML/1866.html9) # sysctl -w security.jail.sysvipc_allowed=1

ListenポートとIPアドレスの調整

ホストとjailで別々のIPを振った場合、サーバソフトでもそれを意識した設定が必要
つまり、listenアドレスをきちんと指定しないとエラーを起こす。

ホストで待ち受けているポートを見る

# sockstat -l4
USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS
root sendmail 1359 3 tcp4 127.0.0.1:25 *:*
root sshd 1356 4 tcp4 *:22 *:*
root syslogd 1293 7 udp4 *:514 *:*

apache

/usr/local/etc/apache/httpd.conf

Listen 192.168.1.jailアドレス:80
Listen 192.168.1.jailアドレス:443

Nginx

/usr/local/etc/nginx/nginx.conf10) 前述手順でjailを作った場合なくても動いた

listen 192.168.1.jailアドレス:80

lighttpd

/usr/local/etc/lighttpd/lighttpd.conf

server.bind = "192.168.1.jailアドレス"
......
$SERVER["socket"] == "192.168.1.jailアドレス:80" { }

sshd

/etc/ssh/sshd_config10)

ListenAddress ＜ホストのIPアドレス＞

# service sshd restart
# sockstat -l4
USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS
root sendmail 1359 3 tcp4 127.0.0.1:25 *:*
root sshd 1356 4 tcp4 ＜ホストのIPアドレス＞:22 *:*
root syslogd 1293 7 udp4 *:514 *:*

syslogd

/etc/rc.confに以下を追記する

syslogd_flags="-ss"

# service syslogd restart
# sockstat -l4
USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS
root sendmail 1359 3 tcp4 127.0.0.1:25 *:*
root sshd 1356 4 tcp4 ＜ホストのIPアドレス＞:22 *:*
root syslogd 1293 7 udp4 ＜ホストのIPアドレス＞:514 *:*

inetd

/etc/rc.confに以下を追記する

inetd_flags="-wW -C 60 -a ＜ホストのIPアドレス＞"

jail内のUID/GIDの範囲を指定する

jail内の/etc/pw.conf（/jail/jail名/etc/pw.conf）で指定

defaultpasswd no
minuid 10000
maxuid 19999
mingid 10000
maxgid 19999

Memo

デフォルトの状態では、traceroute、ping、bpfを利用したWIDE-DHCP等のraw socketを利用するプログラムが正常に動作しません。 これらを利用するためには、hostの「/etc/sysctl.conf」に以下の記述を追記

security.jail.allow_raw_sockets=1

/etc/resolv.confの直し忘れが多いので注意

参考

復習 FreeBSD Jail

FreeBSD/Jailを使用したプログラマのための仮想環境

FreeBSD10.0Rでjailの設定

一歩進めたjail.confの書き方

FreeBSD - Jailは仮想化ではなく半仮想化と呼ぶべきではないか

qjail を使って簡易仮想環境作成

FreeBSD/Jail

FreeBSD 9.1 VIMAGE + ZFS で Jail環境構築

複数バージョンのFreeBSDをJailで共有させる方法

Convert FreeBSD 10 Jails from rc.conf to jail.conf

FreeBSD Jails with VLAN HOWTO

jail.conf

jails: Modularize configuration system (conf.d)

ZFS - スナップショットいつやるか?今でしょ!