我在Docker容器中搭建了一个可以使用Systemd的CentOS

首先

CentOS容器默认情况下不能使用Systemd,但在DockerHub的页面上有记录如何启用Systemd的方法,我尝试了一下。

执行环境

操作系统:MacOS Monterey 12.4
Docker:Docker版本20.10.14
Docker桌面版(适用于Mac):版本4.7.1
Docker镜像:CentOS 7

获取CentOS7的Docker镜像

% docker pull centos:7

创建基于Systemd的映像

创建Dockerfile

因为在DockerHub页面上有示例,所以我们可以参考它们来创建Dockerfile。

% vim ~/workspace/docker/centos/systemd-base/Dockerfile
FROM centos:7
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]

构建图像

根据 Dockerfile 构建镜像。

% docker build --rm -t centos-systemd ~/workspace/docker/centos/systemd-base/
[+] Building 0.1s (6/6) FINISHED                                                    
 => [internal] load build definition from Dockerfile                           0.1s
 => => transferring dockerfile: 37B                                            0.0s
 => [internal] load .dockerignore                                              0.0s
 => => transferring context: 2B                                                0.0s
 => [internal] load metadata for docker.io/library/centos:7                    0.0s
 => [1/2] FROM docker.io/library/centos:7                                      0.0s
 => CACHED [2/2] RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in   0.0s
 => exporting to image                                                         0.0s
 => => exporting layers                                                        0.0s
 => => writing image sha256:ddbe5f1f9b13355b0558d857948f089860b0e4393ec6a40b9  0.0s
 => => naming to docker.io/library/centos-systemd                              0.0s

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

在构建完之后,可以使用docker命令来查看镜像列表。

% docker images -a
REPOSITORY            TAG       IMAGE ID       CREATED        SIZE
centos-systemd   latest    ddbe5f1f9b13   2 days ago     204MB
centos                7         eeb6ee3f44bd   8 months ago   204MB

启动容器

1. 第一次尝试失败了

参考DockerHub页面,使用以下命令启动容器。

% docker run --name centos-systemd-container -ti -v /sys/fs/cgroup:/sys/fs/cgroup:ro -d centos-systemd
f27733e900c6cc99ed9aa3e046c72773cf87cef580b8b8c27d5610d39b35e4f6

我将在已启动的容器中尝试运行Systemd以进行确认。

sh-4.2# systemctl list-units --type=service
Failed to get D-Bus connection: Operation not permitted

似乎没有权限获取D-Bus连接。

在 Docker 文档中查找权限相关信息,发现 Docker 容器在默认情况下缺乏权限,无法连接到设备,因此需要将其设置为特权容器。

因此,我们将尝试使用”privileged”选项作为特权容器来启动。

失败2

% docker run --name centos-systemd-container --privileged -ti -v /sys/fs/cgroup:/sys/fs/cgroup:ro -d centos-systemd
e3de98766ea9b4a181eb9fde99040c0093514e25bb0e72f55bd412717b2e8422
sh-4.2# systemctl list-units --type=service
Failed to get D-Bus connection: No such file or directory

这次好像找不到文件目录,所以失败了。在搜索消息时,我找到了这个页面。

由于Docker Desktop开始使用cgroupv2,所以systemd也需要支持cgroupv2,至少需要systemd247以上的版本。

我会确认一下自己的环境。

sh-4.2# journalctl --version
systemd 219
+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 -SECCOMP +BLKID +ELFUTILS +KMOD +IDN

版本不够,请参考同一页面中的信息,看看是否有使用cgroupv1参数来使用DockerDesktop的选项。我将尝试进行设置。
设置文件位于~/Library/Group Containers/group.com.docker/settings.json。

  "deprecatedCgroupv1": true, // trueに変更します

更改了settings.json后,请重新启动并再次尝试。

取决于个人的定义和努力水平。

sh-4.2# systemctl list-units --type=service
UNIT                         LOAD   ACTIVE SUB     DESCRIPTION
systemd-journald.service     loaded active running Journal Service
systemd-tmpfiles-setup.service loaded active exited  Create Volatile Files and D
ir

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

2 loaded units listed. Pass --all to see loaded but inactive units, too
.
To show all installed unit files use 'systemctl list-unit-files'.

没问题,现在systemctl命令开始有响应了。

文献引用

 

bannerAds