首页 > 解决方案 > 如何使用 --uidmap/gidmap 和 --net-host 选项正确运行具有 containerd 的 ctr 的容器

问题描述

我正在运行一个容器,ctr使用用户命名空间将容器内的用户(根)映射到主机上的另一个用户,我想让主机网络可用于容器。为此,我正在使用该--net-host选项。基于一个非常简单的测试容器

$ cat Dockerfile
FROM alpine
ENTRYPOINT ["/bin/sh"]

我试试

sudo ctr run -rm --uidmap "0:1000:999" --gidmap "0:1000:999" --net-host docker.io/library/test:latest test

这给了我以下错误

ctr: OCI runtime create failed: container_linux.go:349: starting container process caused "process_linux.go:449: container init caused \"rootfs_linux.go:58: mounting \\\"sysfs\\\" to rootfs \\\"/run/containerd/io.containerd.runtime.v2.task/default/test/rootfs\\\" at \\\"/sys\\\" caused \\\"operation not permitted\\\"\"": unknown

如果我要么一切正常

  1. 删除--net-host标志或
  2. 删除--uidmap/--gidmap参数

我尝试将具有主机的用户添加uid=1000netdev组中,但仍然出现相同的错误。我可能需要使用网络命名空间吗?

编辑:

同时发现这是内部的一个问题runc。如果我通过将以下内容添加到config.json

    "linux": {
        "uidMappings": [
            {
                "containerID": 0,
                "hostID": 1000,
                "size": 999
            }
        ],
        "gidMappings": [
            {
                "containerID": 0,
                "hostID": 1000,
                "size": 999
            }
        ],

另外不要使用网络命名空间,这意味着省略条目

            {
                "type": "network"
            },

在该"namespaces"部分中,我收到以下错误runc

$ sudo runc run test
WARN[0000] exit status 1
ERRO[0000] container_linux.go:349: starting container process caused "process_linux.go:449: container init caused \"rootfs_linux.go:58: mounting \\\"sysfs\\\" to rootfs \\\"/vagrant/test/rootfs\\\" at \\\"/sys\\\" caused \\\"operation not permitted\\\"\""
container_linux.go:349: starting container process caused "process_linux.go:449: container init caused \"rootfs_linux.go:58: mounting \\\"sysfs\\\" to rootfs \\\"/vagrant/test/rootfs\\\" at \\\"/sys\\\" caused \\\"operation not permitted\\\"\""

标签: containerslinux-namespacescontainerdrunc

解决方案


终于从这个问题中runc找到了答案。这基本上是内核中的一个限制,即不拥有网络命名空间的用户没有CAP_SYS_ADMIN能力,没有能力就无法挂载sysfs。由于容器内的 root 用户映射到的主机上的用户没有创建主机网络命名空间,因此它没有CAP_SYS_ADMIN

issuerunc讨论中,我现在确实看到了以下选项:

  1. 删除安装sysfs

    config.jsonthatrunc使用中,删除以下部分"mounts"

            {
            "destination": "/sys",
            "type": "sysfs",
            "source": "sysfs",
            "options": [
                "nosuid",
                "noexec",
                "nodev",
                "ro"
            ]
        },
    

    就我而言,我也无法 mount /etc/resolv.conf。通过删除这 2 个,容器确实运行良好并具有主机网络访问权限。不过,这不起作用ctr

  2. 设置从主机网络命名空间到容器网络空间的桥接(参见此处slirp4netns)。

  3. 如果可能的话,使用 docker 或 podman 似乎为此目的使用slirp4netns 。一个老白鲸问题也可能很有趣。


推荐阅读