--env-file 必须用宿主机绝对路径,相对路径静默失效;文件需存在且可读,格式仅支持 K=V 行,不支持变量展开、注释嵌套或 export;敏感信息应避免硬编码,改用 -e 动态注入或 Docker Secrets。

docker run 时 env-file 参数必须是绝对路径
相对路径在容器启动时会被忽略,docker run --env-file .env 很可能静默失效——Docker 默认从容器内部的当前工作目录找文件,而宿主机的 .env 根本没挂进去。正确做法是用绝对路径:docker run --env-file /full/path/to/.env,且该文件必须存在于宿主机上、对 Docker daemon 可读。
常见踩坑点:
- CI/CD 中用
$PWD/.env,但 runner 工作目录和脚本执行目录不一致,导致路径拼错 - 使用
~/.env,波浪线不会被 shell 展开(Docker CLI 不做 tilde expansion) - 文件权限为 600 且属主不是运行 dockerd 的用户(如 rootless Docker),会报
permission denied
env 文件格式不支持变量展开和注释嵌套
.env 文件由 Docker 原生解析,只认 K=V 行,不支持 export、不支持 $VAR 引用、不支持行内注释(# 必须独占一行)。例如以下写法全都会被忽略或出错:
DB_HOST=localhost
APP_ENV=production
# 这行 OK
DB_URL=postgres://$DB_USER:$DB_PASS@${DB_HOST}:5432/app ← 全部当字符串,不替换
如果需要动态组合值,得在启动前用 shell 预处理生成最终 env 文件,或改用 docker-compose 的 env_file + environment 混合方式。
docker-compose.yml 中 env_file 加载顺序影响覆盖行为
多个 env_file 并存时,后声明的文件里同名变量会覆盖前面的;但若同时用了 environment 字段,它的优先级高于所有 env_file。比如:
services:
app:
image: myapp
env_file:
- ./common.env
- ./prod.env ← prod.env 里的 DB_PORT 会覆盖 common.env 的
environment:
- DB_PORT=5433 ← 最终生效的是这个
生产环境建议只保留一个明确命名的 env 文件(如 prod.env),避免多层覆盖带来的不确定性。
敏感参数别硬编码进 env 文件,改用 Docker secrets 或外部注入
.env 文件容易误提交到 Git,尤其当它包含 API_KEY、DB_PASSWORD 等字段时。Docker Desktop 和 Swarm 支持 secrets,但 docker run 本身不支持直接读 secrets——必须用 docker service create 或 docker-compose v3.1+ 配合 secrets: 定义。
更通用的做法是:把敏感项从 .env 移出,启动时用 -e 单独传入,由 CI/CD 工具从密钥管理服务(如 HashiCorp Vault、AWS Secrets Manager)拉取后注入:
docker run \ --env-file ./prod.env \ -e DB_PASSWORD="$(get-secret db/prod/password)" \ myapp
注意 get-secret 命令必须提前配置好权限和认证,且输出不能带换行或空格——否则整个环境变量值会截断或报错。
真正麻烦的不是怎么传,而是谁来保证 .env 里没混进密码、有没有被 IDE 自动上传、会不会被 cat 到日志里——这些比语法细节更容易在线上捅娄子。










