给镜像加一行 USER 就算「非 root」了吗?COPY 进来的文件归谁?uid 在 /etc/passwd 里没有会怎样?USER 之后的构建步骤会遇到什么?这篇逐项实测。
docker inspect 的 Config.User = app 默认 CMD 的输出:uid=10001(app) gid=10001(app) groups=10001(app),10001(app) ; HOME=/home/app ; app CapEff / CapBnd:CapEff: 0000000000000000 CapBnd: 00000000a80425fb 写 /tmp、写 /、写 /etc/x、写 $HOME:/tmp/x 成功; /x 失败; /etc/x 失败; /home/app/x 成功
USER app 后,进程的 uid/gid 是 10001,有效 capability 为空,只能写 /tmp 和 HOME 这类 app 自己的目录。边界集合 CapBnd 仍然是 14 个,但没有有效权限就用不上(c40)。
0:0 /srv ; 10001:10001 /srv/owned.txt ; 0:0 /srv/plain.txt ; 0:0 /srv/root.txt ; 10001:10001 /srv/work USER app 之后 WORKDIR /srv/work 创建出来的目录属主:10001:10001 以 app 身份往 /srv/work 里写文件:成功 以 app 身份修改 COPY 进来的 /srv/plain.txt(root 属主)和 /srv/owned.txt(app 属主):sh: can't create /srv/plain.txt: Permission denied ; owned可写
COPY 默认把文件归 root,即使前面有 USER。要让应用能改自己的文件,要写 COPY --chown=用户:组;WORKDIR 在 USER 之后创建的目录则属于该用户。
--user root:uid=0(root) gid=0(root) groups=0(root),0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video) ; root --user 12345(passwd 里没有):uid=12345 gid=0(root) groups=0(root) ; HOME=/ ; whoami: unknown uid 12345 --user 12345:0(加上 root 组):uid=12345 gid=0(root) groups=0(root) --user app:10001;--user 10001:app
--user 可以用名字或数字;uid 在 /etc/passwd 里没有时,id 仍然能用,但没有用户名、HOME 是 /,gid 默认 0(root 组)——这个组默认 0 值得注意。
USER 10002 之后的 RUN:构建退出码 0;构建输出里的相关行:["/bin/sh: can't create /who: Permission denied", '#7 [4/4] RUN mkdir /out 2>&1 || echo "mkdir /out 失败"', "mkdir: can't create directory '/out': Permission denied", 'mkdir /out 失败'] 这个镜像里 /who、/out 存在吗?ls: /who: No such file or directory ; ls: /out: No such file or directory RUN 里的 id -u(构建时的用户):构建时 USER 10002 生效,所以写 / 失败
USER 从它出现的那一行开始对后面的 RUN 生效。需要 root 的步骤(装包、建目录)要放在 USER 之前。