如何让Docker环境变量在容器构建和运行阶段均可用?
问题修复与优化方案
一、GitLab CI构建失败修复
失败原因
你本地通过docker-compose触发构建时,compose会自动将build.args下的参数传递给docker build进程,但GitLab CI的脚本中直接调用docker build命令,没有传递任何构建参数,导致Dockerfile里的ARG API_URL、ARG NEXT_PUBLIC_CLIENT_API_URL拿到的是空值。Next.js构建阶段如果存在预请求接口的逻辑(比如getStaticProps、服务端组件初始化请求),空的API_URL会默认指向127.0.0.1,就会抛出你遇到的连接拒绝错误。
修复步骤
- 先将
API_URL、NEXT_PUBLIC_CLIENT_API_URL两个变量配置到GitLab项目的CI/CD变量库中(路径:项目设置→CI/CD→变量,敏感值请不要勾选「暴露给管道日志」) - 修改CI脚本的
docker build命令,新增--build-arg传递构建参数:
... Build and Push App: image: docker:19.03.5 services: - docker:19.03.5-dind stage: Build and Push script: - apk add python3 - pip3 install awscli # 新增--build-arg传递构建参数,变量值从GitLab CI变量中读取 - docker build --compress \ --build-arg API_URL=$API_URL \ --build-arg NEXT_PUBLIC_CLIENT_API_URL=$NEXT_PUBLIC_CLIENT_API_URL \ -t $ECR_REPO:$CI_COMMIT_SHORT_SHA . - $(aws ecr get-login --no-include-email --region ap-south-1) - docker push $ECR_REPO:$CI_COMMIT_SHORT_SHA - docker tag $ECR_REPO:$CI_COMMIT_SHORT_SHA $ECR_REPO:latest - docker push $ECR_REPO:latest rules: - if: '$CI_COMMIT_BRANCH =~ /^(main|production)$/' ...
二、docker-compose重复传变量的问题
你本地需要同时传两次变量是正常逻辑,不存在冗余,两者作用阶段完全不同:
build.args下的变量是构建阶段使用,只会在docker build时传递给Dockerfile的ARG指令,容器运行时无法读取这些值environment下的变量是容器运行阶段使用,只会在容器启动时注入到容器的环境变量中,构建阶段完全看不到这些值
优化方案(避免重复写变量值)
可以通过.env文件统一管理所有变量,不需要在docker-compose里硬写两遍值:
- 项目根目录新建
.env文件:
API_URL=http://path-to-my-external-api-url NEXT_PUBLIC_CLIENT_API_URL=http://path-to-my-external-api-url NODE_ENV=production
- 修改docker-compose.yml,直接读取.env的变量:
version: "3.7" # 声明加载根目录.env文件,也可以省略不写,docker-compose默认会加载 env_file: .env services: app: container_name: frontend build: context: . args: - API_URL=${API_URL} - NEXT_PUBLIC_CLIENT_API_URL=${NEXT_PUBLIC_CLIENT_API_URL} environment: - NODE_ENV=${NODE_ENV} - API_URL=${API_URL} - NEXT_PUBLIC_CLIENT_API_URL=${NEXT_PUBLIC_CLIENT_API_URL} ports: - "3000:3000" nginx: depends_on: - app container_name: frontend-nginx build: ./nginx ports: - "8080:8080"
后续修改变量只要改.env文件即可,不需要调整docker-compose配置。
额外优化建议
- Dockerfile里的
ARG声明可以提前到对应FROM语句之后,避免不必要的分层缓存失效 NEXT_PUBLIC_开头的变量会被打包到客户端静态代码中,如果运行时不需要修改,运行时的environment可以不用传这个变量- 如果使用Next.js 13.4+版本,支持运行时公共变量替换,可以不用在构建阶段传
NEXT_PUBLIC_前缀变量,灵活度更高
内容的提问来源于stack exchange,提问作者dEBA M
相关产品推荐
相关产品推荐

