将挂载注入到私有挂载传播后面的不连续挂载命名空间中?

4
作为我正在为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/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_rootunsharensentermount -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中现有的进程中看到。如果首先使用nsenterunshare进入容器1的挂载命名空间,则无法再看到container2-root文件系统,因此无法进行绑定挂载。

1个回答

2
当然,在我最终完成这篇文章后,我解决了这个问题。至少对于我的演示环境,我需要与一个真正的containerd进行比较才能确定。
关键是,没有任何--root--wd选项的nsenter将保留在主机根目录和工作目录中,但进入Guest挂载名称空间。无需进入Guest(container1)pid命名空间。
host # c1leader="$(lsof -t containers/container1-root)"
host # nsenter -t $c1leader -m
host # findmnt -o +PROPAGATION | egrep 'container[12]|c1volume'
├─/root/containers/container1-root                  overlay                                           overlay         rw,relatime,lowerdir=/root/images/container1-root,upperdir=/root/scratch/container1-root,workdir=/root/workdirs/container1-root private
│ ├─/root/containers/container1-root/c1volume       /dev/mapper/vgubuntu-root[/root/volumes/c1volume] ext4            rw,relatime,errors=remount-ro                                                                                                   private
│ ├─/root/containers/container1-root/proc           proc                                              proc            rw,nosuid,nodev,noexec,relatime                                                                                                 private
│ │ └─/root/containers/container1-root/proc         none                                              proc            rw,relatime                                                                                                                     private
│ └─/root/containers/container1-root/sys            none                                              sysfs           rw,relatime                                                                                                                     private
└─/root/containers/container2-root                  overlay                                           overlay         rw,relatime,lowerdir=/root/images/container2-root,upperdir=/root/scratch/container2-root,workdir=/root/workdirs/container2-root private
host # mkdir /root/containers/container1-root/container2-root
host # mount -o bind,ro /root/containers/container2-root /root/containers/container1-root/container2-root

现在在container1的会话中:

container1 # ls /
bin              c1volume         container1       container2-root  dev              enter            etc              foo              proc             sys
container1 # ls /c1volume/
i-see-c1volume
container1 # ls container2-root/
bin         container2  dev         enter       etc         proc        sys
container1 # busybox ps
PID   USER     TIME  COMMAND
    1 0         0:00 /bin/busybox sh -i
   24 0         0:00 busybox ps

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接