Skip to content

Instantly share code, notes, and snippets.

@frafra
Last active January 31, 2024 12:19
Show Gist options
  • Save frafra/02696ed4121772dd38674d5cb0bb1fa6 to your computer and use it in GitHub Desktop.
Save frafra/02696ed4121772dd38674d5cb0bb1fa6 to your computer and use it in GitHub Desktop.

systemd containers

Assumptions

This how-to uses mybox as container name, mkosi in order to create containers (it works for multiple distributions and has more features compared to dnf --installroot), and crudini for configurations file (you can use your preferred text editor instead).

How to create a container with mkosi

# mkosi --cache /var/cache/mkosi -d fedora -t directory -o /var/lib/machines/mybox

mkosi can do much more! https://github.com/systemd/mkosi

How to start a container with machinectl

# machinectl start mybox

How to invoke a shell

# machinectl shell mybox

How to configure the network with networkd

machinectl calls systemd-nspawn with different network connection defaults. The first creates a new virtual ethernet interface, while the second uses the loopback interface. This little how-to uses nspawn configuration files in order to setup containers instead of calling systemd-nspawn directly (this is necessary in order to boot containers with machinectl with custom settings). The configuration files can be stored under /etc/systemd/nspawn (not created by default), /run/systemd/nspawn and /var/lib/machines/, but only the first two paths are considered as trusted, so this how-to uses the second directory (source: nspawn.c source code). machinectl defaults are overridden by specific nspawn configuration files.

In order to see machinectl defaults:

$ crudini --get /usr/lib/systemd/system/systemd-nspawn@.service Service ExecStart

More information about nspawn configuration files: man systemd.nspawn

Loopback

If you want to use the loopback interface:

# crudini --set /run/systemd/nspawn/mybox.nspawn Network VirtualEthernet no
# machinectl stop mybox
# machinectl start mybox

Virtual ethernet interface

# crudini --set /run/systemd/nspawn/mybox.nspawn Network VirtualEthernet yes
# systemctl start systemd-networkd
# systemctl enable systemd-networkd
# systemctl -M mybox enable systemd-networkd
# machinectl stop mybox
# machinectl start mybox

Test your connection with ping -c 1 mybox Unable to ping your container? Have a look at https://www.freedesktop.org/software/systemd/man/nss-mymachines.html Still have problems? Try machinectl status mybox and networkctl

Network bridge

If libvirt-daemon-config-network is installed and libvirtd.service is running, you could use the existing bridge for your containers:

# crudini --set /run/systemd/nspawn/mybox.nspawn Network Bridge=virbr0
# systemctl start systemd-networkd
# systemctl enable systemd-networkd
# systemctl -M mybox enable systemd-networkd
# machinectl stop mybox
# machinectl start mybox

If you need to create a network bridge, please follow https://major.io/2015/03/26/creating-a-bridge-for-virtual-machines-using-systemd-networkd/

Limit CPU and memory usage

# systemctl set-property --runtime systemd-nspawn@mybox.service MemoryMax=500M
# systemctl set-property --runtime systemd-nspawn@mybox.service CPUShares=500

Configuration files are stored in /etc/systemd/system.control/systemd-nspawn@mybox.service.d/ More information about resource control: man systemd.resource-control

Boot container when host boots

# machinectl enable mybox

Example: Wordpress

Container creation

# mkosi --cache /var/cache/mkosi -d fedora -t directory -o /var/lib/machines/wordpress -p wordpress,mariadb-server
# crudini --set /run/systemd/nspawn/wordpress.nspawn Network VirtualEthernet no

Configuration script

Adjust port=8080 as you like (first line).

$ port=8080; password=$(openssl rand -base64 18)
$ curl https://api.wordpress.org/secret-key/1.1/salt/ > /tmp/salt
$ cat > /tmp/wordpress.sh <<EOF
#!/bin/sh
set -x
echo -e '\nn\n\n\n\n\n' | mysql_secure_installation
mysql <<END
CREATE DATABASE wordpress;
GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress'@'%' IDENTIFIED BY '$password';
FLUSH PRIVILEGES;
END
sed -i "s/Listen 80/Listen $port/" /etc/httpd/conf/httpd.conf
sed -i "s/Require local/Require all granted/" /etc/httpd/conf.d/wordpress.conf
multisite="define( 'WP_ALLOW_MULTISITE', true );"
sed -i \
    -e "s:database_name_here:wordpress:" \\
    -e "s:username_here:wordpress:" \\
    -e "s:password_here:$password:" \\
    -e "s:/\* That's all, stop editing! Happy blogging. \*/:$multisite\n&:" \\
    -e "/put your unique phrase here/d" \\
    /etc/wordpress/wp-config.php
cd /tmp
csplit /etc/wordpress/wp-config.php "/\/\*\*#@-\*\//"
cat xx00 salt xx01 > /etc/wordpress/wp-config.php
rm xx00 salt xx01 wordpress.sh
EOF

Container configuration

# machinectl start wordpress
# systemctl -M wordpress start mariadb
# machinectl copy-to wordpress /tmp/wordpress.sh
# machinectl copy-to wordpress /tmp/salt
# machinectl shell wordpress /bin/sh /tmp/wordpress.sh
# systemctl -M wordpress enable mariadb httpd
# systemctl -M wordpress start httpd
$ rm /tmp/wordpress.sh /tmp/salt

Wordpress installation process

Visit http://localhost:8080 and follow the procedure.

Resources

@Germano0
Copy link

This gist contains the best systemd containers use case example of the entire internet

@Germano0
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment