2013年3月21日木曜日

LXCにArchLinuxを入れる

Arch Linux上のLXCにArch Linuxを入れ、systemdとsshが正しく動作するか試し てみる。 大まかな流れは、
  1. ネットワーク設定
    • ブリッジインターフェースの作成
    • IP Masqueradeの設定
  2. コンテナの作成
    • コンテナ内システムのbootstrap
    • コンテナ内の設定
    • コンテナ設定ファイルの作成
  3. コンテナの起動と終了
となる。
完成時のネットワーク構成は、以下の図のようになる。

ホスト側ブリッジインターフェースの設定

LXCのvethネットワークを束ねるブリッジインターフェース(br0)を作成する。 ブリッジインターフェースの作成とアドレスの割当にはipコマンドを用いる。
miku@host% sudo ip link add br0 type bridge
miku@host% sudo ip link set br0 up
miku@host% sudo ip address add 10.3.93.1/24 dev br0
毎度手動でインターフェース設定を行うのは面倒なので、netcfgの設定を行っ ておく。まずは、/etc/network.d/examples/bridgeを参考に /etc/network.d/bridge0を記述する。
INTERFACE="br0"
CONNECTION="bridge"
DESCRIPTION="Hatsune Bridge connection"
BRIDGE_INTERFACES=""
IP="static"
ADDR="10.3.93.1"
NETMASK="24"
最後に、systemctlでnetcfg@bridge0がシステム起動時に実行されるよう設定 する。
miku@host% sudo systemctl enable netcfg@bridge0.service
一時的に手動でnetcfgを起動することもできる。
miku@host% sudo systemctl start netcfg@bridge0.service

IP Masqueradeの設定

LXCコンテナ側から外部ネットワークにアクセスできるよう、IP Masqueradeを 設定する。まず、IP Forwardingを有効である必要があるため、 /etc/sysctl.confのnet.ipv4.ip_forwardを1に設定する。
net.ipv4.ip_forward = 1
手動で一時的に有効にするには、"sudo sysctl net.ipv4.ip_forward=1"でよ い。
次に、iptablesにて10.3.93.0/24から外部ネットワークに接続されたネットワー クインターフェース(enp2s0)へのIP Masqueradeを設定する。
miku@host% sudo iptables -t nat -A POSTROUTING \
> -s 10.3.93.0/24 -o enp2s0 -j MASQUERADE
この時点のiptablesの状態をiptables-saveコマンドでdumpし、それをそのま まiptablesの恒久的なルールとして利用する。 このルールファイルを置くべきパスは、/etc/conf.d/iptablesに "IPTABLES_CONF=/etc/iptables/iptables.rules"として定義されている。
miku@host% sudo sh -c 'iptables-save > /etc/iptables/iptables.rules'
最後に、システム起動時にこのルールが適用されるようにsystemdを設定する。
miku@host% sudo systemctl enable iptables.service

bootstrap

Arch Linuxのrootfsの構築は、Arch LinuxのLiveCDからインストールする際と 同様にarch-install-scriptsのpacstrapコマンドを用いる。合わせて、lxcパッ ケージとiproute2パッケージを導入しておく。
miku@host% sudo pacman -S lxc arch-install-scripts iproute2
/lxc/arch/rootfs以下に環境を作成する場合の操作は以下のようになる。 Arch LinuxのLXCテンプレートも存在するのだが、Arch Linux側の仕様がよく 変わり使い物にならない(すぐ使い物にならなくなる)ため、pacstrapを直接利 用する。
miku@host% sudo mkdir -m 0755 /var/lib/lxc/arch/rootfs
miku@host% sudo pacstrap -i -d /var/lib/lxc/arch/rootfs base openssh
baseパッケージグループを導入する際には、カーネルパッケージ等LXCコンテ ナ内に必要ないパッケージも多数含まれるので、必要に応じて除外する。
:: There are 52 members in group base:
:: Repository core
   1) bash  2) bzip2  3) coreutils  4) cronie  5) cryptsetup  6) device-mapper  7) dhcpcd  8) diffutils
   9) e2fsprogs  10) file  11) filesystem  12) findutils  13) gawk  14) gcc-libs  15) gettext  16) glibc
   17) grep  18) gzip  19) heirloom-mailx  20) inetutils  21) iproute2  22) iputils  23) jfsutils  24) less
   25) licenses  26) linux  27) logrotate  28) lvm2  29) man-db  30) man-pages  31) mdadm  32) nano  33) netcfg
   34) pacman  35) pciutils  36) pcmciautils  37) perl  38) ppp  39) procps-ng  40) psmisc  41) reiserfsprogs
   42) sed  43) shadow  44) sysfsutils  45) systemd-sysvcompat  46) tar  47) texinfo  48) usbutils
   49) util-linux  50) vi  51) which  52) xfsprogs
LXCパッケージのデフォルトでは各コンテナは/var/lib/lxc以下に置かれるの だが、パスが長くて面倒だという場合は以下のようにシンボリックリンクを張っ ておく。(LXC側で設定を変更することもできるが、lxcパッケージ側で /var/lib/lxcにハードコートされているものが存在するようでエラーとなるた め)
miku@host% sudo ln -s /var/lib/lxc /lxc

コンテナ内の設定

コンテナを起動しssh経由にてログインする際に必要な設定を行う。 sshdの有効化とユーザアカウントの設定が必須で、必要に応じてロケール等の 設定を行う。
miku@host% sudo chroot /var/lib/lxc/arch/rootfs /bin/bash
root@host(chroot)# ln -s /usr/lib/systemd/system/sshd.service \
> /etc/systemd/system/multi-user.target.wants/sshd.service 
root@host(chroot)# passwd
Enter new UNIX password: 
Retype new UNIX password: 
passwd: password updated successfully
root@host(chroot)# groupadd -g 3939 miku
root@host(chroot)# useradd -g miku -u 3939 -s /bin/bash -m miku
root@host(chroot)# passwd miku
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
root@host(chroot)# exit
デバイスノードの管理はsystemd-udevdが行うため、後述するLXCのconfigでの 許可ルール設定のみ注意すればよい。また、/tmpのtmpfsや/devのdevtmpfs、 /sysのsysfs、/procのprocfs等もsystemdが自動でマウントを行うため、LXCの configやfstabへの記述は特に必要ない。

コンテナ設定ファイルの作成

今回設定するコンテナの設定ファイルは、"/var/lib/lxc/arch/config"である。 ここでは、コンテナに割り当てられるネットワークとファイルシステム、デバ イスのルールについて定義を行う。 設定ファイルの詳細については、lxc.conf(5)や/usr/share/doc/lxc/examples 以下のファイル、デバイス番号の一覧は以下のドキュメントを参照。 http://www.kernel.org/pub/linux/docs/device-list/devices.txt
# ホスト名とネットワークの設定
lxc.utsname                     = arch
lxc.network.type                = veth
lxc.network.name                = eth0
lxc.network.flags               = up
lxc.network.link                = br0
lxc.network.ipv4                = 10.3.93.11/24
lxc.network.ipv4.gateway        = 10.3.93.1


# ファイルシステムの設定
lxc.rootfs      = /var/lib/lxc/arch/rootfs


# デバイスの設定
lxc.pts                         = 1024
lxc.tty                         = 4

# deny all devices
lxc.cgroup.devices.deny         = a

# /dev/tty0..3
lxc.cgroup.devices.allow        = c 4:0 rwm
lxc.cgroup.devices.allow        = c 4:1 rwm
lxc.cgroup.devices.allow        = c 4:2 rwm
lxc.cgroup.devices.allow        = c 4:3 rwm

# /dev/tty
lxc.cgroup.devices.allow        = c 5:0 rwm
# /dev/console
lxc.cgroup.devices.allow        = c 5:1 rwm
# /dev/ptmx
lxc.cgroup.devices.allow        = c 5:2 rwm

# /dev/null
lxc.cgroup.devices.allow        = c 1:3 rwm
# /dev/zero
lxc.cgroup.devices.allow        = c 1:5 rwm
# /dev/random
lxc.cgroup.devices.allow        = c 1:8 rwm
# /dev/urandom
lxc.cgroup.devices.allow        = c 1:9 rwm

# /dev/pts/*
lxc.cgroup.devices.allow        = c 136:* rwm
# /dev/rtc
lxc.cgroup.devices.allow        = c 254:0 rwm
最終的に許可されたデバイスの一覧は "/sys/fs/cgroup/devices/lxc/コンテナ名/devices.list" から参照できる。

コンテナ内のArch Linuxの起動と終了

コンテナ内のinitの起動にはlxc-startを用いる。このシステムの場合はコン テナ名がarch、コマンドは/usr/lib/systemd/systemdとなる。
早速起動した所、pivot_root(2)が失敗する問題に遭遇した。
miku@host% sudo lxc-start -n arch -- /usr/lib/systemd/systemd
lxc-start: Invalid argument - pivot_root syscall failed
lxc-start: failed to setup pivot root
lxc-start: failed to set rootfs for 'arch'
lxc-start: failed to setup the container
lxc-start: invalid sequence number 1. expected 2
lxc-start: failed to spawn 'arch'
これはsystemdとLXCの組み合わせで発生する問題で、/以下をprivate mountす ることで解決できるようだ。
miku@host% sudo mount --make-rprivate /
このprivate mountの詳細については、以下のページが詳しい。
再度起動した所、今度は/dev/ptsが存在しないとのエラーが発生。どうや らLXC側で/dev/ptsにdevptsをマウントしようとして失敗しているようなので、 /lxc/arch/dev/ptsを作成しておく。
miku@host% sudo lxc-start -n arch -- /usr/lib/systemd/systemd
lxc-start: No such file or directory - failed to mount a new instance of '/dev/pts'
lxc-start: failed to setup the new pts instance
lxc-start: failed to setup the container
lxc-start: invalid sequence number 1. expected 2
lxc-start: failed to spawn 'arch'
miku@host% sudo mkdir -m 755 /var/lib/lxc/arch/dev/pts
以上2つの問題を解決し、ようやくsystemdとsshdが起動した。
miku@host% sudo lxc-start -n arch -- /usr/lib/systemd/systemd
miku@host% lxc-ps -n arch
CONTAINER   PID TTY          TIME CMD
arch       1113 ?        00:00:00 systemd
arch       1124 ?        00:00:00 systemd-udevd
arch       1132 ?        00:00:00 systemd-journal
arch       1243 ?        00:00:00 sshd
arch       1245 ?        00:00:00 dbus-daemon
arch       1246 ?        00:00:00 systemd-logind
arch       1253 ?        00:00:00 agetty
arch       1254 tty1     00:00:00 agetty
デーモンとして動作させる場合は、以下のように-dオプションとログ出力オプ ションを設定し起動する。
miku@host% sudo lxc-start -n arch  -d \
> --logfile=/var/lib/lxc/arch/lxc.log \
> --console=/var/lib/lxc/arch/console.log  -- /usr/lib/systemd/systemd
LXCコンテナを終了する場合は、lxc-stopコマンドを利用する。
miku@host% sudo lxc-stop -n arch
Arch Linux上のLXCコンテナ内でArch Linuxを動かし、基本的な操作(起動と終了)が 行えることが確認できた。

その他の問題

今回作成した環境には、lxc-consoleにてコンソールにアクセスできない問題 がある。LXCが想定する/dev以下の扱いとsystemd-udevdの挙動の問題なように 見受けられるので、そのあたりを探っておこうと思う。 (LXC側で掴んだデバイスノードと別に/devにmountされたdevtmpfs上のデバイ スノードをsystemd側でgettyしているのが原因?)

0 件のコメント:

コメントを投稿