强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

systemd 教程 / 容器管理(systemd-nspawn)

容器管理(systemd-nspawn)

systemd-nspawn 是 systemd 内置的轻量级容器工具,名称源自 “chroot 的命名空间增强版”。它利用 Linux 内核的命名空间(namespaces)和 cgroups 实现进程隔离,是测试、开发和构建环境的理想选择。


1. systemd-nspawn 概述

什么是 systemd-nspawn?

systemd-nspawn 是一个容器运行时工具,功能介于 chroot 和完整容器(如 Docker)之间。

特性chrootsystemd-nspawnDocker
文件系统隔离
PID 命名空间
网络隔离
用户命名空间
cgroup 资源限制
镜像管理✅ (machinectl)
依赖最小化
systemd 作为 PID 1可选

典型应用场景

  • 开发环境隔离:不同项目使用不同的系统环境
  • 构建打包:在干净的环境中编译软件
  • 测试环境:测试 systemd 服务和配置
  • 最小化部署:无需完整虚拟机的场景

2. 启动容器

2.1 基本启动

# 使用目录作为容器根文件系统
sudo systemd-nspawn -D /var/lib/machines/mycontainer

# 指定容器名称
sudo systemd-nspawn -D /var/lib/machines/mycontainer --machine=myapp

# 以只读模式启动
sudo systemd-nspawn -D /var/lib/machines/mycontainer --read-only

2.2 使用 boot 参数

# 启动完整系统(容器内运行 systemd)
sudo systemd-nspawn -D /var/lib/machines/mycontainer --boot

# 分配伪终端
sudo systemd-nspawn -D /var/lib/machines/mycontainer --boot --console=interactive

2.3 常用启动参数

参数说明
-D, --directory=指定容器根目录
-b, --boot以完整系统模式启动
--machine=设置容器名称
--uuid=指定容器 UUID
--read-only只读挂载根文件系统
--bind=绑定挂载宿主目录
--bind-ro=只读绑定挂载
--network-interface=分配网络接口
--private-network隔离网络
--private-users=启用用户命名空间
--drop-capability=移除 capabilities

3. 容器内 systemctl

当容器以 --boot 模式启动时,容器内会运行 systemd 作为 PID 1:

# 进入容器
sudo machinectl login mycontainer

# 在容器内使用 systemctl
systemctl list-units
systemctl start nginx
systemctl enable redis
journalctl -u nginx

⚠️ 注意:容器内的 systemd 与宿主 systemd 完全独立,拥有自己的 unit 文件和服务状态。


4. 镜像管理(machinectl)

machinectl 是管理 systemd 容器和虚拟机的命令行工具。

4.1 基本操作

# 列出所有容器/虚拟机
machinectl list-images

# 查看容器状态
machinectl status mycontainer

# 登录容器
machinectl login mycontainer

# 启动/停止/重启容器
machinectl start mycontainer
machinectl stop mycontainer
machinectl reboot mycontainer

# 查看容器日志
machinectl shell mycontainer

4.2 镜像操作

# 从模板下载镜像
machinectl pull-tar https://example.com/image.tar.gz myimage
machinectl pull-raw https://example.com/image.raw.xz myimage

# 导出镜像
machinectl export-tar mycontainer /tmp/mycontainer.tar.gz

# 删除镜像
machinectl remove mycontainer

4.3 创建容器文件系统

# 方法 1:使用 dnf/yum 创建
sudo dnf --releasever=38 --installroot=/var/lib/machines/fedora38 \
    install -y systemd passwd dnf

# 方法 2:使用 debootstrap 创建 Debian 容器
sudo debootstrap stable /var/lib/machines/debian http://deb.debian.org/debian

# 方法 3:使用 dnf 标准安装
sudo dnf -y --releasever=40 --installroot=/var/lib/machines/mycontainer \
    --repo=fedora --repo=updates install systemd passwd dnf

5. 容器网络配置

5.1 使用虚拟网络接口

# 自动创建虚拟以太网对(veth)
sudo systemd-nspawn -D /var/lib/machines/mycontainer \
    --network-veth \
    --boot

5.2 使用现有网络接口

# 直接使用宿主网络接口
sudo systemd-nspawn -D /var/lib/machines/mycontainer \
    --network-interface=eth0 \
    --boot

# 使用 MACVLAN
sudo systemd-nspawn -D /var/lib/machines/mycontainer \
    --network-macvlan=eth0 \
    --boot

5.3 网络配置文件

为容器创建专用网络配置:

# /etc/systemd/nspawn/mycontainer.nspawn
[Exec]
Boot=yes

[Network]
VirtualEthernet=yes
Bridge=br0

网络类型对比:

类型参数说明
虚拟以太网--network-veth创建 veth pair,适合桥接
接口绑定--network-interface=直接使用宿主接口
MACVLAN--network-macvlan=创建 MACVLAN 子接口
IPVLAN--network-ipvlan=创建 IPVLAN 子接口
隔离--private-network完全无网络

6. 容器资源限制(cgroups)

6.1 通过 nspawn 参数限制

sudo systemd-nspawn -D /var/lib/machines/mycontainer \
    --cpu-quota=50% \
    --memory=512M \
    --boot

6.2 通过 machinectl 限制

# 设置 CPU 配额
sudo machinectl set-property mycontainer CPUQuota=50%

# 设置内存限制
sudo machinectl set-property mycontainer MemoryMax=512M

# 设置 I/O 权重
sudo machinectl set-property mycontainer IOWeight=500

6.3 通过 slice 管理

# /etc/systemd/system/machine-mycontainer.slice.d/limits.conf
[Slice]
CPUQuota=50%
MemoryMax=512M
IOWeight=500
TasksMax=100

💡 提示:使用 systemd-cgls 查看 cgroup 树结构,确认限制是否生效。


7. 容器自动启动

7.1 使用 [email protected] 模板

systemd 提供了 [email protected] 模板用于自动启动容器:

# 启用容器自动启动
sudo systemctl enable [email protected]

# 启动容器
sudo systemctl start [email protected]

# 查看容器状态
sudo systemctl status [email protected]

7.2 容器配置文件

# /etc/systemd/nspawn/mycontainer.nspawn
[Exec]
Boot=yes
Parameters=--boot --console=interactive

[Files]
ReadOnly=no

[Network]
VirtualEthernet=yes
VirtualEthernetExtra=host0:ve-mycontainer

7.3 自定义服务模板

# /etc/systemd/system/[email protected]
[Unit]
Description=Custom Container %i
After=network.target

[Service]
ExecStart=/usr/bin/systemd-nspawn \
    -D /var/lib/machines/%i \
    --boot \
    --network-veth \
    --machine=%i
ExecStop=/usr/bin/machinectl poweroff %i
Restart=on-failure
KillMode=mixed

[Install]
WantedBy=multi-user.target

8. machinectl 命令大全

8.1 容器生命周期

# 列出运行中的容器
machinectl list

# 列出所有镜像
machinectl list-images

# 查看容器详细信息
machinectl show mycontainer

# 登录容器(需要容器内有可登录用户)
machinectl login mycontainer

# 在容器内执行命令
machinectl shell mycontainer /bin/bash

# 关闭容器
machinectl poweroff mycontainer

# 重启容器
machinectl reboot mycontainer

# 终止容器(强制)
machinectl terminate mycontainer

8.2 镜像管理

# 重命名镜像
machinectl rename oldname newname

# 导出镜像
machinectl export-raw mycontainer /tmp/mycontainer.raw

# 从 URL 导入
machinectl pull-tar https://example.com/rootfs.tar.xz myimage

9. systemd-nspawn vs Docker 对比

维度systemd-nspawnDocker
设计目标系统容器应用容器
PID 1systemd用户进程
镜像格式目录/tar/rawOCI/Docker 镜像
生态系统systemd 原生完整生态系统
编排machinectl/systemdDocker Compose/K8s
安全性systemd 沙箱Seccomp/AppArmor/SELinux
适用场景开发/测试/构建生产部署
学习曲线低(已有 systemd 知识)
资源开销极低

选择建议:

  • 需要快速搭建开发/测试环境 → systemd-nspawn
  • 需要完整的 CI/CD 流程 → Docker
  • 需要最小化隔离环境 → systemd-nspawn
  • 需要生产级编排和调度 → Docker + Kubernetes

10. 构建容器镜像(mkosi)

mkosi 是 systemd 官方的镜像构建工具。

10.1 安装 mkosi

# Fedora
sudo dnf install mkosi

# Ubuntu/Debian
sudo apt install mkosi

# pip 安装
pip install mkosi

10.2 创建镜像配置

# mkosi.conf
[Distribution]
Distribution=fedora
Release=40

[Output]
Format=directory
Output=mycontainer

[Content]
Packages=systemd passwd dnf vim curl wget
Password=root

[Partitions]
RootSize=2G

10.3 构建并使用

# 构建镜像
sudo mkosi

# 使用构建的目录启动
sudo systemd-nspawn -D mycontainer --boot

# 导入到 machines 目录
sudo mv mycontainer /var/lib/machines/

生产场景:构建自动化容器环境

以下是一个完整的自动化脚本,用于创建、配置和启动生产级容器:

#!/bin/bash
# create-container.sh

CONTAINER_NAME="webapp"
CONTAINER_DIR="/var/lib/machines/${CONTAINER_NAME}"

# 1. 创建容器根文件系统
sudo dnf --releasever=40 --installroot="${CONTAINER_DIR}" \
    --repo=fedora --repo=updates \
    install -y systemd systemd-networkd nginx redis

# 2. 配置容器
sudo systemd-nspawn -D "${CONTAINER_DIR}" \
    systemctl enable nginx redis

# 3. 创建 nspawn 配置
sudo tee "/etc/systemd/nspawn/${CONTAINER_NAME}.nspawn" <<EOF
[Exec]
Boot=yes

[Network]
VirtualEthernet=yes
Bridge=br0

[Files]
BindReadOnly=/srv/webapp:/var/www/html
EOF

# 4. 启用自动启动
sudo systemctl enable systemd-nspawn@${CONTAINER_NAME}.service
sudo systemctl start systemd-nspawn@${CONTAINER_NAME}.service

echo "Container ${CONTAINER_NAME} is running."

⚠️ 注意事项

  1. 文件系统兼容性:容器根文件系统必须与宿主架构一致(目前不支持跨架构)
  2. 内核共享:systemd-nspawn 与宿主共享内核,无法运行不同内核版本的系统
  3. 存储空间:每个容器都是完整根文件系统,注意磁盘空间管理
  4. 安全隔离:相比 Docker,systemd-nspawn 的安全隔离较弱,不建议用于多租户场景
  5. 网络配置:桥接网络需要宿主配置网桥设备

💡 提示

  • 使用 machinectl shellmachinectl login 更方便执行单次命令
  • 容器配置文件 .nspawn 放在 /etc/systemd/nspawn/ 目录下可被 machinectl 自动识别
  • 使用 systemd-nspawn --ephemeral 启动临时容器,关闭后自动丢弃修改
  • systemd-nspawn --pipe 可用于非交互式命令执行,适合脚本自动化

扩展阅读