systemd-nspawn - Containerization - Part 2

Nov 28, 2020

Recap:

In the last part of the series, we saw how to configure the network in host for containers and learnt how to pull images using machinectl. If you haven’t gone through that first, please do so.

Before Booting your container for the first time:

I’m using an cloud based ubuntu image, as it provides cloud-init support, which lets me configure my container during the boot itself. I’m not going to go into the details of cloud-init, but I’ll give you some idea about minimising full-blown cloud setup.

Also, you can feel familiar with cloud vendors system startup by using the cloud based images.

cloud-init:

By default, if you don’t configure cloud-init, it will try to hit and reach many cloud vendors looking for source configuration, which can take an awful lot of time approximately upto 40 minutes. We’ll see how to disable that:

datasource: NoCloud
policy: search,found=first,maybe=none,notfound=disabled

This file is telling the cloud-init to use the datasource as NoCloud, which will not do any lookup with cloud vendors

$ tree
.
├── ds-identity.cfg
├── nocloud
│   ├── meta-data
│   ├── network-config
│   └── user-data
└── xenial.nspawn
1 directory, 5 files

Our mount file for container - xenial.nspawn:

Always have a copy of this file xenial.nspawn stored somewhere, as the container removal leads to deletion of this file. Copy this file to /etc/systemd/nspawn directory.

[Exec]
# Writable bind mounts don't with user namespacing
PrivateUsers=pick
[Files]
# these lines should be familiar for those who are using docker
# this is a simple read-only volume mount for the cloud-init files
BindReadOnly=/home/user/cloud-init/ds-identity.cfg:/etc/cloud/ds-identity.cfg
BindReadOnly=/home/user/cloud-init/nocloud:/var/lib/cloud/seed/nocloud
PrivateUsersChown=yes
# PrivateUsersChown is an expensive operation according to the documentation
[Network]
VirtualEthernet=yes
Bridge=virxen

Let’s fire up our container:

$ sudo systemd-nspawn -D /var/lib/machines/xenial -U -b -M xenial
# -b flag means boot, which boots our container
...............System Startup messages.............................
......................Login Page...................................

You need to wait for sometime, for the cloud-init to complete, then only we can use the testuser created with the config file. You will see the familiar output logs from cloud-vendors. Use the below command to view the system setup and once, it comes to a halt, use the username and password from the cloud-init config file to login to your new container. Voila!!!

$ sudo journalctl -M xenial -f
.....................Cloud-Init Output Logs........................

Those who want an easier way out of this setup:

Please use debootsrap as follows:

$ sudo mkdir -p /var/lib/machines/{any name of your choice}
$ sudo debootstrap --arch=amd64 jessie /var/lib/machines/{any name of your choice}/

If you don’t specify any network in the xenial.nspawn file, the container will see all network interfaces of the host and acts like it’s an application inside the host using the same ip addresses.

Once, again, some of the steps might be volatile, such as networks, so please make a backup of them if you want to persist. Follow, these tutorials for making them persistent across system reboots.

Problems that might arise and solutions:

Container Management:

After the setup you don’t have to use systemd-nspawn at all except certain cases. machinectl is more than sufficient to manage containers.

I have intentionally left out the container resource management as it is easy to follow from the official documentation of @.nspawn from the references.

References:

   til (4) , systemd (2) , nspawn (2) , systemd-nspawn (2) , linux (5) , unix (5) , script (3) , containers (2) , development (2)