CentOS 7: LXD/LXCでコンテナを立ち上げる

CentOS 7はLXC 1.x系です。LXD/LXCはLXC 2.x系です。1.x系と2.x系ではコマンドが異なります。libvirtでは将来的にLXCがサポートがされなくなります。そこでこの記事ではlibvirt + LXC 1.x系ではなく、LXD/LXCをCentOS 7に導入する手<p>&nbsp;</p>順と制限事項を記載します。

1 制限事項

ここで記載する手順ではUbuntu 16.04でLXD/LXCを動かす場合と比べて、いくつかの制限事項があります。

  • lxd-bridge、lxcfsは含まれていません。
  • 最初に一度、コンテナで以下のコマンドを実行しないとコンテナ内でshutdown/rebootできません。コンテナ外からもlxc stopとlxc restartができません。以下のコマンドを実行しない場合、lxc stop –forceやlxc restart –forceが必須になります。
# find /lib/systemd/system -maxdepth 1 \
-type f -exec sed -e 's/umount\.target//g' -i {} \;
# systemctl --system daemon-reload

1.1 shutdown/rebootできない問題の詳細

本問題はgetrandomシステムコールが実装されていない場合に発生します。

また、本問題は以下のメッセージが出力されますが、/dev/initctlに関する問題ではありません。systemdはreboot.targetが失敗した場合に、/dev/initctlの処理を実行しているだけです。

# reboot
Warning! D-Bus connection terminated.
Failed to wait for response: Connection reset by peer
Failed to open /dev/initctl: No such device or address
Failed to talk to init daemon

詳細は以下の通りです。

  • LXD/LXCは/dev/urandomをmount + MS_BINDでコンテナに提供します。
  • コンテナ内にて、systemdはgetrandomシステムコールがない場合に/dev/urandomを使って乱数を生成します。
  • コンテナ内にて、shutdown/rebootコマンドの延長で呼ばれるumount.targetがdevtmpfsの/dev/urandomをアンマウントします。
  • コンテナ内にて、umount.targetの後でsystemdが乱数の生成を試みますが、getrandomシステムコールも/dev/urandomもない為にエラー終了します。

コンテナ内でアンマウントできるデバイスを提供するLXD/LXCが悪いのか、devtmpfsをすべてアンマウントするsystemdが悪いのかわかりかねますが、 systemd側で対応してくれそうです。

ただし、コンテナイメージ側の変更になる為、現行のコンテナイメージに普及するのにはだいぶ時間がかかりそうです。LXD/LXC側で対応できれば時間がかからないのですが。

2 LXD/LXCのインストール

こちらのページいくつかの手順が紹介されています。以下のスクリプトを実行することでLXD/LXCのインストールから初期化まで実行できます。

#!/bin/sh

USER_ADDED_TO_LXD_GROUP="${USER}"

# LXD/LXC uses lxc-xxx pakcage.
F=https://dl.fedoraproject.org/pub/fedora/linux/releases/25
L=${F}/Everything/source/tree/Packages/l
wget -q ${L}/lxc-2.0.5-1.fc25.src.rpm
sudo yum install -y epel-release rpmdevtools rpm-build graphviz
sudo yum-builddep -y lxc-2.0.5-1.fc25.src.rpm
rpmbuild --rebuild lxc-2.0.5-1.fc25.src.rpm

# Install package.
# shellcheck disable=SC2046
sudo yum localinstall -y \
     $(find ~/rpmbuild/RPMS -type f -a ! -name "*debuginfo*")

# Install LXD/LXC.
sudo adduser --system lxd --home /var/lib/lxd/ --shell /bin/false
sudo addgroup --system lxd
sudo mkdir -p /var/log/lxd
sudo chown root:lxd /var/log/lxd
sudo yum install -y git golang sqlite-devel dnsmasq squashfs-tools
export GOPATH=${HOME}/go
export PATH=${GOPATH}/bin/:${PATH}
go get -v -x -tags libsqlite3 \
   github.com/lxc/lxd/lxc \
   github.com/lxc/lxd/lxd
sudo cp "${GOPATH}"/bin/* /usr/bin/

# Create systemd service and socket.
sudo su -c '
cat <<EOF > /usr/lib/systemd/system/lxd.service
[Unit]
Description=LXD - main daemon
After=network.target
Requires=network.target lxd.socket
Documentation=man:lxd(1)

[Service]
EnvironmentFile=-/etc/environment
ExecStart=/usr/bin/lxd --group lxd --logfile=/var/log/lxd/lxd.log
ExecStartPost=/usr/bin/lxd waitready --timeout=600
KillMode=process
TimeoutStartSec=600
TimeoutStopSec=40
Restart=on-failure
LimitNOFILE=infinity
LimitNPROC=infinity

[Install]
Also=lxd.socket
EOF
'

sudo su -c '
cat <<EOF > /usr/lib/systemd/system/lxd.socket
[Unit]
Description=LXD - unix socket
Documentation=man:lxd(1)

[Socket]
ListenStream=/var/lib/lxd/unix.socket
SocketGroup=lxd
SocketMode=0660
Service=lxd.service

[Install]
WantedBy=sockets.target
EOF
'

# Run LXD for initialization.
sudo systemctl --system daemon-reload
sudo systemctl enable lxd
sudo systemctl start lxd

# Initialize LXD.
cat <<EOF | sudo lxd init
yes
default
dir
no
yes
yes
lxdbr0
auto
auto
EOF

# Running container needs user_namespace.enable=1.
sudo yum install -y grub2-tools
. /etc/default/grub
V="$GRUB_CMDLINE_LINUX user_namespace.enable=1"
sudo sed -e "s;^GRUB_CMDLINE_LINUX=.*;GRUB_CMDLINE_LINUX=\"$V\";g" \
-i /etc/default/grub
sudo grub2-mkconfig -o /boot/grub2/grub.cfg

# Add user to lxd for running lxc command without privilege.
sudo gpasswd -a "${USER_ADDED_TO_LXD_GROUP}" lxd

# Reboot.
sudo reboot

3 動作確認

最初に先ほどのコマンドを実行することでrebootできるようになります。

$ lxc launch ubuntu:16.04 ubuntu-1604
$ lxc exec ubuntu-1604 -- find /lib/systemd/system -maxdepth 1 \
-type f -exec sed -e 's/umount\.target//g' -i {} \;
$ lxc exec ubuntu-1604 -- systemctl --system daemon-reload
$ lxc exec ubuntu-1604 reboot # lxc restart ubuntu-1604 works too.
$ uname -a
Linux centos-7 3.10.0-514.10.2.el7.x86_64 #1 SMP Fri Mar 3 00:04:05
UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
$ lxc exec ubuntu-1604 -- uname -a
Linux ubuntu-1604 3.10.0-514.10.2.el7.x86_64 #1 SMP Fri Mar 3 00:04:05
UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

4 その他の設定

Ubuntu 16.04の場合と同様です。