如何获取docker容器内主机的挂载信息

Akh*_*han 3 linux selinux mount docker bind-mount

我需要连接到 docker 容器内主机的所有磁盘的挂载点。安装信息在/proc/1/mounts文件中可用,但我无法在所有操作系统上访问该文件。

当我在 Ubuntu 上运行以下命令时,它工作正常。

docker run -it -v /proc/1/mounts:/tmp/mounts ubuntu:16.04

但是在启用了 SELinux 的 CentOS 上,我无法挂载/proc/1/mounts文件。它会给出permission denied错误。

我也尝试过/etc/mtab,但由于它是到 的符号链接/proc/self/mounts,因此 docker 容器内的内容会发生变化。

除了 ,还有其他方法可以获取主机的挂载信息/proc/1/mounts,还是应该使用特定的 SELinux 标签?

我试过docker run -it --privileged -v /proc/1/mounts:/tmp/mounts ubuntu:16.04,它仍然给出同样的错误。

f9c*_*534 6

我假设您并不严格要求 init 进程(pid 1)可见的挂载,并且 docker 守护程序可见的挂载就足够了。通常,它们都应该具有相同的挂载命名空间。

CentOS docker 包的答案

(使用来自 CentOS 存储库的 docker 1.13.1)

我可以用/proc/1/mounts. 但是,使用 docker 守护进程的 mounts 文件可以工作:

$ docker run -it -v /proc/$(pidof dockerd-current)/mounts:/tmp/mounts ubuntu:16.04
Run Code Online (Sandbox Code Playgroud)

在 docker 容器中,/tmp/mounts然后列出主机的挂载。

Docker 社区版的答案

(使用这里描述的外部 docker-ce 18.09.5 包)

除了上面解释的问题外,该docker-ce包还有一个containerd服务的 SE Linux 上下文的问题:

# ps xZ | grep containerd
system_u:system_r:unconfined_service_t:s0 5695 ? Ssl   0:00 /usr/bin/containerd
...
Run Code Online (Sandbox Code Playgroud)

我们希望containerd 用类型container_runtime_t而不是unconfined_service_t. 为此,/usr/bin/containerd必须更新的标签(一般参考):

# ls -Z /usr/bin/dockerd-ce 
-rwxr-xr-x. root root system_u:object_r:container_runtime_exec_t:s0 /usr/bin/dockerd-ce
# ls -Z /usr/bin/containerd
-rwxr-xr-x. root root system_u:object_r:bin_t:s0       /usr/bin/containerd
# semanage fcontext -a -t container_runtime_exec_t /usr/bin/containerd
# restorecon /usr/bin/containerd
# ls -Z /usr/bin/containerd
-rwxr-xr-x. root root system_u:object_r:container_runtime_exec_t:s0 /usr/bin/containerd
Run Code Online (Sandbox Code Playgroud)

接下来,重新启动containerd守护进程:

# systemctl daemon-reload
# systemctl restart containerd
# ps xZ | grep containerd
system_u:system_r:container_runtime_t:s0 6557 ? Ssl   0:00 /usr/bin/containerd
Run Code Online (Sandbox Code Playgroud)

现在,可以使用与上述相同的技术(用dockerd代替dockerd-current)启动 docker 容器:

$ docker run -it -v /proc/$(pidof dockerd)/mounts:/tmp/mounts ubuntu:16.04
Run Code Online (Sandbox Code Playgroud)

背景资料

我在 CentOS Linux 7.6.1810 版上对此进行了测试。

您可以验证 init 和 docker 守护进程是否具有相同的挂载命名空间(即它们的 /proc/[pid]/mounts 将显示相同的挂载):

# readlink /proc/1/ns/mnt /proc/$(pidof dockerd-current)/ns/mnt
mnt:[4026531840]
mnt:[4026531840]
Run Code Online (Sandbox Code Playgroud)

我还验证了 SE Linux 已启用:

# getenforce
Enforcing
Run Code Online (Sandbox Code Playgroud)

使用 CentOSdocker软件包运行您的命令时,我收到此错误消息:

$ docker run -it -v /proc/1/mounts:/tmp/mounts ubuntu:16.04
/usr/bin/docker-current: Error response from daemon: oci runtime error: container_linux.go:247: starting container process caused "container init exited prematurely".
Run Code Online (Sandbox Code Playgroud)

此外,在 中/var/log/audit/audit.log,我看到以下 AVC 违规:

type=AVC msg=audit(1555530383.707:214): avc:  denied  { mounton } for  pid=5691 comm="runc:[2:INIT]" path="/var/lib/docker/overlay2/8944062749f8ad19c3ff600e1d5286315227378174b95a952e7b0530927f4dcd/merged/tmp/mounts" dev="proc" ino=45422 scontext=system_u:system_r:container_runtime_t:s0 tcontext=system_u:system_r:init_t:s0 tclass=file permissive=0
Run Code Online (Sandbox Code Playgroud)

这告诉我们 SE Linux 规则不允许 container_runtime_t 类型的源上下文对“init_t”类型的目标上下文执行“mounton”操作。您可以验证这是 的上下文/proc/1/mounts,而/proc/$(pidof dockerd-current)/mounts匹配的上下文:

# ls -Z /proc/1/mounts /proc/$(pidof dockerd-current)/mounts
-r--r--r--. root root system_u:system_r:init_t:s0      /proc/1/mounts
-r--r--r--. root root system_u:system_r:container_runtime_t:s0 /proc/5476/mounts
Run Code Online (Sandbox Code Playgroud)