Ste*_*hen 10 cgroup systemd docker
我将在下面附上最小化的测试用例。但是,它是一个简单的 Dockerfile,具有以下几行:
VOLUME ["/sys/fs/cgroup"]
CMD ["/lib/systemd/systemd"]
Run Code Online (Sandbox Code Playgroud)
它是基于 Debian:buster-slim 的映像,并在容器内运行 systemd。实际上,我曾经像这样运行容器:
$ docker run --name any --tmpfs /run \
--tmpfs /run/lock --tmpfs /tmp \
-v /sys/fs/cgroup:/sys/fs/cgroup:ro -it image_name
Run Code Online (Sandbox Code Playgroud)
在我升级一堆主机 Linux 软件包之前,它曾经运行良好。主机内核/systemd 现在似乎默认 cgroup v2。之前是cgroup。它停止工作。但是,如果我提供内核选项以便主机使用 cgroup,则它会再次运行。
在不提供内核选项的情况下,修复是添加--cgroupns=host到docker run除了/sys/fs/cgroup以读写方式安装(:rw代替:ro)之外。
我想避免强迫用户提供内核选项。尽管我远非专家,但强制为 docker 容器使用主机命名空间对我来说并不合适。
我试图理解为什么会发生这种情况,并弄清楚应该做什么。我的目标是在 docker 中运行 systemd,其中主机遵循 cgroup v2。
这是我看到的错误:
$ docker run --name any --tmpfs /run --tmpfs /run/lock --tmpfs /tmp \
-v /sys/fs/cgroup:/sys/fs/cgroup:rw -it image_name
systemd 241 running in system mode. (+PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD -IDN2 +IDN -PCRE2 default-hierarchy=hybrid)
Detected virtualization docker.
Detected architecture x86-64.
Welcome to Debian GNU/Linux 10 (buster)!
Set hostname to <5e089ab33b12>.
Failed to create /init.scope control group: Read-only file system
Failed to allocate manager object: Read-only file system
[!!!!!!] Failed to allocate manager object.
Exiting PID 1...
Run Code Online (Sandbox Code Playgroud)
它看起来不对,但尤其是这条线似乎很可疑:
Failed to create /init.scope control group: Read-only file system
Run Code Online (Sandbox Code Playgroud)
似乎之前应该有什么/init.scope。这就是为什么我审查了docker run选项,并尝试了该--cgroupsns选项。如果我添加--cgroupns=host,它会起作用。如果我/sys/fs/cgroup以只读方式挂载,则会失败并显示不同的错误,相应的行如下所示:
Failed to create /system.slice/docker-0be34b8ec5806b0760093e39dea35f4305262d276ecc5047a5f0ff43871ed6d0.scope/init.scope control group: Read-only file system
Run Code Online (Sandbox Code Playgroud)
对我来说,这就像 docker daemon/engine 无法为容器配置 XXX.slice 或类似的东西。我认为 docker 可能在某种程度上负责提供命名空间,但有些事情进展不顺利。但是,我完全不能确定。问题/修复是什么?
我本次实验使用的Dockerfile如下:
FROM debian:buster-slim
ENV container docker
ENV LC_ALL C
ENV DEBIAN_FRONTEND noninteractive
USER root
WORKDIR /root
RUN set -x
RUN apt-get update -y \
&& apt-get install --no-install-recommends -y systemd \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \
&& rm -f /var/run/nologin
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*
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/lib/systemd/systemd"]
Run Code Online (Sandbox Code Playgroud)
我正在使用 Debian。docker 版本是 20.10.3 左右。Google 搜索告诉我 docker 从 20.10 开始支持 cgroup v2,但我实际上不明白“支持”是什么意思。
pin*_*een 18
在我看来,这个用例尚未得到明确支持。你几乎可以让它工作,但还不够。
当 systemd 看到一个统一的 cgroupfs时,/sys/fs/cgroup它假设它应该能够写入它,这通常应该是可能的,但这里的情况并非如此。
首先,您需要为 docker 容器创建一个systemd 切片并告诉 docker 使用它 - 我当前的docker/daemon.json:
{
"exec-opts": ["native.cgroupdriver=systemd"],
"features": { "buildkit": true },
"experimental": true,
"cgroup-parent": "docker.slice"
}
Run Code Online (Sandbox Code Playgroud)
注意:并非所有这些选项都是必需的。最重要的一点是
cgroup-parent。默认情况下应该cgroupdriver已经切换到“systemd”。
每个切片都有自己的嵌套 cgroup。但有一个警告:每个组可能只是一个“叶子”或“中介”。一旦某个进程取得了 cgroup 的所有权,其他进程就无法管理它。这意味着实际的容器进程需要并将其自己的私有组以systemd 作用域的形式附加到配置的组下面。
参考:请查找有关systemd 资源控制、 cgroup 命名空间处理和委托的更多信息。
注意:默认情况下,docker 守护进程应该使用这一点
--cgroupns private,但无论如何您都可以强制它。
现在,新启动的容器将获得自己的组,该组应该在类似于以下的路径(取决于您的设置)中可用:
/sys/fs/cgroup/your_docker_parent.slice/your_container.scope
Run Code Online (Sandbox Code Playgroud)
这是重要的部分:您不能将卷安装到容器的/sys/fs/cgroup. 上面提到的其私有组的路径应该自动安装在那里。
现在,理论上,容器应该能够几乎完全自行管理这个委托的私有组。这将允许其自己的 init 进程创建子组。
问题在于/sys/fs/cgroup容器中的路径以只读方式安装。我检查了 apparmor 规则并将 seccomp 切换为 unconfined,但无济于事。
我还不完全确定 - 我目前的假设是这是 docker/moby/containerd 的安全功能。如果没有私人团体,走这条路是非常有意义的ro。
我还发现,启用用户命名空间重新映射会导致私有按预期/sys/fs/cgroup安装!rw
但这远非完美 - cgroup(以及其他)挂载的所有权错误:它由真实系统根(UID0)拥有,而容器已被重新映射到完全不同的用户。一旦我手动调整了所有者,容器就能够成功启动 systemd init。
我怀疑这是 docker 的用户重新映射功能的缺陷,迟早会被修复。请记住,我对此可能是错的 - 我没有确认。
用户重新映射有很多缺点,对我来说最好的方案是在rw没有它的情况下安装 cgroupfs。我仍然不知道这是故意的还是 cgroup/userns 实现的某种限制。
您的内核启用了 cgroupv2 还不够。根据 Linux 发行版,捆绑的 systemd 可能更喜欢默认使用 v1。
您可以通过内核命令行参数告诉 systemd 使用 cgroupv2:
systemd.unified_cgroup_hierarchy=1
可能还需要显式禁用混合cgroupv1 支持以避免出现问题:
systemd.legacy_systemd_cgroup_controller=0
或者在内核中完全禁用 cgroupv1:
cgroup_no_v1=all
小智 6
感谢 @pinkeen 的回答,这是我的 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" ]
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
注意:您必须使用 Docker 20.10 或更高版本,并且您的系统启用了 cgroupv2(检查是否/sys/fs/cgroup/cgroup.controllers存在)。
| 归档时间: |
|
| 查看次数: |
2331 次 |
| 最近记录: |