docker-compose构建阶段能否访问环境变量与容器网络
docker-compose构建阶段无法访问内部容器与环境变量问题
问题描述
在docker-compose镜像构建阶段,尝试读取环境变量、通过docker内部网络访问同网络下的其他容器时始终失败:
- 容器启动后
CMD指令执行阶段,网络访问、环境变量读取均正常 - 镜像构建过程中
RUN指令执行阶段,两类操作均无法生效
已知诉求
- 环境变量:已知可通过Dockerfile内
ENV声明、build args传参的方式让RUN阶段读取变量,但数据库密码类敏感信息不希望通过这类方式传递 - 网络访问:构建过程不需要访问宿主机外部公网,仅需要通过docker内部网络与其他依赖容器通信
- 执行流程:观察到docker-compose默认先执行全量镜像构建,再创建自定义网络、启动依赖容器,期望实现自定义网络与依赖容器启动完成后,再执行app服务的构建步骤;同时需要明确compose中
environment配置的环境变量在构建阶段无法读取的原因
最小复现
复现命令:docker-compose up --build
docker-compose.yml
version: "3.9" services: app: build: context: . dockerfile: test.Dockerfile args: CACHE_BUST: 1 environment: - MYENV=good1 links: - redis depends_on: - redis networks: back-net: {} redis: image: "redis:bullseye" networks: back-net: {} networks: back-net: driver: bridge
test.Dockerfile
FROM debian:bullseye-slim RUN apt-get update && apt-get -y install iputils-ping RUN echo $CACHEBUST && echo "ENV " && echo $MYENV && echo "RUN HOSTS:" && cat /etc/hosts && echo "RUN PING:" && ping -c 2 redis; exit 0 CMD echo "ENV " && echo $MYENV && echo "CMD HOSTS:" && cat /etc/hosts && echo "CMD PING:" && ping -c 2 redis
根本原因
- 环境变量隔离
docker-compose中service层级的environment配置属于容器运行时配置,仅会在容器启动阶段注入到容器进程环境中,对镜像构建阶段完全不可见。镜像构建是独立于容器运行的流程,默认仅能读取Dockerfile内ENV指令定义的变量、build段传入的args参数,不会加载任何运行时配置。 - 网络与执行顺序问题
docker-compose默认执行生命周期顺序固定:
- 解析全量compose配置,收集所有待构建的镜像
- 逐个执行所有服务的镜像构建,构建阶段默认使用docker全局默认bridge网络
- 所有镜像构建完成后,才会创建项目专属自定义网络、按依赖顺序启动各服务容器
也就是说构建阶段,自定义网络back-net还未创建,redis容器也未启动,自然无法通过内部域名访问依赖服务。
解决方案
调整执行顺序,先启动依赖与网络
放弃docker-compose up --build的全量一键执行逻辑,先单独启动依赖服务与对应网络:
# 后台启动redis服务,自动创建关联的back-net网络 docker-compose up -d redis
指定构建阶段接入已存在的内部网络
修改app服务的build配置,添加network参数,让构建过程直接接入已经创建好的项目内部网络,不需要访问外部公网:
services: app: build: context: . dockerfile: test.Dockerfile args: CACHE_BUST: 1 # 指定构建阶段使用的网络,替换为实际的compose网络名 network: "【你的项目目录名】_back-net" # 其余配置保持不变
网络名默认规则为
[compose项目根目录名]_back-net,可执行docker network ls查看实际名称后填入。
配置完成后单独执行app服务的构建与启动:
docker-compose up -d --build app
敏感信息传递方案
不要通过build args传递数据库密码类敏感信息——build args会被记录到镜像历史中,只要拿到镜像就能反向查看到参数值,存在泄露风险。
更安全的实践是:
- 把需要访问敏感信息、连接依赖服务的逻辑,从构建阶段的
RUN指令移到容器启动后执行的ENTRYPOINT/CMD脚本中,运行时通过environment注入敏感变量,不会被写入镜像层 - 如果确实必须在构建阶段读取敏感信息,可在构建时通过宿主机临时环境变量注入,不要将敏感值写入compose配置或Dockerfile;也可以在构建阶段通过已经启动的内部依赖服务,拉取需要的敏感配置,全程不经过外部网络。
内容的提问来源于stack exchange,提问作者user16551018
相关产品推荐
相关产品推荐

