DEBUG.WIKI
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国

RUN 的 bind 挂载加了 rw,下一步文件仍消失

构建 bind 挂载加 rw 后生成的文件仍在下一步消失:挂载写入不会提交镜像层。产物须在当前 RUN 结束前写到挂载外,再进入最终阶段。

一条 RUN --mount=type=bind,...,rw 成功生成文件,同一步的 ls 也能看到;下一条 RUN 再挂载同一个目录,文件却不见了。构建时的 bind 挂载允许写入,不代表这些写入会回到宿主机或提交到镜像层。

BuildKit 的规则是:写入 bind 挂载的内容在该条 RUN 结束后丢弃。Colima 0.6.10 环境中也出现过这个现象,但不能据此归因于 Colima 的文件共享故障,或者承诺升级 Colima 就能保存产物。

rw 只改变当前步骤的写权限

下面是说明现象的 Dockerfile,不是业务发布镜像。构建上下文需有 mod 目录:

# syntax=docker/dockerfile:1
FROM alpine:3.22
RUN --mount=type=bind,source=mod,target=/mod,rw \
    touch /mod/generated.txt && ls -l /mod
RUN --mount=type=bind,source=mod,target=/mod,rw \
    ls -l /mod

第一步写入的是临时挂载里的文件;第二步重新得到构建上下文中的 mod,不会继承上一条指令的挂载写入。去掉 rw 后,挂载默认只读,原写入操作还可能直接报只读文件系统错误。允许写与保存写入是两个独立条件。

运行容器时的宿主机 bind 挂载具有不同的数据关系,不能拿其写回行为解释 Dockerfile 的构建挂载。这里也不是 shell 的 cd 没有跨指令保留:消失的是挂载中的数据。

在当前 RUN 结束前,把产物写到挂载之外

如果工具支持指定输出目录,直接输出到镜像文件系统中不属于任何临时挂载的位置。若只能在源目录生成,就在同一条 RUN 中复制出来。下面继续用空文件说明路径关系:

# syntax=docker/dockerfile:1
FROM alpine:3.22 AS build
RUN --mount=type=bind,source=mod,target=/mod,rw \
    touch /mod/generated.txt && \
    mkdir -p /out && cp /mod/generated.txt /out/generated.txt
RUN test -f /out/generated.txt

FROM alpine:3.22
COPY --from=build /out/generated.txt /app/generated.txt

/out 在示例中属于构建阶段的普通文件系统,实际项目要确认它没有落在另一个 bind、cache 或 tmpfs 挂载中,且执行用户有写权限。复制必须发生在当前挂载仍有效时;到下一条 RUN 再从临时目录复制,产物已经没有了。

镜像中的目标路径若已有文件,挂载还可能在当前步骤暂时遮住它们。检查时同时核对挂载位置和实际输出位置,不要把被遮住的基础文件误当作被删除。

cache 也不适合保存唯一交付产物

cache 挂载可以加速编译或依赖下载,但内容可能被其他构建改变,也可能被垃圾回收清理。把 bind 改成 cache,不等于产物已经进入最终镜像。

需要发布的文件仍应从挂载中写到普通镜像文件系统,再从对应阶段取出。若文件在上一阶段的普通路径中确实存在,而 COPY 仍找不到,应另外检查普通 COPY 与跨阶段来源;这里的关键是先保证文件没有随着临时挂载结束而丢弃。

核对成功需要覆盖两个位置:后续构建步骤能读取持久路径,最终阶段也含有应用需要的文件。不要只用生成命令返回 0 判断交付完整。保留原 Dockerfile 和旧镜像,先验证新产物再安排部署;回退使用原镜像,无需清空全局构建缓存或删除运行数据卷。