Bootstrap

在 Docker 中使用 Systemd

注意,本文讨论的是在如何 Docker 中运行 Systemd,并不是通过 Systemd 管理 Docker。首先有两个前提条件:

  1. Docker 版本至少要 20.10
  2. 系统必须启用 cgroupv2(检查 /sys/fs/cgroup/cgroup.controllers 文件是否存在即可)

首先是感谢这个大佬给出的方案,链接:

  • https://gist.github.com/pinkeen/bba0a6790fec96d6c8de84bd824ad933
  • https://serverfault.com/questions/1053187/systemd-fails-to-run-in-a-docker-container-when-using-cgroupv2-cgroupns-priva/1054414#1054414

首先在一些人的博客上看到把 /sys/fs/cgroup 映射到容器内的做法,实际上这种玩法在 Debian buster 以及之前的版本是可行的,因为内核默认用的 cgroupv1。但是从 Debian bullseye 之后内核默认用的是 cgroupv2,对于一些比较旧的镜像(比如 CentOS 7)自带的 systemd 还不支持 cgroupv2,就会出现问题。

实际上从 cgroupv2 开始就不应该把 /sys/fs/cgroup 映射到容器内了。Dockerfile 如下:

FROM debian:bullseye
# Using systemd in docker: https://systemd.io/CONTAINER_INTERFACE/
# Make sure cgroupv2 is enabled. To check this: cat /sys/fs/cgroup/cgroup.controllers
ENV container docker
STOPSIGNAL SIGRTMIN+3
VOLUME [ "/tmp", "/run", "/run/lock" ]
WORKDIR /
# Remove unnecessary units
RUN rm -f /lib/systemd/system/multi-user.target.wants/* \
  /etc/systemd/system/*.wants/* \
  /lib/systemd/system/local-fs.target.wants/* \
  /lib/systemd/system/sockets.target.wants/*udev* \
  /lib/systemd/system/sockets.target.wants/*initctl* \
  /lib/systemd/system/sysinit.target.wants/systemd-tmpfiles-setup* \
  /lib/systemd/system/systemd-update-utmp*
CMD [ "/lib/systemd/systemd", "log-level=info", "unit=sysinit.target" ]

启动容器:

docker build -t systemd_test .
docker run -t --rm --name systemd_test \
  --privileged --cap-add SYS_ADMIN --security-opt seccomp=unconfined \
  --cgroup-parent=docker.slice --cgroupns private \
  --tmpfs /tmp --tmpfs /run --tmpfs /run/lock \
  systemd_test

参考

  • https://systemd.io/CONTAINER_INTERFACE/
  • https://github.com/opencontainers/runc/blob/master/docs/cgroup-v2.md
;