运行 containerd 的 ctr 通过 uidmap 映射到主机上的非 root 用户的容器

run container with containerd's ctr by means of uidmap to map to non-root user on the host

为了更好地理解如何将 --uidmapctr 一起使用,我通过以下步骤创建了一个测试容器。 containerd 版本是 1.4.3.

构建和运行容器:

  1. 构建 Dockerfile
    $ cat Dockerfile
    FROM alpine
    ENTRYPOINT ["/bin/sh"]
    
    $ docker build -t test .
    Sending build context to Docker daemon  143.1MB
    Step 1/2 : FROM alpine                         
     ---> d6e46aa2470d                             
    Step 2/2 : ENTRYPOINT ["/bin/sh"]              
     ---> Running in 560b09f9b287                  
    Removing intermediate container 560b09f9b287   
     ---> 8506bfeab109                             
    Successfully built 8506bfeab109                
    Successfully tagged test:latest                
    
  2. 将图像保存为 tar 球
    $ docker save test > test.tar
    
  3. 使用 containerd 导入它 ctr
    $ sudo ctr i import test.tar
    unpacking docker.io/library/test:latest (sha256:9f7dabf0e4feadbca9bdc180422a3f2cdd7b545445180a3c23de8129dc95f29b)...done
    
  4. 创建并运行容器
    $ sudo ctr run --uidmap 0:5000:4999 docker.io/library/test:latest test
    
    uid 映射应将容器内部 uid 0(root)映射到对应于 ctr 的联机帮助页的 5000:

    --uidmap="": run inside a user namespace with the specified UID mapping range; specified with the format container-uid:host-uid:length

检查容器和主机上的 UID:

容器内:

ps -eo ruser,rgroup,comm 
RUSER    RGROUP   COMMAND
root     root     sh     
root     root     ps     

在主机上:

$ ps -eo uid,gid,cmd | grep /bin/sh
  126   128 /bin/sh /usr/lib/lightdm/lightdm-greeter-session /usr/sbin/unity-greeter
    0     0 /bin/sh

问题

它似乎不起作用,/bin/sh 运行在容器内和主机上作为 root (uid=0)。

我搜索了一段时间,直到我检查了 containerd 的代码并在 cmd/ctr/commands/run/run_unix.go:

中找到了这个
149       if uidmap, gidmap := context.String("uidmap"), context.String("gidmap"); uidmap != "" && gidmap != "" {
150         uidMap, err := parseIDMapping(uidmap)
151         if err != nil {
152           return nil, err
153         }
154         gidMap, err := parseIDMapping(gidmap)
155         if err != nil {
156           return nil, err
157         }

这基本上意味着: uidmap AND gidmap 两者都必须提供,否则无法正常工作。

运行 上面的容器再次用

$ sudo ctr run --uidmap 0:5000:4999 --gidmap 0:5000:4999 docker.io/library/test:latest test

成功了。

容器内:

ps -eo ruser,rgroup,comm  
RUSER    RGROUP   COMMAND 
root     root     sh      
root     root     ps      

在主机上:

$ ps -eo uid,gid,cmd | grep /bin/sh
  126   128 /bin/sh /usr/lib/lightdm/lightdm-greeter-session /usr/sbin/unity-greeter
 5000  5000 /bin/sh