CentOS6 で LXC を使ってみる

下記の記事で Docker というものを知って少し気になったのですが、Docker を試してみる前に LXC がどんなものなのか試してみたほうがいいかなーと思ったので、手元の CentOS6 で使ってみました。

他のブログやWikiから切り貼りしただけですが、自分で見返したときに意味がわかるようにそれなりに説明も書きました。

参考にしたサイト

前提

  • CentOS 6.4 を Base パッケージグループのみでセットアップ
  • IPv6 は無効にしています
  • SELinux は無効にしています

LXC のインストールとホストの設定

epel と rpmforge を追加

rpmforge に lxc の rpm があるようなので rpmforge を追加します。

$ yum localinstall -y http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm

また、lxc-templates が依存している debootstrap が epel にあるので、これも追加します。

$ yum localinstall -y http://ftp-srv2.kddilabs.jp/Linux/distributions/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm

どちらもデフォルトで無効にしておきます。

$ sed -i.bak '/^enabled/c enabled=0' /etc/yum.repos.d/epel.repo
$ sed -i.bak '/^enabled/c enabled=0' /etc/yum.repos.d/rpmforge.repo

LXC をインストール

yum で LXC をインストールします。

$ yum --enablerepo=epel,rpmforge -y install lxc lxc-templates lxc-doc lxc-libs

ブリッジ作成

ホスト~ゲスト間のためのブリッジを作成します。NAT を使うようにするので実 I/F には繋ぎません。

$ cat > /etc/sysconfig/network-scripts/ifcfg-lxcbr0 <<EOS
DEVICE=lxcbr0
ONBOOT=yes
TYPE=Bridge
BOOTPROTO=none
IPADDR=10.12.128.1
PREFIX=24
DEFROUTE=no
EOS

$ ifup lxcbr0

cgroup をマウントします。

$ cat >> /etc/fstab <<EOS
cgroup                  /cgroup                 cgroup  defaults        0 0
EOS

$ mkdir -p /cgroup
$ mount -a

dnsmasq インストール

ゲストの IP を DHCP で割り当てるために dnsmasq をインストールします。固定で割り当てるなら必要ありません。

$ yum install -y dnsmasq
$ mv /etc/dnsmasq.conf /etc/dnsmasq.conf.orig

$ cat > /etc/dnsmasq.conf <<EOS
domain-needed
bogus-priv
interface=lxcbr0
listen-address=127.0.0.1
listen-address=10.12.128.1
expand-hosts
domain=lxc
dhcp-range=10.12.128.100,10.12.128.200,1h
EOS

$ service dnsmasq start
$ chkconfig dnsmasq on

IP Forwarding と NAT

ゲスト→ホスト で NAT するために IP Forwarding を有効にして iptables で NAT を設定します。 ホストの実 I/F が DHCP だったので MASQUERADE です。

$ sed -i.bak '/^net\.ipv4\.ip_forward/c net.ipv4.ip_forward = 1' /etc/sysctl.conf
$ sysctl -p

$ service iptables start
$ chkconfig iptables on

$ iptables -t nat -A POSTROUTING -s 10.12.128.0/24 -o eth0 -j MASQUERADE

$ service iptables save

ゲストの rootfs 作成

ゲストの rootfs を作成します。

作業用のディレクトリとして /t を使います。

$ mkdir /t
$ cd /t

chroot で yum を動かすために必要な最小限のパッケージをインストールします。

  • --installroot=/t で /t をルートとしてインストールします
  • --releasever=6 がないと $releasever が未定義 とか言われてエラーになります
$ yum --installroot=/t --releasever=6 -y install centos-release rootfiles yum

resolv.conf をコピーします。

$ cp /etc/resolv.conf /t/etc/

chroot します。

$ chroot /t

デバイスファイルを作成します。

$ rm -f /dev/null
$ mknod -m 666 /dev/null c 1 3
$ mknod -m 666 /dev/zero c 1 5
$ mknod -m 666 /dev/urandom c 1 9
$ ln -s /dev/urandom /dev/random
$ mknod -m 600 /dev/console c 5 1
$ mknod -m 660 /dev/tty1 c 4 1
$ chown root:tty /dev/tty1

$ mkdir -p /dev/shm
$ chmod 1777 /dev/shm
$ mkdir -p /dev/pts
$ chmod 755 /dev/pts

その他に必要そうなパッケージをインストールします。

$ yum -y install dhclient passwd openssh-server

/etc/sysconfig/network を作ります。

$ cat > /etc/sysconfig/network <<EOS
NETWORKING=yes
HOSTNAME=localhost
EOS

I/F 設定を作ります。

$ cat > /etc/sysconfig/network-scripts/ifcfg-eth0 <<EOS
DEVICE=eth0
ONBOOT=yes
TYPE=Ethernet
BOOTPROTO=dhcp
DEFROUTE=yes
PEERDNS=yes
PEERNTP=no
EOS

/etc/fstab を作ります。これはコンテナの起動時にマウントされます。

$ cat > /etc/fstab <<EOS
/dev/root               /                       rootfs   defaults        0 0
tmpfs                   /dev/shm                tmpfs    nosuid,nodev    0 0
EOS

lxc-sysinit.conf を作ります。コンテナの起動時に init から upstart で実行されます。

$ cat > /etc/init/lxc-sysinit.conf <<EOS
start on startup
env container
pre-start script
        if [ "x$container" != "xlxc" -a "x$container" != "xlibvirt" ]; then
                stop;
        fi
        telinit 3
        initctl start tty TTY=console
        exit 0;
end script
EOS

root のパスワードを設定します。

$ passwd

udev-post はたぶん不要なので off にします。

$ chkconfig udev-post off

chroot を抜けます。

$ exit

作成した rootfs をゲストの作成時に使いまわすために tar で固めます。

$ cd /t
$ tar cvzf /centos6-lxc-root.tgz .

ゲストの作成

ゲストのディレクトリを作成します。この位置に作成すれば lxc-create しなくても認識されます。

$ mkdir -p /var/lib/lxc/vm01/rootfs

rootfs のアーカイブを展開します。

$ cd /var/lib/lxc/vm01/rootfs
$ tar xvzf /centos6-lxc-root.tgz --numeric-owner

lxc の config を作成します。cgroup でリソース制限ができるようですがとりあえず必要最小限にします。

$ cat > /var/lib/lxc/vm01/config <<EOS
lxc.utsname = vm01
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = lxcbr0
lxc.network.name = eth0
lxc.network.veth.pair = veth-vm01
lxc.tty = 6
lxc.pts = 1024
lxc.rootfs = /var/lib/lxc/vm01/rootfs
lxc.mount  = /var/lib/lxc/vm01/fstab
lxc.cap.drop = sys_module mac_admin
EOS

fstab を作成します。これはたぶんゲストの init の前の chroot の前にマウントされます。

$ cat > /var/lib/lxc/vm01/fstab <<EOS
proc            /var/lib/lxc/vm01/rootfs/proc           proc    nodev,noexec,nosuid     0 0
sysfs           /var/lib/lxc/vm01/rootfs/sys            sysfs   defaults                0 0
EOS

ゲストの起動

ゲストの準備はできたので起動してみます。-d はデーモンとして起動するオプションです。 -o でログの出力先の指定、-l でログレベルの指定もできます。

$ lxc-start -n vm01 -d

ゲストのコンソールに接続します。

$ lxc-console -n vm01

ログインのプロンプトが表示されるので、↑の方で設定した root のパスワードでログインします。

コンソールからの切断は Ctrl+a → q です。

SSH で接続する

ホストの dnsmasq が DHCP でゲストに割り当てた IP アドレスを確認します。

$ cat /var/lib/dnsmasq/dnsmasq.leases

あるいは messages から探します。

$ grep dnsmasq-dhcp /var/log/messages

SSH でゲストにログインします。

$ ssh root@10.12.128.197

ゲストの停止

$ lxc-stop -n vm01

疑問点

  • lxc の config の lxc.mount がなくでも動作したけど必要?
    • proc や sysfs はなくてもマウントされている
    • rootfs 以外のホストのディレクトリをゲストに見せたいときに使うのでは?
  • ゲストの中の fstab がなくても動作したけど必要?
    • rootfs はなくてもマウントされている
    • tmpfs もなくてもマウントされている
      • しかもゲストの中の fstab に書いていると2重にマウントされているように見える
  • lxc-start -n vm01 としてもブートのメッセージが見えない
    • lxc-sysinit.conf を弄ると表示されるようになった
    • が、コンソールにログインプロンプトが表示されなくなった
  • lxc-stop -n vm01 で止めると次回起動時にネットワークとかが自動で始動しない?
    • /var/lock/subsys/ にいろいろ残るため?
    • lxc-sysinit.conf で消し去る?