构建时要用私有仓库的凭据,怎么传才不会留在镜像里?这篇把三种做法(COPY 后删除、--build-arg、--mount=type=secret)的镜像都拆开,在配置、历史和每一层里搜索密钥字符串,并验证 secret mount 的缓存行为和失败方式。
[A:COPY 进去用完再 rm] 退出码 0;在镜像里找到密钥的位置:['层内文件 tmp/secret.txt']
[B:--build-arg] 退出码 0;在镜像里找到密钥的位置:['blobs/sha256/830e139dbb7f2422a(原始 blob/配置)'];docker history 里含密钥的行数 2
[C:RUN --mount=type=secret] 退出码 0;构建输出里:构建期读到了 18 字节
在镜像里找到密钥的位置:(没找到);docker history 里含密钥的行数 0
从镜像启动后 ls /run/secrets:ls: /run/secrets: No such file or directoryCOPY 进去再 rm,密钥留在较早的层里(层内文件 tmp/secret.txt,前面讲 whiteout 的那一篇说过,删除救不了);--build-arg 把值写进配置和 docker history;--mount=type=secret 只在构建的那一步里把密钥挂载成临时文件 /run/secrets/tok,镜像的所有层和配置里都搜不到它。
退出码 0;环境变量 TOKVAR 长度 17;镜像里的密钥位置:(没找到)
--secret id=tok,env=MYTOK 配 RUN --mount=type=secret,id=tok,env=TOKVAR,构建期的 TOKVAR 就是宿主机环境变量里的值(长度 17),同样不进镜像。
换了密钥内容(10 字节 → 35 字节)再构建:第 3 步 CACHED(命中缓存)
密钥内容不参与缓存键:换成完全不同的密钥,用到它的步骤仍然 CACHED。好处是密钥轮换不会让整条构建链重做;坏处是密钥变了你得自己想办法让它重建。
退出码 1;#5 ERROR: secret nope: not found | ERROR: failed to build: failed to solve: secret nope: not found 没写 required(默认可选):构建退出码 0;ls: /run/secrets/nope: No such file or directory | 退出码 1
默认挂载是可选的:没提供密钥,构建照样成功,只是文件不存在;写了 required=true 才会以 secret nope: not found 失败。命令依赖密钥时记得写 required。
RUN --mount=type=secret … cp /run/secrets/tok /app.conf:退出码 0;镜像里找到密钥的位置:['层内文件 app.conf']
cp /run/secrets/tok /app.conf 把内容写进了镜像的层里,密钥又泄漏了。secret mount 保证的是挂载本身不进镜像,不是命令的输出。