注意,本文讨论的是在如何 Docker 中运行 Systemd,并不是通过 Systemd 管理 Docker。首先有两个前提条件:
- Docker 版本至少要 20.10
- 系统必须启用 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