もう10年以上看守していたオレが通りますよ。
- Free bsd jail入門
- 勉強会聴講メモ 【第28回 #FreeBSD 勉強会 数千台のFreeBSD Jailホストを管理する技術、実務実践からのテクニック】 #FreeBSDStudy | しげはるblog
上記記事の認識は間違っているとは言えないのだけど、正しいとも言い切れないと感じるので。
Jail != 仮想化
Jailに関して、一番「正しいとは言えない」のは、これ。
FreeBSD jail - WikipediaFreeBSD jailはOSレベル仮想化機構実装の一つである勉強会聴講メモ 【第28回 #FreeBSD 勉強会 数千台のFreeBSD Jailホストを管理する技術、実務実践からのテクニック】 #FreeBSDStudy | しげはるblog
FreeBSD上の仮想環境
そう。「Jail = 仮想化」という認識。
「カーネル共通なんでしょ?」「それって結局言葉のあやでしょ?」ですまない、知っていないと運用上はまる重大な違いがそこにはあるので、備忘録代わりにここに書いておくことにする。
まず仮想化とは何か。Wikipediaにはこうある。
仮想化 - Wikipedia仮想化(英語: virtualization)とは、コンピュータのリソースを抽象化することである。リソースの物理的特性を、そのリソースと相互作用するシステム/アプリケーション/エンドユーザーから隠蔽する技法。
「リソースの物理的特性を、そのリソースと相互作用するシステム/アプリケーション/エンドユーザーから隠蔽する技法」。Jailにおいて、隠蔽はなされているのか?
真のOS仮想化ではゲスト(guest OS)に相当する囚人側はなされているが、ホスト(host OS)に相当する看守からはなされていない、というのがその答えになる。
具体的には、このような形になって表れる。
- 囚人のファイルは、看守から丸見え
- たとえば
/jail/abashiri
に(jailによって)chrootされた囚人のパスが/foo/bar
だとしたら、看守からは/jail/abashiri/foo/bar
として必ず見える。 - 真の仮想化では、このようなことにはならない。ホスト側でサポートしていないファイルシステムでもゲスト側でサポートしてさえしていればよいし、ゲストのファイルシステムがあるのは仮想ディスクという名のファイルか nfs や iSCSI などのリモートディスクであり、ホスト側で強引にmountしないかぎり個々のファイルは見えない。
- 囚人のプロセスも、看守から丸見え
- 看守側で
ps
すれば、囚人側のプロセスもJ
フラグ付きで必ず見える。 - これまた真の仮想化ではありえない。
VirtualBox
とかbhyve
とか、一つのゲストOSにつき一つのプロセスが見えるだけだ。 - 囚人のネットワークインターフェイスも、看守から使いたい放題(ただしVIMAGEでない場合)
- 以下は、実際にうちで使っているJailの一つからDNSを引いている例である。
root@ports:/ # ifconfig lo1 lo1: flags=8049
あれ?ローカルのキャッシュサーバー使っているのに、サーバープロセスが見当たらないんだが…metric 0 mtu 16384 options=600003 inet 10.0.0.2 netmask 0xffffffff stf0: flags=1 metric 0 mtu 1280 root@ports:/ # cat /etc/resolv.conf nameserver 10.0.0.2 root@ports:/ # host www.example.com www.example.com has address 93.184.216.119 www.example.com has IPv6 address 2606:2800:220:6d:26bf:1447:1097:aa7 root@ports:/ # ps awwux USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND root 90537 0.0 0.0 14424 1436 - SsJ Fri02PM 0:03.44 /usr/sbin/syslogd -s root 90725 0.0 0.0 16520 560 - SsJ Fri02PM 0:00.58 /usr/sbin/cron -s root 72192 0.0 0.0 23488 3924 0 SJ 2:23PM 0:00.07 /bin/tcsh root 72202 0.0 0.0 16588 2104 0 R+J 2:24PM 0:00.00 ps awwux - 答えはもちろん、看守が動かしている、である。
Jailではまっている事例で最も多いのは、jexec
などで入獄してやるべき作業を看守のままやってしまったいうものなのであるが、なぜそうなのかといえば、それが出来てしまうからなのである。
私がJailを「仮想化」と呼びたくない理由が、それだ。Jailは仮想化の代わりとしても使えるし、そう使った場合仮想化コストもほぼゼロなので大変ありがたいのだが、実は何も仮想化されておらず、不可視化されているだけということを忘れると無実の囚人を殺すしてしまいがちだ。
「仮想化されているフリ」なので仮装化(masquerading)と呼びたいところであるが、これではダジャレにもほどがあるし、改変なしにゲストOSを運用する真の仮想化に対しホストOSにあわせて改変したゲストOSを運用することを準仮想化(paravitualization)と呼んでいるので、半仮想化(semivirtualizaion)と呼ぶのはどうか。
便利ツールいらずの当代Jail事情
通常の仮想化と半仮想化の違いが最も顕著に現れるのは、環境構築であろう。
通常の仮想化においては、まず仮想化アプリケーション上で仮想マシンを構築し、その上で実マシン(bare metal)の場合と同じようにゲストOSをインストールした後、さらにVirtualBoxであればGuest Addition、VMWareであればVMWare Toolsなどをインストールして、性能と利便性を向上させるための一種の準仮想化してから運用を開始するか、出来合いの仮想マシンファイルをもってくるかするのであるが、Jailの場合半仮想化だけあって、こうした下準備は全て看守側で行われる。
教科書どおりだと…
15.3. Creating and Controlling Jails# setenv D /here/is/the/jail # mkdir -p $D # cd /usr/src # make buildworld # make installworld DESTDIR=$D # make distribution DESTDIR=$D # mount -t devfs devfs $D/dev
ということになるが、これはいかにもめんどくさい。そういうこともあってezjailやqjailといった便利ツールが発達したのであるが、FreeBSD 9以降であれば、すっぴんでもこうしたツールが不要なほど楽が出来る。さらにzfsと組み合わせれば、新規Jailの構築も一瞬である。
- 用地確保
- ここではtankというzpoolに、
/jail
というprefixでjailを並べておくことにする。# zfs create -o mountpoint=/jail tank/jail # zfs create tank/jail/jail
- 種jailの構築
- ここでは
base
という名前にしておく。# bsdinstall jail /jail/base
インストールするパッケージは、base
とlib32
だけでよいだろう。 - 種jailへの
freebsd-update
の適用(optional) - 「囚人としてできることを看守でやらない」というのはJail作法の第1条なのであるが、
freebsd-update
の適用は残念ながら現時点においても囚人としてはできない。 -
# 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
としておこう。- 追記:
allow.chflags
を設定したJailであれば、jail内でもfreebsd-update
を発見した。freebsd-update cannot be applied in jail but this is because chflags is forbidden by default. I found allow.chflags enables update-in-jail
— Dan Kogai (@dankogai) April 27, 2014 - 追記:
- 仮想ネットワークの構築(オプショナル)
- Jailごとに固有のIPアドレスを用意しなければならないと思い込んでいる方は多いが、実は誤解である。Jailというのは、あくまで看守にすでにある資源の一部を囚人にとってそれが全部であるがように見せる技術であり、よって看守のIPアドレスをそのまま指定すれば普通に動くし、IPアドレスが全くないJailももちろん作れる。
- 余談であるが、現在のllevalでは、1 requestごとにJailを「構築」しているが、IPアドレスは看守と共通である(IPv4とIPv6が一つづつ)。
- しかしそれだと仮想化している感じもまた得られないので、ここでは最も手っ取り早い方法でJail用のIPアドレスを用意することにする。
-
/etc/rc.conf (抜粋)
cloned_interfaces="lo1" ipv4_addrs_lo1="10.0.0.1-15/32" pf_enable="YES" pf_rules="/etc/pf.conf"
/etc/pf.confext_if = re0 nat_if = lo1 nat on $ext_if from $nat_if to any -> ($ext_if)
- こうしておいてから
# service netif start lo1 # service pf start
とするか看守を再起動すれば、10.0.0.1-10.0.0.15が準備完了。 - /etc/jail.conf の作成
- 9以降のFreeBSDで一番変わったのがこれである。これさえあれば、
/etc/rc.conf
に書くのはjail_enable="YES"
だけでよい。# common variables exec.start = "/bin/sh /etc/rc"; exec.stop = "/bin/sh /etc/rc.shutdown"; exec.clean; mount.devfs; interface = lo1; path = "/jail/$name"; host.hostname = $name; # each jail base { ip4.addr = 10.0.0.1; } ports { ip4.addr = 10.0.0.2; } ports32 { ip4.addr = 10.0.0.3; } # .... and more
見ての通り、共通の設定項目とJailごとの設定項目を書き分けられるし、変数も使える。 - 動作確認
- というわけでまずは種jailがきちんと動くかどうかを確認する。
# service jail start base
でbaseのみstartしておいてから、# jexec base /bin/sh
として動作確認してみる。問題がなければexit
で看守に戻る。 - 問題としてよくあるのは、
/etc/resolv.conf
の書き(かえ)忘れ。特に local でキャッシュサーバーを動かしている場合、nameserver 127.0.0.1
としてあると思うが、明示的に囚人に見えるようにしていない限りこれは見えない。上記のjail.conf
の場合、# echo 'nameserver 10.0.0.1' > /etc/resolv.conf
とする必要がある。 - 種jailをclone
- あとは念のため
# service jail stop base
とした上で# zfs snapshot tank/jail/base@10.0p1
としておき、# zfs clone tank/jail/base@10.0p1 tank/jail/ports
とすれば一瞬でいくらでも監獄が作れる。
まとめ
JailとZFSは、私にとって今時のFreeBSDの魅力の双璧である。しかも、この両者の相性は抜群だ。今やLinuxにもLXCもZFS on Linux もあるけど、LXCはJailほどには軽くないし(しかしその分FreeBSDでは標準ではないネットワーク仮想化がなされている(FreeBSDのVIMAGE相当)などの利点もあるが)、ZFS on Linuxはカーネルのバージョンアップと同期してない(おかげでUbuntuでも最近まで使えなくなっていた)。枯れているが進化はまだ続いている。これからもがんがん使っていきたい。
Happy Jailing!
Dan the (Jail|Self-Prison)er
このブログにコメントするにはログインが必要です。
さんログアウト
この記事には許可ユーザしかコメントができません。