bigywater.tech
Docker · 92

容器里跑 systemd:需要哪些额外的设置

能不能在容器里跑完整的 systemd?它需要什么条件、启动后有多重、怎么停?这篇用 debian:12-slim 装上 systemd,逐种选项试能不能启动,并量停止信号的差别。

只有 1 种能启动
试过的 7 种选项配置里,只有 --privileged 能让 systemd 在容器里跑起来
255
没有足够权限时 systemd 当 PID 1 的退出码
0.2 秒 对 10.2 秒
SIGRTMIN+3 与 SIGTERM 下 docker stop 的用时

条件

实测 · 本机执行输出
  默认(什么选项都不加):exited exit=255;systemctl is-system-running = -;控制台最后几行:[!!!!!!] Failed to mount API filesystems. | Exiting PID 1...
  --tmpfs /run --tmpfs /tmp:exited exit=255;systemctl is-system-running = -;控制台最后几行:[!!!!!!] Failed to mount API filesystems. | Exiting PID 1...
  --tmpfs /run --tmpfs /run/lock --tmpfs /tmp:exited exit=255;systemctl is-system-running = -;控制台最后几行:[!!!!!!] Failed to allocate manager object. | Exiting PID 1...
  --cap-add SYS_ADMIN:exited exit=255;systemctl is-system-running = -;控制台最后几行:[!!!!!!] Failed to allocate manager object. | Exiting PID 1...
  --cap-add SYS_ADMIN --security-opt seccomp=unconfined:exited exit=255;systemctl is-system-running = -;控制台最后几行:[!!!!!!] Failed to allocate manager object. | Exiting PID 1...
  --cap-add SYS_ADMIN + seccomp=unconfined + --tmpfs /run /run/lock /tmp:exited exit=255;systemctl is-system-running = -;控制台最后几行:[!!!!!!] Failed to allocate manager object. | Exiting PID 1...
  --privileged:running exit=0;systemctl is-system-running = running;控制台最后几行:[  OK  ] Finished systemd-update-ut… - Record Runlevel Change in UTMP. | Debian GNU/Linux 12 4bea387ff94e console

systemd 当 PID 1 要挂载 /run、/run/lock 等 tmpfs、管理 cgroup。非特权容器里这些操作被拒绝,结果是 255 退出;我试的 --cap-add SYS_ADMIN 加 seccomp=unconfined 加 tmpfs 都还是 Failed to allocate manager object。另一种常被提到的做法是让 cgroup 以可写方式挂入(-v /sys/fs/cgroup:/sys/fs/cgroup:rw --cgroupns=host);我最初探索时带这些选项的 docker run 没有成功创建出容器(原因没有看),所以没有纳入最终的矩阵,不能下结论。

跑起来之后

实测 · 本机执行输出
  PID 1 的名字:systemd
  systemctl is-system-running:running
  运行中的服务:console-getty.service getty@tty1.service getty@tty2.service getty@tty3.service getty@tty4.service getty@tty5.service getty@tty6.service systemd-journald.service
  进程(按名字统计 systemd / systemd-journald / agetty):systemd=2 systemd-journal=1 agetty=7
  docker top 看到的进程数:9

systemd 容器像一台小机器:journald、getty 一组服务,9 个进程。这和「一个容器一个进程」的惯例相反,通常只在需要测试 systemd 服务单元的场景里用。

怎么停

实测 · 本机执行输出
  镜像里 STOPSIGNAL SIGRTMIN+3(c30):docker stop -t 10 用时 0.2 秒,ExitCode=130
  --stop-signal SIGTERM:docker stop -t 10 用时 10.2 秒,ExitCode=137(SIGTERM 没能让它关机,等满宽限期后被 SIGKILL)

systemd 通过 SIGRTMIN+3 关机(这也是 jrei/systemd-debian 这类镜像设 STOPSIGNAL 的原因),SIGTERM 对它无效,docker stop 就会等满宽限期再 SIGKILL。

开销

实测 · 本机执行输出
  从 docker run 到 systemctl is-system-running 返回 running 用了 0.5 秒
  docker stats 的 MemUsage:15.25MiB / 7.748GiB PIDs=9

空闲时 15.25MiB、0.5 秒到 running。服务多了会更重,没有测。

分步演示

容器里的 systemd
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Docker Desktop(Engine 29.8.2,容器跑在 Docker Desktop 自带的 Linux 虚拟机里,内核与宿主机的 macOS 不同);镜像为 linux/arm64;需要看虚拟机内部时用特权容器 + nsenter;计时用 time / date +%s%N,数字每次运行会有小幅抖动。镜像在本机构建(debian:12-slim 经 dpull.py 下载,apt-get 通过容器网络安装 systemd、procps);所有启动选项各试一次,用 -t 让 systemd 的控制台输出进 docker logs;is-system-running 由 docker exec 查询;实验后已删除容器和镜像
    • 没有验证:cgroup 可写挂载方式(--cgroupns=host + 可写 /sys/fs/cgroup)是否让非特权容器启动(在 -t 的最终矩阵里没有包含)、systemd 的 user 实例、在 systemd 里运行真实服务、cgroup v1 的情形、Podman 的 systemd 支持、journald 日志与 docker logs 的关系
    京ICP备2026067502号-1京公网安备11010502063487号