CentOS 7: Run containers with LXD/LXC

CentOS 7 has LXC 1.x while LXD/LXC is 2.x. Commands are different between 1.x and 2.x. And libvirt will not support LXC 1.0. This article will describe installing LXD/LXC on CentOS 7.

1 Limitation

This way has limitation compared with running LXD/LXC on Ubuntu 16.04.

  • This way does not install lxd-bridge and lxcfs.
  • This way must run the following command. If not running the following command, cannot run shutdown/reboot command in container. And running lxc stop and lxc restart will be failed (need to use –force option).
# find /lib/systemd/system -maxdepth 1 \
-type f -exec sed -e 's/umount\.target//g' -i {} \;
# systemctl --system daemon-reload

1.1 Issue with shutdown/reboot

This issue happens on kernel which does not implement getrandom system call.

This issue outputs the following message, but this is not /dev/initctl issue. When reboot.target is failed, systemd will try /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

Detail is the following.

  • LXC/LXC provides /dev/urandom to container with using mount + MS_BIND.
  • In container, systemd will create random value with /dev/urandom if getrandom system call is not supported.
  • In container, umount.target called by shutdown/reboot command will umount /dev/urandom.
  • In container, after umount.target runs, systemd will create random value. But there are no getrandom system call and /dev/urandom. So systemd will be errored.

I do not know whether LXD/LXC that provides devices that can be unmounted in container is not good, or whether systemd which unmounts all devtmpfs is not good. But systemd will fix this issue.

2 Install LXD/LXC

This page introduces a way for installing LXD/LXC on CentOS 7. The following script will installing LXD/LXC and initialize it.

#!/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 Execution result

Running the previous command enables 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 Other stuff

It is the same with Ubuntu 16.04.