DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
雨云;给项目一台云服务器
RackNerd;$21.99/年 · 1GB KVM

COPY --link 写入 /tmp 后,apt 无法写临时文件

COPY 加上 --link 后,/tmp 从带 sticky bit 的模式变为 0755,apt 无法写临时文件。核对独立层的目录模式覆盖,避免只给文件加 chmod。

Dockerfile 给一条 COPY 加上 --link,后面的 apt 步骤开始无法写入 /tmp。如果复制前目录是 drwxrwxrwt,复制后却变成 drwxr-xr-x,先处理目录模式变化。文件复制成功并不表示它经过的父目录保留了基础镜像中的权限。

这里限定 Linux 镜像中的 BuildKit 构建。Docker Engine 23.0.0 和 BuildKit 0.11.2 环境已有上述目录变化;当前 --link 语义也要求注意目录模式覆盖,不能把升级某个版本当作必然修复。

比较目录,而不只检查复制的文件

在原 Dockerfile 相关步骤前后临时加入只读检查。以下用构建上下文中的 FILE.txt 说明位置,实际文件名需替换:

RUN ls -ldn /tmp
COPY --link FILE.txt /tmp/FILE.txt
RUN ls -ldn /tmp && ls -ln /tmp/FILE.txt

构建镜像需具备 ls。对照两次 /tmp 的数字属主和权限:drwxrwxrwt 对应带 sticky bit 的 01777;drwxr-xr-x 对应 0755。后一种模式中,非属主用户不能在目录里创建临时文件。不能把前一种简单记录成 0777,因为末尾的 t 也有用途。

如果模式没有改变,或失败目录不是 /tmp,继续按真实错误检查空间、只读挂载和执行身份,不要直接套用这个原因。

普通复制把文件放入已有文件系统;COPY --link 会先把文件复制到独立的空目录层,再把该层接到前面的镜像状态上。这个独立层中的 /tmp 是为目的路径隐式创建的目录,不会因为基础镜像已经有 /tmp,就读取并继承它的模式。

自动创建的目录使用 0755。独立层合并时,其目录模式可能覆盖基础镜像原有的模式。这也解释了为什么复制的文件本身可读,后续以非 root 身份运行的工具却不能创建临时文件。

给这一份文件加 COPY --chmod=0777,也不能保证隐式父目录变成同一模式;它调整的是复制对象。不要把整棵系统目录递归改成可写来处理一个目录的变化。

最小改动是让这条复制保留普通语义

如果这条复制不需要独立层复用,可以去掉它的 --link,保留原来源、目的路径和其他必要参数:

COPY FILE.txt /tmp/FILE.txt

这是原步骤的替换片段,不是完整业务镜像。重新检查 /tmp 是否保留基础镜像要求的模式。若复制的是整个目录,其源目录模式仍可能影响目标,不能把普通复制理解成绝不改变目录属性。

另一种选择是把业务文件放在专用目录,避免通过 /tmp 承接独立层;修改前核对后续命令的读取路径和所需权限。只有确实需要恢复 /tmp 原模式、并已确认原设计为 01777 时,才在有权限的构建步骤中针对该目录恢复模式,随后恢复原运行用户。不要省略 sticky bit,也不要把这一处理扩大到其他目录。

构建后核对目录模式、实际运行身份和原先失败的 apt 步骤;最终应用也应能正常使用临时目录。移除诊断步骤前保存检查结果,保留原 Dockerfile 和旧镜像用于回退。这个修复改变新镜像的构建内容,不需要清理运行数据卷。