お手軽に軽量な隔離環境を作るための kazuho さんの jailing とか、それにリソース管理の仕組みを加えた matsumotory さんの virtualing いいですね。
コンテナほどの隔離性は不要だし、一々イメージを落としてきて構築とかやるにはちょっと重たいなというシーンもあるわけで、そういう時に chroot、bind mount はお気軽で良いですし、それに cgroup でのリソース管理を加えてもそんなに重くはなりません。(docker だと他にも色々考えないとダメだし)
こういうのを思いついてサクッと作れてしまう才能がうらやましいわけですが、LXC を使えば才能がない私でも、何かをサクッと作る能力も努力もなく、もう少し隔離度を上げつつある程度の軽さを残した環境を LXC を使って作れますので、ここで紹介しましょう。
LXC 使っちゃったら、前述の軽さがなくなるから意味ないやんって話ですが、LXC ならコンテナ用のファイルシステムを作らずに bind mount を使ってコンテナを起動するのも簡単ですので、環境を作る手間のお手軽さと、bind mount を使ってホストのシステムを共用するというお手軽さは残して環境構築が可能です。
そもそもコンテナって、単に clone システムコールを使ってプロセス起動するだけなので、そんなに重くはならないでしょう、というお話です。もちろん LXC はそれ以外に色々やるので chroot に比べたら重いんですけどね。
bind mount を使った軽量(?)コンテナ
LXC にはコンテナ起動時にコンテナ用に何かをマウントするための設定があります。ここでホストのディレクトリやファイルを bind mount するだけで、ホストのシステムの一部をコンテナにエクスポートできます。
例えばホストの /usr をコンテナでそのまま使う場合、以下のように書けばそれでコンテナ起動時にマウントしてくれます。
lxc.mount.entry = /usr usr none ro,bind 0 0
つまり
- コンテナ用 rootfs 以下にディレクトリを作る (bind mount するにはマウントポイントないとダメですね)
- LXCの設定を書く
- lxc-startコマンドでコンテナ起動
これで jailing と同じような隔離環境が得られます。
LXC から cgroup を使うのも設定ファイルに制限値を設定すれば良いので、virtualing 相当の操作も可能ですね。
テンプレートを使って bind mount を使ったコンテナを作成する
言葉で書くと簡単ですが、ディレクトリを作ったり、設定ファイルを作ったりを手でやってると面倒で、jailing のお手軽さにかなうわけもありません。
そこで作ってみました。
LXC でコンテナを作る時は lxc-create コマンドにテンプレートを指定して作成します。その lxc-create に指定できるテンプレートファイルです。
$ sudo lxc-create -t bind -n (コンテナ名)
みたいにすれば、必要なディレクトリと設定ファイルを作成してくれます。
私の作った lxc-bind は決め打ちのところが多いです。そこはシェルスクリプトで書かれてるお気軽さですので、適当に変えてもらうということで。
もともと LXC には lxc-sshd というテンプレートが付属していて、これはまさしくコンテナのファイルシステムのほとんどをホストのディレクトリを bind mount して、sshd だけが起動するコンテナを作るテンプレートです。lxc-bind はこれを少し変えただけです。
jailing の例にあった /usr/local/apache/httpd を起動するコンテナを作るのも、
$ sudo lxc-create -t bind -n apache01 \ -- --bind=/usr/local/apache \ /usr/local/apache/bin/httpd \ -c /usr/local/apache/conf/httpd.conf $ sudo lxc-start -n apache01
ってな感じで簡単です (試してませんが :-p)。もちろん、作成したあとは起動させないとダメですので、jailing よりは実行するコマンドは増えます :-p
テンプレートに渡す引数なしで
lxc-create -t bind -n test01みたいに実行すると bash を実行するコンテナを勝手に作ります。他に dhclient を実行して勝手に eth0 にアドレスも割り当てます (lxc.network.ipv4 みたいな設定で静的に割り当てることも可能)。
実行例
$ sudo lxc-create -t bind -n test01 $ sudo cat /var/lib/lxc/test01/config lxc.network.type=veth lxc.network.link=lxcbr0 lxc.network.flags=up lxc.rootfs = /var/lib/lxc/test01/rootfs lxc.utsname = test01 lxc.pts = 1024 lxc.cap.drop = sys_module mac_admin mac_override sys_time lxc.mount.auto = cgroup:mixed proc:mixed sys:mixed lxc.mount.entry = /etc/rc.d etc/rc.d none ro,bind 0 0 lxc.mount.entry = /etc/ssl/certs etc/ssl/certs none ro,bind 0 0 lxc.mount.entry = /dev dev none ro,bind 0 0 lxc.mount.entry = /run run none ro,bind 0 0 lxc.mount.entry = /bin bin none ro,bind 0 0 lxc.mount.entry = /sbin sbin none ro,bind 0 0 lxc.mount.entry = /usr usr none ro,bind 0 0 lxc.mount.entry = /lib lib none ro,bind 0 0 lxc.mount.entry = /lib64 lib64 none ro,bind 0 0 lxc.mount.entry = /var/lib/lxc/test01/init sbin/init none ro,bind 0 0
作成するとこんな感じに。
$ sudo lxc-start -n test01 $ sudo lxc-ls -f test01 NAME STATE IPV4 IPV6 GROUPS AUTOSTART ----------------------------------------------------- test01 RUNNING 10.0.100.41 - - NO $ pstree :(略) |-lxc-start---init.lxc-+-bash | `-dhclient :(略) $ sudo lxc-attach -n test01 -- ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 17272 596 ? S 11:28 0:00 /usr/sbin/init.lxc -- /bin/bash root 18 0.0 0.0 18984 6852 ? Ss 11:28 0:00 /usr/sbin/dhclient eth0 -cf /dhclient.conf -v root 19 100 0.0 20264 3144 ? R 11:28 12:00 /bin/bash root 21 0.0 0.0 16612 2624 ? R+ 11:40 0:00 ps aux
起動してますね。コンテナ内は bash と dhclient が動いています。
コンテナ内のマウントの様子を見てみると
$ sudo lxc-attach -n test01 -- cat /proc/mounts :(略) /dev/root /etc/rc.d ext4 ro,relatime,data=ordered 0 0 /dev/root /etc/ssl/certs ext4 ro,relatime,data=ordered 0 0 /dev /dev tmpfs ro,relatime,mode=755 0 0 /dev/root /run ext4 ro,relatime,data=ordered 0 0 /dev/root /bin ext4 ro,relatime,data=ordered 0 0 /dev/root /sbin ext4 ro,relatime,data=ordered 0 0 /dev/root /usr ext4 ro,relatime,data=ordered 0 0 /dev/root /lib ext4 ro,relatime,data=ordered 0 0 /dev/root /lib64 ext4 ro,relatime,data=ordered 0 0 /dev/mapper/LXCVG01-LXCLV01 /sbin/init btrfs ro,relatime,space_cache 0 0 :(略)
lxc.mount.entry で設定した辺りは上記でしょうかね。
ruby-lxc を使って同じようなことをやる
LXC には ruby-lxc というものがあって、これでスクリプトを書けば同じようなことが比較的簡単にできます。これをやるのが
です。シャレで作っただけなのでこれを使おうと思わないでください。^^;
こっちは --bind みたいなオプションも未実装なので使えないと思います。コンセプト作と思ってください。(ruby-lxc を使ってみたかっただけ)
$ sudo ruby lxcing /bin/bash
まとめ
延々とわけのわからないことを書きましたが、何が言いたいかというと、LXC お手軽だからもっとみんな使いましょう、ってことです。
おまけ
LXC 使っちゃうとまあ色々プロセス起動したり、ファイルシステム色々扱ったりするので、声を大にして「軽いぞ!!」とは言えない気もするのですが、libcontainer とか libct とか使ったら bind mount して気軽に隔離環境作るプログラムってすぐ作れないかな? 誰か作るといいですね。