systemd-nspawn: Lightweight Containers on Linux
Using systemd-nspawn for lightweight container management on Linux, including setup, networking, resource limits, and use cases.
Introduction
systemd-nspawn is often described as "chroot on steroids." It provides container-like isolation using Linux namespaces and cgroups without the overhead of Docker or full container runtimes. For building packages, testing configurations, or running isolated services, systemd-nspawn is a powerful tool that is already installed on most systemd-based Linux distributions.
Environment
The examples use systemd-nspawn 252 on Debian 12, creating containers for package building and testing.
systemd-nspawn --version
# systemd 252 (252.19-1~deb12u1)
# Check if systemd-nspawn is available
which systemd-nspawn
# /usr/bin/systemd-nspawnProblem
You need lightweight isolation for:
- Building packages without affecting the host
- Testing system configurations safely
- Running services in isolated environments
- Chroot-like environments with proper namespace isolation
Docker is too heavy for these use cases, and plain chroot lacks proper isolation.
Analysis
systemd-nspawn provides:
- Mount namespace isolation: Container sees its own filesystem
- PID namespace isolation: Container has its own process tree
- Network namespace isolation: Optional network isolation
- Cgroup resource limits: CPU, memory, and I/O limits
- Boot capability: Can boot a full systemd inside the container
Unlike Docker, systemd-nspawn:
- Uses the host kernel directly
- Has minimal overhead
- Integrates with systemd on both host and container
- Requires no daemon process
Solution
1. Create a basic container
# Create a minimal Debian container
sudo debootstrap bullseye /var/lib/machines/test-container http://deb.debian.org/debian
# Or use an existing rootfs
sudo mkdir -p /var/lib/machines/mycontainer
sudo tar -xf rootfs.tar.gz -C /var/lib/machines/mycontainer2. Run a basic container
# Interactive shell
sudo systemd-nspawn -D /var/lib/machines/test-container
# With networking
sudo systemd-nspawn -D /var/lib/machines/test-container --network-bridge=br0
# Boot the container (starts systemd)
sudo systemd-nspawn -D /var/lib/machines/test-container --boot3. Use machinectl for management
# List running containers
machinectl list
# MACHINE CLASS OS VERSION ADDRESS
# test-container container debian 11
# Start a container
sudo machinectl start test-container
# Login to a container
sudo machinectl login test-container
# Shell into a container
sudo machinectl shell test-container4. Configure networking
# Create a bridge interface
sudo ip link add br0 type bridge
sudo ip addr add 192.168.100.1/24 dev br0
sudo ip link set br0 up
# Start container with bridge networking
sudo systemd-nspawn -D /var/lib/machines/test-container \
--network-bridge=br0 \
--boot
# Configure IP inside container
sudo machinectl shell test-container
ip addr add 192.168.100.10/24 dev host0
ip route add default via 192.168.100.15. Set resource limits
# Limit memory
sudo systemd-nspawn -D /var/lib/machines/test-container \
--memory-limit=2G \
--boot
# Limit CPU
sudo systemd-nspawn -D /var/lib/machines/test-container \
--cpu-weight=100 \
--boot
# Limit I/O
sudo systemd-nspawn -D /var/lib/machines/test-container \
--io-weight=100 \
--boot6. Mount host directories
# Mount a host directory into the container
sudo systemd-nspawn -D /var/lib/machines/test-container \
--bind=/home/user/project:/mnt/project \
--boot
# Read-only mount
sudo systemd-nspawn -D /var/lib/machines/test-container \
--bind-ro=/etc/resolv.conf:/etc/resolv.conf \
--boot7. Use systemd-nspawn for package building
# Create a build environment
sudo debootstrap bullseye /var/lib/machines/build http://deb.debian.org/debian
# Enter and build
sudo systemd-nspawn -D /var/lib/machines/build \
--bind=/home/user/project:/build \
--boot
# Inside container
apt-get update
apt-get install -y build-essential
cd /build
make8. Create a systemd service for a container
# /etc/systemd/system/mycontainer.service
[Unit]
Description=My Application Container
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/systemd-nspawn \
-D /var/lib/machines/mycontainer \
--boot \
--network-bridge=br0
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targetsudo systemctl enable mycontainer.service
sudo systemctl start mycontainer.service9. Export and import containers
# Export a container
sudo tar -czf mycontainer.tar.gz -C /var/lib/machines mycontainer
# Import a container
sudo mkdir -p /var/lib/machines/newcontainer
sudo tar -xzf mycontainer.tar.gz -C /var/lib/machines/10. Use systemd-nspawn for testing
#!/bin/bash
# test.sh - Test in isolated container
# Create test environment
sudo debootstrap bullseye /var/lib/machines/test-env http://deb.debian.org/debian
# Run tests in container
sudo systemd-nspawn -D /var/lib/machines/test-env \
--bind=$(pwd):/test \
--quiet \
-- /bin/bash -c "cd /test && make test"
# Cleanup
sudo rm -rf /var/lib/machines/test-env11. Debug container issues
# Check container status
machinectl status test-container
# View container logs
journalctl -M test-container
# Check cgroup usage
systemd-cgtop -M test-container12. Remove a container
# Stop the container
sudo machinectl stop test-container
# Remove the container
sudo machinectl remove test-container
# Or manually
sudo rm -rf /var/lib/machines/test-containerLessons Learned
systemd-nspawn is ideal for lightweight isolation where Docker is overkill. It excels at package building, configuration testing, and running isolated services with minimal overhead. The integration with systemd provides familiar management tools like machinectl and journalctl. For production workloads, Docker or Podman may be more appropriate due to image management and orchestration features. But for development and testing, systemd-nspawn is a powerful tool already at your disposal.
This blog does not accept any external sponsorships, affiliate marketing, or ad revenue.