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 daemon of its own, 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
nspawn hub ls # repositories and tags on the hub
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
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
nspawn ps # running machines: image, mode, command, uptime
nspawn exec fedora-44 -- systemctl is-system-running
nspawn shell fedora-44
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
nspawn push team/app:1 # upload it; layers already there are skipped
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.