Raspberry PiでLXC(Linux Container)
LXC(Linux Container)を初めて知ったのはつい最近のことで、”もぐてっく”さんの”Raspbian WheezyにLXCを導入してみた。”の記事を拝見した時です。
Intel系でLinuxの仮想化というともっぱらKVMやら何やらといったところがメジャーですが、ここは所詮非力なARM系であるところのRaspberry Piなので、お手軽に軽い仮想環境というのが魅力的でした。
どうお手軽で軽いかというと、ごく大雑把に言うと、基本的にchroot環境+αぐらいの仮想環境なので、CPUエミュレーションが要らない(ネイティブコードがそのまま走る)ので軽いといったところでしょうか。ちょうどRaspberry Piのメモリー容量が倍増されて512MBになったこともあり、さらに敷居は低くなったといえるでしょう。
というわけで、さっそくLXCの導入をしてみました。
※ただし、まだ”とりあえずできたよー”レベルなので、厳密にはさらに手直しをしなければいけませんが、それは今後続編としてUPできればなぁと思っています。
1.まずはカーネルの準備
LXCを使う場合、Linuxカーネルに以下の機能が含まれている必要があります。
- CONFIG_NAMESPACES
- CONFIG_CGROUPS
- CONFIG_DEVPTS_MULTIPLE_INSTANCES
- CONFIG_VETH
ですが、Raspbian "Wheezy"では一部含まれていません。
そこで、前に記事”How to:Raspberry Pi(Raspbian”Wheezy”)用にクロスコンパイル環境を構築する”にしたのとほぼ同じ手順で、.configはbootcカーネルのものをベース(CONFIG_VETHがモジュールになっていたのでカーネルに組み込みました)にして、LinuxカーネルのソースはGitHubのRaspberry公式の最新版(3.2.27)をgit cloneで引っ張ってきてクロスコンパイルしました。
※クロスコンパイル(armhf)したものを野良パッケージングしたものは近日中に公開予定です。 公開しました。
linux-image-3.2.27rpi-bootc+_2_armhf.deb (Google Drive上に置いてあります)
※あくまで野良ビルドですので、ご利用は自己責任にてお願い致します。このカーネルを用いることによるいかなる損害に関して私はその責を負いません。
2.ベースとなるRaspbian Wheezy(armhf版)環境を用意
これについては、Windows系、Mac系などなどで作り方が異なるので、適当にぐぐって最新版のイメージファイルをSDHCカードに書き込んで、ファームウェアのアップデートなどを行なって下さい。
3.カーネルの入れ替え
まだ、野良ビルドのパッケージを公開してませんが、名前はlinux-image-3.2.27rpi-bootc+_2_armhf.debですので、これを元に説明しますと、
dpkg -i linux-image-3.2.27rpi-bootc+_2_armhf.deb
cp -p /boot/kernel.img /boot/kernel.img.121211
(コピー後の名前はどうでもいいといえばどうでもいいので、適当につけて下さい)
cp -p /boot/vmlinuz-3.2.27rpi-bootc+ /boot/kernel.img
reboot
これで、無事立ち上がってきたら、
$ uname -a
などでバージョンを確認してみて下さい。
4.cgroupのmount
debian公式のLXC解説ページでは、/sys/fs/cgroupにmountしているので、
mount -t cgroup cgroup /sys/fs/cgroup
/etc/fstabに以下の行を追加
cgroup /sys/fs/cgroup cgroup defaults 0 0
でいいかと思います。
5.LXCなどのパッケージのインストール
LXC自体と、ホストとコンテナの間のネットワークブリッジのために以下のパッケージを導入します。
apt-get install lxc bridge-utils
コンテナの置き場所など聞かれますが、デフォルトでいいと思います。
6.LXCコンテナの作成
いよいよ、コンテナ(ゲスト側)の作成です。
LXCの場合、テンプレートというのが先に用意されています(/usr/share/lxc/templates/配下にあります)
基本的に、このテンプレートをそのまま使うか、一部変更して使うようです。今回はテンプレートをそのまま使ってみます。
この段階まできてチェックするのも何ですが、一応、LXC使えるよね?ということで、
lxc-checkconfig
というコマンドで、動作環境をチェックできます。上記の野良ビルドのカーネルでは全て"Enabled"でした。
ここでは、ホスト:Raspbian、ゲスト:Raspbian(コンテナ名は適当につければいいのですが、仮にplutoとします)でコンテナを作成してみます。
テンプレートはdebian用のものをそのまま使っちゃいます。
lxc-create -t debian -n pluto
すると、以下の項目を聞かれますので、こんな感じで答えていきます。
- Preseed file anyone? →デフォルト(空欄)
- Distribution →Debian GNU/Linux 7.0 "wheezy"
- Archives →オプションを全てOFF
- Mirror →http://mirrordirector.raspbian.org/raspbian/
- Archive Areas →デフォルト
- Packages →デフォルトか好みに合わせてその他の欄にもチェック(私は全部にチェックしときました)
- Root password →お好きなパスワードで
これが終わると、LXCコンテナの作成が始まります。Raspberry Piの場合非力なので、コンテナが出来上がるまで40~50分はかかりました。
あと、最後のほうでエラーがちょろっと出ますが、特に問題はありませんでした。
コンテナはデフォルトでは/var/lib/lxc/plutoに出来上がります。plutoの部分は皆さんがつけたコンテナ名になります。
7.最後の手直し
作成したコンテナ内に/dev/tty1~/dev/tty6が無いので(別途作ってもいいといえばいいのですが)、/var/lib/lxc/pluto/etc/inittab(いかにもchroot環境という感じですね)で、/dev/tty1~/dev/tty6の部分をコメントアウトして、
1:2345:respawn:/sbin/getty 38400 console
の行を追加します。
ネットワークブリッジの設定も必要なので、まずホスト側で、
brctl addbr br0
でブリッジインターフェースを作成します。
その後、/var/lib/lxc/pluto/config(LXCコンテナのコンフィギュレーションファイル)に以下の行を追加します(IPアドレスは環境に合わせてつけて下さい)
lxc.network.type = veth lxc.network.flags = up lxc.network.link = br0 lxc.network.name = eth0 lxc.network.ipv4 = 192.168.111.111/24
ちなみに、lxc.network.ipv4は最後の/24なり/28なりというのをつけ忘れないようにして下さい。
※確認はしていませんが、コンテナがIPアドレスをDHCPで取る設定にする場合には多分lxc.network.ipv4はいらないと思います。
後は、先ほど追加したbr0がrebootすると消えてしまうので、またまたもぐてっくさんの記事"/etc/interfacesでブリッジをセットアップする"を参考に、br0が起動時にIPアドレスが振られた状態で立ち上がるようにします。
auto lo br0 iface lo inet loopback iface br0 inet static pre-up /sbin/brctl addbr br0 pre-up /sbin/brctl addif br0 eth0 pre-up /sbin/ifconfig eth0 up bridge_ports eth0 brigde_fd 0 address 192.168.111.100 netmask 255.255.255.0 gateway 192.168.111.1 network 192.168.111.0 broadcast 192.168.111.255
※/etc/network/interfacesで設定する固定IPアドレスはホスト側のIPアドレスです(適宜IPアドレスは読み変えて下さい)。また、Raspbian ”Wheezy"ではbrctlは/sbin/brctlにあります。コンテナ側でDHCPでIPアドレスを取得する場合もたぶんこれでいけると思います(未検証)
※※自分はここでドツボにはまったのですが、interfacesの中にeth0に関する記述が残っているとうまくNICが立ち上がって来ませんのでご注意を。
※※※この方法以外にも設定方法があるので、お好きな方法でどうぞ。
※※※※ubuntuだとブリッジインターフェースまで面倒見てくれるようです。
7.LXCコンテナの起動
lxc-start -n pluto
これだけです。あとは、起動時にエラーやwarningが出ますが、それはおいおい起動スクリプトを直したり、configファイルを直したり、デバイスを作れば出なくなるはずです。(”とりあえず動いたよー”レベルなので勘弁して下さい)
終了時は、haltなりshutdown -h nowなどで普通のマシンと同様にすれば、initが子プロセスが無くなったと判定した時点でコンテナが終了し、ホスト側に制御が戻ってきます。どうしても落ちない場合には、lxc-stopあたりで無理やり落とすしか無いかもしれません。
最後に
今回LXCを動かしてみるために、もぐてっくさんのサイトが非常に参考になりました。ありがとうございます。
その他、参考にしたリンクをご紹介します。(他にもググりまくってますが・・・)
LXC Configure Debian Containers (リンク切れになっています)