bigywater.tech
Docker · 66

Compose 的环境变量:插值、env_file 与优先级

Compose 里的环境变量有 .env、env_file、environment、shell、命令行好几个来源,谁覆盖谁?.env 里的变量会进容器吗?这篇设计了一组故意重名的变量,逐项量出结果。

environment 胜过 env_file
同名变量 T_Y 在两处都有时,容器里取 environment 的
.env 不进容器
.env 里独有的变量不在容器里,只用于插值
退出码 1
${VAR:?msg} 对未设置的变量,docker compose config 的退出码

三层关系

实测 · 本机执行输出
  compose.yaml 里的 environment 有 T_Y(引用 ${T_I})、T_Z、T_PASS(不写值);env_file 有 T_X、T_Y、T_I;.env 有 T_I=dotenv、T_ONLY_DOTENV=yes
  默认:T_I=envfile-I T_X=from-envfile T_Y=environment-dotenv T_Z=environment

容器里的变量:environment 覆盖 env_file;docker compose run -e 又覆盖前两者。

.env 的角色

实测 · 本机执行输出
  同时在 env_file 和 environment 里的 T_Y:取了 environment 的(上面的 T_Y 值);T_I 在 env_file 和 .env 里,容器里的 T_I 取自 env_file——.env 默认只用于 compose.yaml 里的插值,不进容器
  .env 里独有的 T_ONLY_DOTENV 在容器里吗?不在
  shell 里设 T_I=shell 后(插值优先级:shell 高于 .env):T_I=envfile-I T_X=from-envfile T_Y=environment-shell T_Z=environment
  T_PASS 不写值,shell 里设 T_PASS=from-shell:T_I=envfile-I T_PASS=from-shell T_X=from-envfile T_Y=environment-dotenv T_Z=environment
  docker compose run -e T_Z=cli -e T_X=cli:T_I=envfile-I T_X=cli T_Y=environment-dotenv T_Z=cli

.env 提供的是 compose.yaml 里 ${…} 插值用的变量,不会自动放进容器;而 env_file 的内容不参与插值(T_I 在 env_file 里是 envfile-I,插值仍用 .env 的 dotenv)。插值时 shell 的变量高于 .env,--env-file 可以换掉 .env。

透传

实测 · 本机执行输出
  --env-file other.env(T_I=other-env-file):T_I=envfile-I T_X=from-envfile T_Y=environment-other-env-file T_Z=environment
  docker compose config 展开后的 environment:{'T_I': 'envfile-I', 'T_PASS': None, 'T_X': 'from-envfile', 'T_Y': 'environment-dotenv', 'T_Z': 'environment'}
  --env-file other.env 之后展开的 environment:{'T_I': 'envfile-I', 'T_PASS': None, 'T_X': 'from-envfile', 'T_Y': 'environment-other-env-file', 'T_Z': 'environment'}

environment 里只写变量名不写值,从运行 compose 的 shell 里取;shell 没设就不出现。

默认值语法

实测 · 本机执行输出
  ${T_MISSING:-default-value}-${T_EMPTY-unset} 在 T_MISSING 未设、T_EMPTY 未设时展开成:['echo', 'default-value-unset']
  T_EMPTY 设成空串时(${T_EMPTY-unset} 只在未设置时用默认值):['echo', 'default-value-']
  ${T_REQUIRED:?…} 未设置时:退出码 1;error while interpolating services.web.command: required variable T_REQUIRED is missing a value: 必须设

:- 对未设置或空串都用默认值;不带冒号的 - 只对未设置用默认值;:? 缺失时报错。env_file 与 image 的 ENV 的优先级关系我没有测。

分步演示

环境变量的优先级
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Docker Desktop(Engine 29.8.2,容器跑在 Docker Desktop 自带的 Linux 虚拟机里,内核与宿主机的 macOS 不同);镜像为 linux/arm64;需要看虚拟机内部时用特权容器 + nsenter;计时用 time / date +%s%N,数字每次运行会有小幅抖动。Docker Compose v5.5.1;变量都以 T_ 开头,运行时清除了 shell 里已有的 T_* 变量避免干扰;容器内的值用 docker compose run --rm -T web env 读取,展开结果用 docker compose config --format json;实验后已删除临时文件和容器
    • 没有验证:image 的 ENV 与 env_file 的优先级、env_file 的 required: false 和 format 选项、多个 --env-file、COMPOSE_ENV_FILES、docker compose up(而不是 run)的环境差异、secrets 与 configs
    京ICP备2026067502号-1京公网安备11010502063487号