密钥应仅在构建时通过arg临时接收、绝不写入env或run,运行时再通过--env-file或--secret挂载注入;arg不设默认值,多阶段中限作用域,宿主机密钥文件需严格权限。

核心是让密钥只出现在构建过程里,但绝不固化进镜像层——ARG负责“临时接收”,ENV负责“运行时配置”,而密钥本身必须绕过这两者直接注入运行时。
用ARG接收但不落地
在Dockerfile中声明ARG用于构建时传入密钥,但绝不把它赋值给ENV,也不在RUN指令中明文拼接使用:
- 正确写法:
ARG API_KEY(仅声明,不设默认值,避免误留空字符串) - 错误写法:
ENV API_KEY=${API_KEY}或RUN curl -H "X-Key: $API_KEY" ... - 原因:一旦写入ENV,
docker inspect就能看到;若在RUN中直接引用,命令行可能被缓存层记录,历史可追溯
构建时用--build-arg传参,且限定作用域
通过命令行传入密钥,仅在需要它的构建阶段生效,其他阶段不声明、不传递:
- 多阶段构建中,只在第一阶段(如builder)声明
ARG API_KEY,第二阶段(如runtime)不声明也不使用 - 构建命令示例:
docker build --build-arg API_KEY=$(cat ./secret.key) -t myapp . - 注意:宿主机上确保
secret.key权限严格(如chmod 600),且不在.gitignore之外提交
运行时才加载密钥,用--env或--env-file
最终容器启动时,再把密钥作为环境变量注入,它不会出现在镜像任何一层中:
- 启动命令:
docker run --env-file ./prod.env myapp(prod.env含API_KEY=xxx) - 或更安全方式:
docker run --mount type=secret,source=mykey,target=/run/secrets/api_key myapp(需Docker Swarm或启用buildkit) - 应用代码中统一从
process.env.API_KEY或/run/secrets/api_key读取,不依赖构建时值
替代方案:用构建脚本动态注入,避开ARG明文
如果CI/CD流水线支持,可跳过ARG,改用shell脚本生成临时配置文件,再COPY进镜像(不带密钥):
- 例如:构建前用脚本生成
config.json.template,用sed替换占位符,但密钥由运行时挂载的配置文件覆盖 - 关键点:Dockerfile中只COPY不含密钥的模板,敏感内容由
docker run -v或--env-file提供 - 这样ARG完全不用接触密钥,彻底规避泄露路径











