作为我正在为Linux容器系统(如docker和containerd/runc)开发的容器诊断工具的一部分,我一直在寻找一种将一个挂载命名空间中的挂载点注入或绑定到另一个不相交的挂载命名空间中的方法。
问题陈述:
考虑以下场景。
改变
我可以创建一个新的挂载和进程命名空间,它可以将
我已经尝试了许多变化的技巧,包括
演示设置
这是一个设置说明,用于使用低级Linux原语手动创建容器化的演示环境,以便您可以看到发生了什么。
问题陈述:
考虑以下场景。
hostdir nsdir
------- -----
/ / [mountns 1, pidns 1, ]
/var/containers/container1-root / [mountns 2, pidns 2, propagation=private]
[not visible] /c1volume [mountns 2, pidns 2]
/var/containers/container2-root / [mountns 3, pidns 1, propagation=private] privileged]
container1
是一个普通的容器,它挂载了c1volume
卷。由于挂载传播规则,主机无法看到c1volume
,因为它是在进入新的挂载命名空间后挂载的。
container2
使用主机的pid命名空间运行,因此它可以“看到”容器外部与主机交互。它是特权容器,并且可以使用nsenter
进入主机挂载命名空间。
目标是使/var/container/container2-root文件系统对运行在容器1的命名空间、挂载命名空间2中的进程可见,例如,以便容器1中的进程可以访问不通常包含在其容器镜像中的其他注入工具或实用程序,并且他们看到pidns 2(容器1)的pid号。
我还没有找到一种方法来实现这个目标。
挂载传播规则意味着从主机的挂载命名空间进行绑定挂载不会使绑定挂载对container1
挂载的命名空间中的进程可见:
mkdir /var/containers/container1-root/container2
mount -o bind /var/containers/container2-root /var/containers/container1-root/container2
改变
/var/containers/container1-root
的挂载传播似乎没有任何效果。我可以创建一个新的挂载和进程命名空间,它可以将
/var/containers/container1-root
视为/
并且对于/var/containers/container2-root
有一个可见的绑定挂载,但是它不会看到原始container1进程的pid命名空间中的任何进程,并且不会看到/c1volume
的挂载。我已经尝试了许多变化的技巧,包括
pivot_root
、unshare
、nsenter
、mount -o bind
等,但至今没有成功。
container1
的领导进程(pid 1)不可用;这是从容器工具层进行的外部注入。演示设置
这是一个设置说明,用于使用低级Linux原语手动创建容器化的演示环境,以便您可以看到发生了什么。
# create "container images" (static)
mkdir images
cd images
mkdir -p container1-root/{bin,proc,sys,dev,etc}
curl -sSLf -o container1-root/bin/busybox busybox https://busybox.net/downloads/binaries/1.35.0-x86_64-linux-musl/busybox
chmod +x container1-root/bin/busybox
for cmd in ls mount sh ; do ln -s busybox container1-root/bin/$cmd; done
cat > container1-root/enter <<'__END__'
#!/bin/sh
mount -t sysfs none /sys
exec /bin/busybox sh -i
__END__
chmod +x container1-root/enter
cp -aR container1-root container2-root
touch container1-root/container1
touch container2-root/container2
mkdir container1-root/c1volume
cd ..
# Create a volume for c1
mkdir -p volumes/c1volume
touch volumes/c1volume/i-see-c1volume
# create the container runtime dirs
for c in container1-root container2-root; do
mkdir -p {containers,workdirs,scratch}/$c
mount -t overlay overlay -o lowerdir=$PWD/images/$c,upperdir=$PWD/scratch/$c,workdir=$PWD/workdirs/$c $PWD/containers/$c
mount --make-rprivate $PWD/containers/$c
done
# [Terminal session 1: container1]
# Launch container1, with mounted volume not visible to the host and new pid namespace.
unshare -m
mount -o bind volumes/c1volume containers/container1-root/c1volume
ls containers/container1-root/c1volume/
unshare -p -m --mount-proc --fork --propagation private --wd=containers/container1-root --root=containers/container1-root /enter
PS1='container1 # '
ls /c1volume
echo $$
# [Terminal session 2: container2]
# This container shares the host pid namespace, but not mount namespace, and does not
# have a mounted volume.
unshare -m
unshare -m --mount-proc --fork --propagation private --wd=containers/container2-root --root=containers/container2-root /enter
PS1='container2 # '
Demo
Now, from the host, you will see
host # findmnt | egrep 'c1volume|container[12]'
├─/root/containers/container1-root overlay overlay rw,relatime,lowerdir=/root/images/container1-root,upperdir=/root/scratch/container1-root,workdir=/root/workdirs/container1-root
└─/root/containers/container2-root overlay overlay rw,relatime,lowerdir=/root/images/container2-root,upperdir=/root/scratch/container2-root,workdir=/root/workdirs/container2-root
没有看到任何 c1volume,并且
host # ls /root/containers/container1-root/c1volume/
host #
它的绑定挂载内容是不可见的。
容器2中的进程可以进行容器突破,然后使用nsenter
进入容器2:
container2 # /bin/busybox nsenter -t 1 -m -p /bin/bash -w /root
host # nsenter -t "$(lsof -t containers/container1-root)" --all -w -r /bin/sh
# ls /c1volume
i-see-c1volume
但是没有办法从那里访问container2-root
。
可以通过mount -o bind
挂载到/proc/$(lsof -t containers/container1-root)/root/
中,但是由于挂载传播的原因,这不会从container1-root
中现有的进程中看到。如果首先使用nsenter
或unshare
进入容器1的挂载命名空间,则无法再看到container2-root文件系统,因此无法进行绑定挂载。