Write and Run

it's a simple way, but the only way.

ZFS な FreeBSD に VIMAGE な Jail を構築してみた

KOBA789 です。
昨日作った Node.js ホスティング向けの Jail を既に2名のテストユーザーの方に使っていただいています。
まだ node-http-proxy の運用は開始していないので、外部からのウェブアクセスはできず、SSH しか繋がらないのですが……。
それはさておき、今回はその Jail 環境を構築したときのお話です。

発端

自分は高校でコンピュータ部の部長をしています。うちのコンピュータ部ではゲーム制作がメインなので、自分はあまり何かを作るということはないですが、他の高校1年の部員が RPG を作りたいと言うので、せっかくなら HTML5+JavaScript で作ったらどうかと勧めました。すると、どうやらマジになってくれたようなのでとても嬉しかったのですが、さらにさらに、ついでだから Git も使おうよ、と言いかけたところで、次のことに気が付きました。

  • Windows で Git を使うにはよくわからん GUI ツールを入れなければならない
  • そのよくわからんツールを学校のマシンにインストールすることは(セキュリティ的制限で)できない

(ノ∀`)アチャー
という経緯で「それならうちのサーバーを貸せばいいんじゃね?」と思ったわけです。
しかししかし、これにも問題があって、

  • まるごと一台貸せるほど台数に余裕が無い
  • koyomi サーバーなら貸せるけど非力すぎて残念

なので「では仮想マシンを立てよう」とも思ったのですが、仮想マシンはなんか RAM をバカ食いするイメージがあって嬉しくない。
そこで俺は思い出した。FreeBSD の Jail があるではないか、と。今でこそ Ubuntu Server 10.04 のサーバーが2台も動いていますが、自分が宅鯖始めた時は FreeBSD を使っていて、FreeBSD が大好きだったりします。
そして、どうせなら性能の良いマシンで贅沢環境を組みたいなぁとも思い、RAM 16GB、SSD 64GB、HDD 640GB というハードを用意しました。そしてファイルシステムは流行りの ZFS で、しかも Jail はただの Jail ではなく、ネットワークスタックを仮想化できる VIMAGE も使うことに。
SSD cached な ZFSFreeBSD の構築はFreeBSD Install Battle をして、Root On ZFS かつ SSD Cache な環境を手に入れたときのメモ - ダイアリーはてなブログを参照にしてください。

構築

以下、完全に記憶に頼って書いているので、変な所があったらツッコミお願いします。

データセットの準備

まず、ZFS Pool に Jail 用のデータセットを作ります。

# zpool list
NAME    SIZE  ALLOC   FREE    CAP  DEDUP  HEALTH  ALTROOT
zroot   596G  6.99G   589G     1%  1.00x  ONLINE  -
# zfs create -o 'mountpoint=/jails' zroot/jails
# zfs list
NAME                   USED  AVAIL  REFER  MOUNTPOINT
zroot                 11.1G   576G   669M  legacy
zroot/jails            728M   576G    37K  /jails
zroot/swap            4.13G   580G    16K  -
zroot/tmp               43K   576G    43K  /tmp
zroot/usr             5.53G   576G  3.73G  /usr
zroot/usr/home         454M   576G   454M  /usr/home
zroot/usr/ports       1.36G   576G  1.36G  /usr/ports
zroot/var             88.8M   576G  88.8M  /var
zroot/var/tmp           32K   576G    32K  /var/tmp

こんな感じ。/jails にマウントしておきます。
次にすべての Jail の元になるデータセットを作ります。ボイラープレートってやつですかね。

# zfs create zroot/jails/basejail

そして installworld と distributewoorld します。

# cd /usr/src
# make installworld DESTDIR="/jails/basejail"
# make distributeworld DESTDIR="/jails/basejail"

これで立ち上げる準備はできたので、とりあえずスナップショットを取っておきましょう。

# zfs snapshot zroot/jails/basejail@created

zfs では簡単にスナップショットが取れるので便利です。
さて、では実際にインスタンスを立ち上げてみましょう。まずは basejail を元にしたクローンデータセットを作ります。

# zfs clone zroot/jails/basejail@created zroot/jails/testjail

zfs ではクローンも一瞬です。クローンできたら実際に立ち上げてみましょう。

# jail -c vnet name=testjail host.hostname=testjail path=/jails/testkjail/ persist

これで立ち上がりました。jls コマンドで Jail の一覧を見てみます。

# jls
   JID  IP Address      Hostname                      Path
     1  -               testjail                      /jails/testjail

ネットワークの準備

さてここからはネットワークの設定です。
まず、ホスト側に epair と bridge を作成します。

# ifconfig bridge create
bridge0
# ifconfig epair create
epair0a

そして、ブリッジに物理インターフェースの re0(適宜読み替え) と作成した epair0a を追加、それぞれ up します。

# ifconfig bridge0 addm re0 addm epair0a ip
# ifconfig epair0a up

そして、epair の逆側、epair0b を testjail に割り当てます。

# ifconfig epair0b vnet 1

こうすると、testjail 側に epair0b が出現します。Jail に入って確かめてみます。

# jexec 1 /bin/csh
testjail# ifconifg
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
	options=3<RXCSUM,TXCSUM>
	inet6 ::1 prefixlen 128 
	inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 
	inet 127.0.0.1 netmask 0xff000000 
	nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
epair0b: flags=8843<BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=8<VLAN_MTU>
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
	media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
	status: active

こんな感じです。ifconfig の結果は結構適当なのでアテにしないでください。
確認できたら epair0b に IP アドレスを割り当てます。

testjail# ifconifg epair0b 192.168.11.128

ホストの IP が 192.168.11.6 なのでこんな感じにしました。適宜読み替えてください。
このままでは Jail からゲートウェイの外へ出られないのでデフォルトゲートウェイを追加します。

testjail# route add default 192.168.11.1

これで外のネットワークに接続できました。ルーティングテーブルを netstat で確認するため、/dev を testjail にマウントしましょう。

testjail# exit
# mount -t devfs dev /jails/testjail/dev

マウントできたら netstat -rn で確認します。

# jexec 1 csh
testjail# netstat -rn
Routing tables

Internet:
Destination        Gateway            Flags    Refs      Use  Netif Expire
default            192.168.11.1       UGS         0      470 epair0
127.0.0.1          link#1             UH          0        0    lo0
192.168.11.0/24    link#2             U           0       45 epair0
192.168.11.128     link#2             UHS         0        0    lo0

良い感じです。本当はこの下に IPv6 のルーティングテーブルが表示されますが省略しています。

完成

以上で最小構成は完成(のはず)です。お疲れ様でした。
あとは sshd を立ち上げるなりなんなりと。
devfs は用途に応じて適切に mount しましょう。