Docker Compose 环境变量配置实战:三种方式与避坑指南

主题: docker-compose-env-variable-not-loading更新于: 2026/6/30作者:AgentFactory 技术团队

在 Docker Compose 编排多容器应用时,环境变量配置是连接服务、注入配置、管理敏感信息的关键环节。很多开发者会遇到变量不生效、覆盖顺序混乱、敏感信息泄露等问题。本文将从配置方式、优先级规则、常见报错三个维度,给出可直接落地的解决方案。

它解决什么问题 / 适用场景

Docker Compose 环境变量机制解决的核心问题是:如何为不同服务(Web 应用、数据库、缓存等)动态注入配置,同时保持 compose.yaml 的通用性。典型场景包括:

  • 开发环境快速切换:通过 .env 文件切换数据库连接串、API 端点等配置,无需修改 compose.yaml
  • CI/CD 流水线注入:在构建阶段通过 shell 环境变量或命令行参数注入构建号、版本标签等。
  • 敏感信息分离:将密码、密钥等敏感信息从代码仓库中剥离,通过外部文件或 secrets 管理。

Docker Compose 提供了三种互补的变量设置方式,支持变量插值(interpolation)、多文件覆盖、可选文件(required: false)以及替代文件格式(format),在灵活性和安全性之间取得了良好平衡。

核心配置 / 参数说明

Docker Compose 支持三种环境变量配置方式,各有适用场景。下表对比了它们的核心差异:

配置方式定义位置变量作用域安全性灵活性
environmentcompose.yaml 内联服务级低(明文在 YAML 中)高(支持列表和映射语法)
env_file外部 .env 文件服务级中(文件可设置权限)高(支持多文件、可选文件、格式选择)
-e / --env命令行临时服务级中(可能暴露在 shell 历史)中(适合临时调试)

1. environment 属性

直接在 compose.yaml 的服务定义中设置环境变量,支持两种语法:

YAML
# 映射语法(推荐)
services:
  web:
    image: nginx:alpine
    environment:
      DEBUG: "true"
      APP_ENV: production
      DB_URL: "postgres://user:pass@db:5432/mydb"

# 列表语法(等效)
services:
  web:
    image: nginx:alpine
    environment:
      - DEBUG=true
      - APP_ENV=production
      - DB_URL=postgres://user:pass@db:5432/mydb

注意:映射语法中,值必须用引号包裹(如 "true"),否则 YAML 解析器可能将 true 解释为布尔值。列表语法中,值不需要引号,但等号两边不能有空格。

2. env_file 属性

引用外部 .env 文件,适合管理大量变量或在不同服务间共享同一组变量:

YAML
services:
  web:
    image: nginx:alpine
    env_file:
      - path: ./common.env
        required: true
      - path: ./optional.env
        required: false   # 从 Docker Compose 2.24.0 开始支持
      - path: ./app.env
        format: properties  # 支持 properties 格式(默认是 env 格式)

关键细节

  • env_file 的路径是相对于 compose.yaml 文件的,而非当前工作目录。
  • 多文件覆盖时,后指定的文件会覆盖先指定的文件中的同名变量。
  • 从 Docker Compose 2.24.0 开始,可以设置 required: false 使文件可选,避免文件不存在时报错。

3. -e / --env 命令行参数

通过 docker compose run 命令临时设置环境变量,适合调试或一次性任务:

BASH
# 设置单个变量
docker compose run -e DEBUG=1 web

# 从 shell 环境传递变量(不赋值)
export MY_SECRET="s3cr3t"
docker compose run -e MY_SECRET web

# 从环境文件传递
docker compose run --env-file ./extra.env web

注意:使用 -e VARIABLE(不赋值)时,如果 shell 环境中未设置该变量,不会报错,但容器内该变量会为空。

变量优先级与覆盖规则

理解 Docker Compose 的变量优先级至关重要,否则很容易出现“我明明设置了,为什么容器里没有”的问题。

优先级从高到低

  1. docker compose run -e 命令行参数
  2. environment 属性(compose.yaml 内联)
  3. env_file 属性(外部文件)
  4. .env 文件(项目根目录,用于变量插值)

变量插值(Interpolation):在 compose.yaml 中使用 ${VARIABLE} 语法时,Docker Compose 会从以下位置查找变量值(按优先级从高到低):

  1. 当前 shell 环境变量
  2. 项目根目录下的 .env 文件
  3. 如果都找不到,Compose 会发出警告,并将变量替换为空字符串
YAML
# compose.yaml
services:
  web:
    image: nginx:alpine
    environment:
      - APP_ENV=${APP_ENV:-development}  # 默认值语法
      - DB_URL=${DB_URL}
BASH
# .env 文件(项目根目录)
APP_ENV=staging
DB_URL=postgres://user:pass@db:5432/mydb

重要限制:变量插值仅在 Docker Compose CLI 中生效,不适用于 docker run --env-file

常见报错与排查

1. 环境变量未生效,容器内变量为空

报错现象:容器启动后,应用读取不到预期的环境变量。

排查步骤

  1. 检查 compose.yamlenvironmentenv_file 的配置是否正确。
  2. 如果使用 -e VARIABLE(不赋值),确保 shell 环境中已设置该变量。
  3. 如果使用插值 ${VARIABLE},确保 .env 文件或 shell 环境中已定义该变量。

验证命令

BASH
# 进入容器查看环境变量
docker compose exec web env | grep MY_VAR

# 或直接打印
docker compose run web env

2. env_file 文件未找到(FileNotFoundError)

报错现象:启动时提示 file not found 错误。

解决方案

  • 确认 env_file 的路径是相对于 compose.yaml 文件的。
  • 检查文件是否存在,以及文件名是否拼写正确。
  • 从 Docker Compose 2.24.0 开始,可以设置 required: false 使文件可选:
YAML
env_file:
  - path: ./optional.env
    required: false

3. 变量覆盖顺序不符合预期

报错现象:设置了多个变量源,但容器内取到的值不是期望的那个。

解决方案:理解并遵循优先级规则。对于 env_file 中的多个文件,后指定的文件会覆盖先指定的文件中的同名变量:

YAML
env_file:
  - ./base.env      # 先加载
  - ./override.env  # 后加载,同名变量会覆盖 base.env 中的值

4. 使用 docker run --env-file 时变量插值不生效

报错现象:在 docker run 命令中使用 --env-file 时,${VARIABLE} 没有被替换。

根因:变量插值是 Docker Compose CLI 的特性,docker run --env-file 不支持。如果需要在 docker run 中使用,请直接在 .env 文件中写入字面值。

生产环境实践与注意事项

1. 敏感信息管理

绝对不要将密码、API 密钥等敏感信息存储在环境变量中。官方建议使用 Docker Secrets:

YAML
# compose.yaml
services:
  web:
    image: myapp:latest
    secrets:
      - db_password

secrets:
  db_password:
    file: ./secrets/db_password.txt

应用代码从 /run/secrets/db_password 文件读取密码,而非环境变量。这样 secret 不会在日志、docker inspect 输出或子进程中泄露。

2. 文件权限控制

确保 .env 文件权限设置正确,避免被其他用户读取:

BASH
chmod 600 .env

3. 路径问题

env_file 的路径是相对于 compose.yaml 文件的,而非当前工作目录。如果使用 -f 指定了非默认路径的 compose.yaml,务必注意:

BASH
# compose.yaml 在 ./config/ 目录下
docker compose -f ./config/compose.yaml up

# env_file 路径应相对于 ./config/
# 例如:./config/.env

4. 并发冲突

多个 docker compose 实例同时操作同一项目可能导致状态不一致。建议使用 --project-name 隔离:

BASH
docker compose --project-name myapp-dev up -d
docker compose --project-name myapp-staging up -d

5. 变量插值默认值

使用 ${VARIABLE:-default} 语法提供默认值,避免变量未定义时容器内变量为空:

YAML
environment:
  - APP_ENV=${APP_ENV:-development}

常见问题 FAQ

Q: 如何在 Docker Compose 中安全地管理数据库密码等敏感信息?

A: 官方建议不要使用环境变量传递敏感信息,而应使用 Docker Secrets。在 Docker Compose 中,你可以通过 secrets 顶级元素定义 secret,然后在服务中使用 secrets 属性挂载到容器内的文件(如 /run/secrets/db_password)。应用代码再从该文件读取。这比环境变量更安全,因为 secret 不会在日志、docker inspect 输出或子进程中泄露。

Q: environment 属性和 env_file 属性有什么区别?我该用哪个?

A: environment 属性直接在 compose.yaml 中定义变量,适合少量、非敏感的配置,或需要明确展示在配置文件中的变量。env_file 属性引用外部 .env 文件,适合管理大量变量、在不同服务间共享同一组变量、或希望将配置与主配置文件分离的场景。通常建议:对于开发环境,使用 env_file 配合 .env 文件;对于生产环境,使用 environment 配合 CI/CD 注入的变量或 secrets。

Q: 为什么我在 compose.yaml 中使用了 ${MY_VAR},但容器内该变量为空?

A: Docker Compose 的变量插值(interpolation)会从以下位置查找变量值(按优先级从高到低):1. 当前 shell 环境变量;2. 项目根目录下的 .env 文件;3. 如果都找不到,Compose 会发出警告,并将变量替换为空字符串。请确保在 shell 中 export MY_VAR=value,或在项目根目录创建 .env 文件并写入 MY_VAR=value。注意:env_file 属性指定的文件不会用于插值,它仅用于将文件中的变量注入容器环境。

相关深度解决方案

在配置当前服务时,如果您遇到了数据库锁死或需要更高并发的读写控制,建议配合参考我们整理的 SQLite MCP 服务的高级缓存配置指南 来提升响应速度。