LXC
Content
External doc.
LXC is a userspace interface for the Linux kernel containment features. Through a powerful API and simple tools, it lets Linux users easily create and manage system or application containers.
LXC containers are often considered as something in the middle between a chroot and a full fledged virtual machine. The goal of LXC is to create an environment as close as possible to a standard Linux installation but without the need for a separate kernel.
source: linuxcontainers.org
Install
$ prt-get depinst lxc
Configure
To use unprivileged containers edit /etc/lxc/default.conf replace USERNAME with user name that will launch containers;
# Template used to create this container: /usr/share/lxc/templates/lxc-local # Parameters passed to the template: --fstree crux-3.5-x86_64-20190419-rootfs.tar.xz --metadata crux-3.5-x86_64-20190419-lxc.tar.xz # Template script checksum (SHA-1): c4910e305a7e8fc8bd5ce18d2254f36fac84a207 # For additional config options, please look at lxc.container.conf(5) # Uncomment the following line to support nesting containers: #lxc.include = /usr/share/lxc/config/nesting.conf # (Be aware this has security implications) # Uncomment to create unprivileged containers # Network configuration # Distribution configuration lxc.include = /usr/share/lxc/config/common.conf lxc.include = /usr/share/lxc/config/userns.conf lxc.arch = x86_64 lxc.tty.max = 6 # Container specific configuration lxc.idmap = u 0 100000 65536 lxc.idmap = g 0 100000 65536 lxcuser veth lxcbr0 10 lxc.rootfs.path = dir:/srv/lxc/rootfs lxc.uts.name = LXC_NAME # Network configuration lxc.net.0.link = lxcbr0 lxc.net.0.type = veth lxc.net.0.flags = up lxc.net.0.name = eth0 lxc.net.0.hwaddr = 00:16:3e:00:00:00 # uncomment the next two lines if static IP addresses are needed # leaving these commented will imply DHCP networking # #lxc.net.0.ipv4.address = 10.0.0.20/8 #lxc.net.0.ipv4.gateway = 10.0.0.1 # populate /dev lxc.autodev = 1 lxc.mount.entry = none dev/shm tmpfs nodev,nosuid,noexec,mode=1777,create=dir 0 0
Edit /etc/lxc/lxc-usernet and add;
lxcuser veth lxcbr0 10
Check if kernel supports user namespaces;
$ grep CONFIG_USER_NS /boot/config-4.19.116-gnu CONFIG_USER_NS=y
Allow normal users to run unprivileged containers;
# sysctl kernel.unprivileged_userns_clone=1
Edit /etc/sysctl.conf and add following to make it permanent;
kernel.unprivileged_userns_clone = 1
Create /etc/subuid with root and desired user that will launch containers, in this case we will create and use lxcuser;
lxcuser:100000:65536
And /etc/subgid;
lxcuser:100000:65536
Create user;
# useradd -s /bin/bash -c "lxc unprivileged user" -U -G users -d /srv/lxc -m lxcuser
Set password;
# passwd lxcuser
Mount cgroups filesystems;
Check this script cgroupfs-mount the easy way but not correct way is to;
# mount -t cgroup cgroup /sys/fs/cgroup
Add to /etc/fstab;
cgroup /sys/fs/cgroup cgroup defaults
Run lxc-cgroups rc script and add it to /etc/rc.conf;
# sh /etc/rc.d/lxc-cgroups
Check if there is missing requirements;
$ lxc-checkconfig
To manually setup network add bridge;
# ip link add name lxcbr0 type bridge # ip link set dev lxcbr0 up # ip link set enp8s0 master lxcbr0
This steps are not enough to allow network to containers but will allow to run a simple test. Check Qemu network, change example step described to fit desired configuration.
Setup the bridge, dnsmasq is required, run script rc lxc-net
# sh /etc/rc.d/lxc-net
Add above script to /etc/rc.conf.
Create image
Pacman provides script that creates images with given iso and tarballs ready to use at nullvoid.de. To create your own image download and mount iso on a directory then install packages into rootfs.
$ mkdir -p ~/lxc-image/iso $ cd ~/lxc-image/
Download setup-iso.sh scrit and execute it;
$ chmod +x setup-iso.sh $ ./setup-iso.sh -r ~/lxc-image/iso -d $ sudo ./setup-iso.sh -r ~/lxc-image/iso -m /media
Install core packages into rootfs directory, download install-core.sh script and execute it;
$ sudo ./install-core.sh -r ~/lxc-image/rootfs -p /media/crux -o
Create create-container.sh, this script is based on pacman lxc.sh script with few changes to match the steps described above.
#!/bin/sh set -e if test $(id -u) -ne 0 then echo 'This must be run as root.' exit 1 fi DIR="$(pwd)" ARCH="x86_64" RELEASE="$(cat /media/crux-media)" VERSION="${RELEASE%-*}" DATE="${RELEASE#*-}" # Insert hostname templates sed -i -e '/HOSTNAME=/cHOSTNAME=LXC_NAME' rootfs/etc/rc.conf sed -i -e 's;localhost.*;& LXC_NAME;' rootfs/etc/hosts # Fix default networking cat > rootfs/etc/rc.d/net << 'EOF' #!/bin/sh # # /etc/rc.d/net: start/stop network interface # case $1 in start) /sbin/dhcpcd -4 eth0 ;; stop) /sbin/dhcpcd -x eth0 ;; restart) $0 stop $0 start ;; *) echo "Usage: $0 [start|stop|restart]" ;; esac EOF # Remove noclear from agettys # Replace linux with xterm on agettys # Remove serial console # Remove existing powerfail entries # Add an entry to allow LXC/LXD to shutdown the container sed -i \ -e 's;--noclear ;;' \ -e 's;linux;xterm;' \ -e '/s1:2:/d' \ -e '/:powerfail:/d' \ -e '/ctrlaltdel/cpf::powerfail:/sbin/telinit 0' \ rootfs/etc/inittab # Disable klogd in containers as it doesn't work sed -i -e '/KLOG/d' -e 's;and klog ;;' rootfs/etc/rc.d/sysklogd # Export a default LANG sed -i -e '/LESS=/iexport LANG="C"' rootfs/etc/profile # Disable startup functionality that doesn't work in a container sed -i \ -e '/# Start udev/,/^ *$/d' \ -e '/# Create device-mapper device nodes and scan for LVM volume groups/,/^ *$/d' \ -e '/# Mount root read-only/,/^ *$/d' \ -e '/-f \/forcefsck/,/^ *$/d' \ -e '/# Check filesystems/,/^ *$/d' \ -e '/# Mount local filesystems/,/^ *$/d' \ -e '/# Activate swap/,/^ *$/d' \ -e '/hwclock/d' \ -e '/# Load console font/,/^ *$/d' \ -e '/# Load console keymap/,/^ *$/d' \ -e '/# Screen blanks after 15 minutes idle time/,/^ *$/d' \ -e '/# Run module initialization script/,/^ *$/d' \ rootfs/etc/rc # Disable shutdown functionality that doesn't work in a container sed -i \ -e '/# Set linefeed mode to avoid staircase effect/,/^ *$/d' \ -e '/# Save system clock/,/^ *$/d' \ -e '/# Turn off swap/,/^ *$/d' \ -e '/# Unmount file systems/,/^ *$/d' \ -e '/# Remount root filesystem read-only/,/^ *$/d' \ rootfs/etc/rc.shutdown # Disable certain functionality in single user login sed -i \ -e '/# Start udev/,/^ *$/d' \ rootfs/etc/rc.single # Remove variables that are not used in containers sed -i -e '/FONT=/d' -e '/KEYMAP=/d' rootfs/etc/rc.conf # Create the LXC metadata tarball cat > config << EOF lxc.include = LXC_TEMPLATE_CONFIG/common.conf lxc.arch = $ARCH lxc.tty.max = 6 EOF cat > excludes << 'EOF' dev/* EOF cat > config-user << EOF lxc.include = LXC_TEMPLATE_CONFIG/common.conf lxc.include = LXC_TEMPLATE_CONFIG/userns.conf lxc.arch = $ARCH lxc.tty.max = 6 EOF cat > excludes-user << 'EOF' dev/* EOF cat > templates << 'EOF' /etc/rc.conf /etc/hosts EOF cat > create-message << EOF You just created a CRUX $VERSION $ARCH ($DATE) container. EOF tar -c -f - config excludes config-user excludes-user templates create-message | xz -9 > "$DIR/crux-$VERSION-$ARCH-$DATE-lxc.tar.xz" rm -rf config config-user create-message excludes-user templates # Create the LXD metadata tarball mkdir -p templates sed -e 's;LXC_NAME;{{ container.name }};' rootfs/etc/rc.conf > templates/rc.conf.tpl sed -e 's;LXC_NAME;{{ container.name }};' rootfs/etc/hosts > templates/hosts.tpl sed -e '/c1:2:/,/^ *$/c{% for i in config_get("user.ttys","")|make_list %}c{{ i }}:2:respawn:/sbin/agetty 38400 tty{{ i }} xterm\ {% endfor %}' rootfs/etc/inittab > templates/inittab.tpl cat > metadata.yaml << EOF architecture: $ARCH creation_date: $(date +%s) properties: architecture: $ARCH description: CRUX $VERSION $ARCH ($DATE) name: crux-$VERSION-$ARCH-$DATE os: crux release: "$VERSION" serial: "$DATE" templates: /etc/rc.conf: when: - create - copy create_only: false template: rc.conf.tpl /etc/hosts: when: - create - copy create_only: false template: hosts.tpl /etc/inittab: when: - create - copy create_only: false template: inittab.tpl EOF tar -c -f - templates/ metadata.yaml | xz -9 > "$DIR/crux-$VERSION-$ARCH-$DATE-lxd.tar.xz" #rm -rf templates/ metadata.yaml # Create the root tarball (cd rootfs; tar -c -f - *) | xz -9 > "$DIR/crux-$VERSION-$ARCH-$DATE-rootfs.tar.xz" #rm -rf rootfs
Run script;
$ chmod +x create-container.sh $ sudo ./create-container.sh
Output of above script creates three archives;
crux-3.5-x86_64-20190611-lxc.tar.xz crux-3.5-x86_64-20190611-lxd.tar.xz crux-3.5-x86_64-20190611-rootfs.tar.xz
Manage images
First become the user previoulsy created;
$ su - lxcuser
Create configuration file;
$ mkdir -p ~/.config/lxc $ cp /etc/lxc/default.conf ~/.config/lxc/
From the man page;
"lxc-create creates a system object where is stored the configuration information and where can be stored user information. The identifier name is used to specify the container to be used with the different lxc commands."
At the time of this writing to directories are created; /var/lib/lxc/name_of_container and /usr/var/lib/lxc/name_of_container. Man page says; "The object is a directory created in /usr/var/lib/lxc and identified by its name."
$ lxc-create -n test -t local -- --metadata crux-3.5-x86_64-20190611-lxc.tar.xz --fstree crux-3.5-x86_64-20190611-rootfs.tar.xz Unpacking the rootfs --- You just created a CRUX 3.5 x86_64 (20190611) container.
To destroy a container run;
$ lxc-destroy -n container_name -s
Using containers
Become user created to run containers;
$ su - lxcuser
Start container in daemon mode, this will run it in background;
$ lxc-start -n test -d
When necessary to run in foreground to end up with a login shell use -F, this is useful when doing debugging;
$ lxc-start -n test -F
When running in foreground you should see the output of container starting and it's services, to get information about container run;
$ lxc-info -n test Name: test State: RUNNING PID: 4946 IP: 10.0.3.95 Link: veth101_AEYSE TX bytes: 1.87 KiB RX bytes: 5.31 KiB Total bytes: 7.18 KiB $
To list running containers run;
$ lxc-ls -f NAME STATE AUTOSTART GROUPS IPV4 IPV6 UNPRIVILEGED test RUNNING 0 - 10.0.3.95 - true
To configure users and sshd access container using lxc-attach, add /usr/sbin to path and add user in this case test;
$ lxc-attach -n test # export PATH="/usr/sbin:$PATH" # passwd # useradd -U -m -k /etc/skel -s /bin/bash test # usermod -G adm,wheel,audio,input,video,users test # passwd test # exit
Now is possible to login using console;
$ lxc-console -n test
To exit lxc-console session, type Ctrl-A followed by Q. To stop a container;
$ lxc-stop -n test