作为我正在为Linux容器系统(如docker和containerd/runc)开发容器诊断工具的工作的一部分,我一直在寻找一种方法,将一个挂载名称空间中的挂载注入或绑定到另一个不相交的挂载名称空间中。
问题陈述
请考虑以下场景
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/container 2-root中的文件系统对container 1的名称空间mount namespace 2中运行的进程可见,例如,这样container1
中的进程可以访问通常不包括在其容器映像中的附加注入工具或实用程序,并且它们可以看到pidns 2(container 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
可见的绑定挂载,但它不会看到原始container 1 pid名称空间中的任何进程,也不会看到/c1volume
的挂载。
我已经尝试了很多变化的技巧与pivot_root
,unshare
,nsenter
,mount -o bind
等,但尚未无济于事。container1
的leader进程(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 # '
演示
现在,通过主机,您将看到
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
c1体积不可见,且
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
首先输入container 1的挂载名称空间,则container 2根文件系统将不再可见,因此无法绑定挂载。
1条答案
按热度按时间knsnq2tg1#
所以我当然是在最终写完这个之后才算出来的。至少对于我的演示env来说,我必须和一个真实的的containerd进行比较才能看到。
诀窍是没有
--root
或--wd
的nsenter
将保留在主机根目录和工作目录中,但输入访客挂载名称空间。* 没有必要同时输入访客(container1)pid名称空间 *。现在在
container1
的会话中: