nspawn pulls OCI images from the hub at
hub.nspawn.org, from Docker Hub or from any other registry, stores them as
shared layers and starts, inspects and stops the machines through the D-Bus
APIs of systemd-machined and systemd itself. No machinectl, no importctl:
the machines are ordinary systemd-nspawn@.service units that the rest of the
system already knows.
Images from any registry
nspawn search fedora looks on the hub and on Docker Hub at once;
nspawn pull fetches from either, and login keeps credentials per registry.
Layers are downloaded once, verified against their digests and shared between
machines. Remove an image and the layers nobody uses go with it.
Machines and apps
Images that ship systemd boot like machinectl start does. Anything else, for
example a docker image, runs its entrypoint as an app under a stub init, with
-p, -e, -v and --entrypoint as in docker. ps, exec, shell,
logs and stop work the same on both.
Networking that works everywhere
A docker0 style bridge with NAT, fixed addresses, published ports and machine names that resolve, managed by nspawn itself. It behaves the same whether the host runs systemd-networkd, NetworkManager, docker, firewalld or nothing at all.
The whole tool in a screenful
sudo nspawn hub ls # repositories and tags on the hub
sudo nspawn search fedora # images on the hub and on Docker Hub
sudo nspawn login docker.io -u me # credentials for a registry (the hub by default)
sudo nspawn pull fedora:44 # download and assemble an image
sudo nspawn images ls # local images (all of them, not only ours)
sudo nspawn start fedora-44 # boot it as a machine
sudo nspawn create fedora-44 db # another machine from the same image
sudo nspawn start web -p 8080:80 -e KEY=v -v /srv/data:/data -v pgdata:/var/lib/pg
sudo nspawn ps # running machines: image, mode, command, uptime
sudo nspawn exec fedora-44 -- systemctl is-system-running
sudo nspawn shell fedora-44
sudo nspawn logs fedora-44 # console output; --inside reads its journal
sudo nspawn stop fedora-44
sudo nspawn images rm fedora-44 # also frees layers and blobs nobody uses
sudo nspawn build -t team/app:1 ./app # mkosi --format=oci, imported as an image
sudo nspawn push team/app:1 # upload it; layers already there are skipped
Every command is a call to nspawn’s service on the system bus, which asks
polkit who you are: sudo always works, an administrator is asked for a
password, and a rule of your own can hand the actions to a group.
Build with mkosi, push anywhere
nspawn build runs mkosi with --format=oci on a directory with a
mkosi.conf, imports the result as a local image and push uploads it to the
hub or to any registry you point it at.
Open images
Every image on the hub is built from public mkosi definitions with the distribution’s own package manager. Read them, rebuild them, send fixes.
Small and self-contained
One binary, written in Rust. Its state lives under /var/lib/nspawn, its
machines under /var/lib/machines, and everything it generates is a plain
systemd unit or settings file you can read.