容器里的 uid 和宿主机的 uid 是什么关系?为什么有时候卷里的目录非 root 用户写不进去?这篇分别在 bind mount 和命名卷上实测文件属主的映射规则。
容器里 root(uid 0)创建的 by-root.txt,在宿主机上:uid=501 gid=20 mode=0o644 宿主机创建的 by-host.txt(宿主机上 uid=501 gid=20 mode=0o640),容器里 ls -ln:-rw-r----- 1 0 0
容器里 root 创建的文件,在宿主机上归宿主机用户(uid 501);宿主机用户的文件在容器里显示成 root 的(0 0)。这是 Docker Desktop 在 macOS 上的行为,不能推广到 Linux 宿主机——Linux 上 bind mount 的 uid 是原样的,我没有测。
宿主机目录 mode 755、属主是宿主机用户:--user 1000 写入 → 退出码 0;写成功 文件在宿主机上:uid=501 gid=20 mode=0o644 容器里 chown 1234:1234 并 chmod 600 之后,容器里看:-rw------- 1234 1234;宿主机上:uid=501 gid=20 mode=0o600
uid 1000 的容器用户可以往宿主机上 755、属主是宿主机用户的目录里写文件;容器里 chown 1234:1234 之后容器里看到 1234,宿主机上仍是 501;chmod 600 则在宿主机上也生效。也就是说,在这种 bind mount 上不要指望靠 uid 做访问控制。
镜像里 /rootonly 属主是 root(0:0):空命名卷挂上去,--user 1000 → 退出码 1;drwxr-xr-x 0 0 | sh: can't create /rootonly/f.txt: Permission denied 镜像里 /owned 属主是 1000:1000(并含 seed.txt):空命名卷挂上去,--user 1000 → 退出码 0;drwxr-xr-x 1000 1000 | 1000:1000 /owned/seed.txt | 写成功 事后用 root chown 1000:1000 这个卷的根目录(drwxr-xr-x 1000 1000),再用 --user 1000 写入 → 写成功
空命名卷第一次挂载时,镜像里该目录的内容连同属主一起复制进卷(根目录本身也一样)。镜像里目录是 root 的,非 root 的容器用户就写不进去;在 Dockerfile 里先 chown 目录是一种做法,事后用 root 容器 chown 卷的根目录是另一种。
Docker Desktop 虚拟机里 /var/lib/docker/volumes/bwlab-c23-owned/_data:-rw-r--r-- 1 1000 1000 f.txt ; -rw-r--r-- 1 1000 1000 seed.txt
进入虚拟机看卷的目录,文件属主就是 1000 1000,没有映射。所以同一个命名卷换一个 uid 不同的镜像去用,就可能遇到权限问题(本文没有演示这个场景)。