🐈

FreeBSD サーバ上に仮想マシン(jail)を立てる

2023/06/06に公開

はじめに

この記事では、FreeBSD に jail を導入して、FreeBSD 上に仮想マシンを立てる手順を解説します。今回の実験環境は以下のようになっています。mac 上の VirtualBox で FreeBSD を動かしており、さらにその中で仮想マシンを立てる・・・というイメージです。

VirtualBox: 7.0
HostOS: macOS BigSur
GuestOS: FreeBSD 13.1-RELEASE

jail とは

jail は OS レベル仮想化機構実装の一つです。自分はざっくりと、FreeBSD 版 Docker と思っています。ただし、Docker は様々な OS 環境のコンテナを立てることができますが、jail は作成したコンテナが利用できる OS は FreeBSD のみになります。つまり、jail は、動かせるアプリケーションに制限があります。

Docker と jail の違いについては、参考資料を参照してください[1]

今回は、ezjail というパッケージを使って jail 環境を構築していきます。

ezjail のインストール

ezjail インストール

pkg install ezjail

rc.conf に追記

echo 'ezjail_enable="YES"' >>  /etc/rc.conf

設定ファイルを修正(option)

# /usr/local/etc/ezjail.conf 編集
# ezjail のディレクトリを指定できます。
# デフォルトでは、/usr/jails になっています。
# お好みでディレクトリを変更してください。
# 私はいつも /jails にしています。
ezjail_jaildir=/jails

jail ディレクトリを作成(上で指定したもの)

mkdir /jails

basejail を作成。basejail は ezjail で管理するすべての jail の元になる jail です。

ezjail-admin install
# jail ディレクトリを確認
ls /jails/
basejail	flavours	newjail

jail の作成と起動

ezjail のスコープ内に新しい jail を作成します。作成する jail 名は test とします。

[root@vitothon /jails]# cd /jails
[root@vitothon /jails]# ezjail-admin create test 0.0.0.0
[root@vitothon /jails]# ls
basejail	flavours	newjail		test <- 新しく作成されました

続いて jail コマンドを使用して jail を作成します。

# jail 名を test としています
[root@vitothon /jails]# /usr/sbin/jail -c vnet host.hostname=test name=test path=/jails/test persist
     -c      jail の作成(create)
     vnet    独自のネットワークインタフェース、アドレス、ルーティングテーブルなどを持つ、独自の仮想ネットワークスタックを供えた jail を作成
     persist このパラメタを設定すると、jail が任意のプロセスなしで存在することが可能

# ここで jls コマンドを使用すると、test が作成されていることが確認できます。
[root@vitothon /jails]# jls
   JID  IP Address      Hostname                      Path
     1                  test                          /jails/test

ファイルシステムのマウントをします。
devfs は、カーネルが管理するデバイス関係の情報をファイルシステムに見せかけて扱うことができるものです。

# mount -t タイプ デバイス マウント先ディレクトリ
[root@vitothon /jails]# mount -t devfs devfs /jails/test/dev
[root@vitothon /jails]# mount
devfs on /jails/test/dev (devfs) <- これが新しく追加されている
# devfs が /jails/test/dev にマウントされていることがわかります。

[root@vitothon /jails]# mount_nullfs /jails/basejail /jails/test/basejail
[root@vitothon /jails]# mount
/jails/basejail on /jails/test/basejail (nullfs, local, noatime, nfsv4acls) <- これが新しく追加されている

jexec コマンドで作成した jail に入ります。

[root@vitothon /jails]# jexec test /bin/csh
# この段階では、IP アドレスを割り当てていません
root@test:/ # ifconfig
lo0: flags=8008<LOOPBACK,MULTICAST> metric 0 mtu 16384
	options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
	groups: lo
	nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
# ホストマシンに対しての ping も通りません
root@test:/ # ping 192.168.56.103
PING 192.168.56.103 (192.168.56.103): 56 data bytes
ping: sendto: Network is unreachable

jail とホストマシンの疎通

lo0 インターフェースにループバックアドレスを設定する。

[root@vitothon /jails]# jexec test ifconfig lo0 127.0.0.1/24 up
[root@vitothon /jails]# jexec test ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
	options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
	inet6 ::1 prefixlen 128
	inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
	inet 127.0.0.1 netmask 0xffffff00 <- 設定されている
	groups: lo
	nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>

ホストマシンと jail を繋ぐための仮想インターフェースを作成

[root@vitothon /jails]# ifconfig epair create
epair0a
[root@vitothon /jails]# ifconfig
# epair0a, epair0b が作成されたことを確認
epair0a: flags=8862<BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=8<VLAN_MTU>
	ether 02:66:0b:7c:50:0a
	groups: epair
	media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
	status: active
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
epair0b: flags=8862<BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=8<VLAN_MTU>
	ether 02:66:0b:7c:50:0b
	groups: epair
	media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
	status: active
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
	
# MAC アドレス設定
[root@vitothon /jails]# ifconfig epair0a link 02:c0:e4:00:00:0a
[root@vitothon /jails]# ifconfig epair0b link 02:c0:e4:00:00:0b
[root@vitothon /jails]# ifconfig
epair0a: flags=8862<BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=8<VLAN_MTU>
	ether 02:c0:e4:00:00:0a <- 設定
	hwaddr 02:66:0b:7c:50:0a
	groups: epair
	media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
	status: active
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
epair0b: flags=8862<BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=8<VLAN_MTU>
	ether 02:c0:e4:00:00:0b <- 設定
	hwaddr 02:66:0b:7c:50:0b
	groups: epair
	media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
	status: active
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>

epair0a にアドレスを割り当てて up する(IP アドレスは 192.168.100.254

[root@vitothon /jails]# ifconfig epair0a 192.168.100.254 netmask 255.255.255.0
[root@vitothon /jails]# ifconfig epair0a up
[root@vitothon /jails]# ifconfig epair0a
epair0a: flags=8863<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=8<VLAN_MTU>
	ether 02:c0:e4:00:00:0a
	hwaddr 02:66:0b:7c:50:0a
	inet 192.168.100.254 netmask 0xffffff00 broadcast 192.168.100.255
	groups: epair
	media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
	status: active
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>

epair0bjail(test)に接続。IP アドレスを割り当てて、up する(IP アドレスは 192.168.100.1)。また、デフォルトルートを設定する。

[root@vitothon /jails]# ifconfig epair0b vnet test
[root@vitothon /jails]# jexec test ifconfig epair0b inet 192.168.100.1 netmask 255.255.255.0
[root@vitothon /jails]# jexec test ifconfig epair0b up
[root@vitothon /jails]# jexec test ifconfig epair0b
epair0b: flags=8863<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=8<VLAN_MTU>
	ether 02:c0:e4:00:00:0b
	hwaddr 02:66:0b:7c:50:0b
	inet 192.168.100.1 netmask 0xffffff00 broadcast 192.168.100.255
	groups: epair
	media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
	status: active
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
[root@vitothon /jails]# jexec test route add default 192.168.100.254

使用したコマンドのまとめ

ezjail-admin create test 0.0.0.0
/usr/sbin/jail -c vnet host.hostname=test name=test path=/jails/test persist
mount -t devfs devfs /jails/test/dev
mount_nullfs /jails/basejail /jails/test/basejail
jexec test ifconfig lo0 127.0.0.1/24 up
ifconfig epair create
ifconfig epair0a link 02:c0:e4:00:00:0a
ifconfig epair0b link 02:c0:e4:00:00:0b
ifconfig epair0a 192.168.100.254 netmask 255.255.255.0
ifconfig epair0a up
ifconfig epair0b vnet test
jexec test ifconfig epair0b inet 192.168.100.1 netmask 255.255.255.0
jexec test ifconfig epair0b up
jexec test route add default 192.168.100.254

jail からホストマシンへの ping

[root@vitothon /jails]# jexec test sh
--- ここから jail ---
# ping 192.168.100.1
PING 192.168.100.1 (192.168.100.1): 56 data bytes
64 bytes from 192.168.100.1: icmp_seq=0 ttl=64 time=0.036 ms
64 bytes from 192.168.100.1: icmp_seq=1 ttl=64 time=0.039 ms
64 bytes from 192.168.100.1: icmp_seq=2 ttl=64 time=0.039 ms
OK

jail の停止

ezjail-admin コマンドを使用して稼働している jail を止めます。ただし、jail に接続していた epair0b はホストマシンに再び接続されます。

[root@vitothon /jails]# ezjail-admin stop test
Stopping jails: test.
[root@vitothon /jails]# jls
   JID  IP Address      Hostname                      Path
[root@vitothon /jails]# ifconfig
epair0a: flags=8863<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=8<VLAN_MTU>
	ether 02:c0:e4:00:00:0a
	hwaddr 02:66:0b:7c:50:0a
	inet 192.168.100.254 netmask 0xffffff00 broadcast 192.168.100.255
	groups: epair
	media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
	status: active
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
epair0b: flags=8862<BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=8<VLAN_MTU>
	ether 02:c0:e4:00:00:0b
	hwaddr 02:66:0b:7c:50:0b
	media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
	status: active
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
	
# epair を削除する場合は以下のコマンドを実行(片方を指定すれば、もう片方も自動的に消えます)
# 再起動した場合は、epair は消えます
ifconfig epair0a destroy

参考文献

脚注
  1. https://academy.gmocloud.com/docker/20220201/14061 ↩︎

Discussion