docker compose 漏一个参数全失效
compose 文件早就摆好了,镜像也拉过,我以为就差一行 up -d:
bash
docker compose -f compose/_base.yml -f compose/openbao.yml up -d
回车,容器起来了,健康检查也过了。打开管理后台一登 --- 密码不对。
我对着 .env 看了好几遍,密码字符串都对啊。换浏览器、清 cookie、容器重启一遍,还是不行。
服了。
进容器看环境变量:
bash
docker exec -it openbao env | grep PASSWORD
OPENBAO_ADMIN_PASSWORD=
值是空的。
.env 里明明写了 OPENBAO_ADMIN_PASSWORD=xK9f2... 一大串,容器里怎么变空了?
一行 warning 都没有的失败
我把 compose 命令重新跑了一遍,这次盯着输出:
css
[+] Running 1/1
✔ Container openbao Started
没有任何 warning。容器照样起,只是它认为 OPENBAO_ADMIN_PASSWORD 这个变量值就是空字符串。
把 .env 临时塞了个错的密码,再跑,期望它至少要报错让我知道值在哪一步丢的。结果还是这副"成功"的样子。
我开始怀疑 compose 没读 .env。这个文件就放在我执行命令的目录下,按理说默认会读的。
直到翻 docker compose 文档看到这一段:
The
.envfile is loaded from the project directory. The project directory is determined by--project-directory, then by the parent directory of the first compose file specified, then by the current working directory.
我一脸懵。我用了 -f compose/_base.yml -f compose/openbao.yml,第一个 compose 文件的父目录是 compose/。所以 compose 把 project directory 推断成 compose/,而 .env 在它上一级的项目根。compose 在 compose/.env 找不到东西就当没有,展开 ${OPENBAO_ADMIN_PASSWORD} 直接给我个空串。
整个过程零 warning。
一个参数的事
修法是加 --project-directory .,显式告诉 compose 项目根在哪:
bash
docker compose --project-directory . `
-f compose/_base.yml `
-f compose/openbao.yml up -d
加上这一行,.env 立刻被读到,密码也对了。
我之后所有的 compose 命令模板都套这个:
css
docker compose --project-directory . -f ... -f ... up -d
哪怕只用一个 -f,我也加。免得下次某个组件文件挪了位置,推导路径又跑偏。
为什么这事让我搞了一晚
回头看,有几个让我跑偏的地方:
第一,compose 不报错。
${VAR} 展开为空在 compose 里是合法行为。如果 yml 里写的是 image: ${IMAGE}:${TAG},展开后会变成 image: :,这个 docker 还会接,只是拉不到镜像。但密码这种,展开成空字符串就直接以空密码塞进环境变量,容器自己也不知道这是错的。
第二,我以为 .env 是默认读的。
只在最简单的 docker compose up(单 compose 文件,没 -f)情况下,.env 才"看起来是默认读的"。一旦多 -f,project directory 推导就开始按文件位置走。文档里写得清楚,但谁会在加新组件的时候去读 docker compose 的"project directory inference rules"。
第三,压根没意识到要往这个方向查。
整个上午我在反复怀疑 .env 的格式、密码里有没有特殊字符、容器自己有没有把变量吃掉。绕了一大圈才回到 "compose 根本没读 .env"。
一行参数,记一下
css
docker compose --project-directory . -f xxx.yml -f yyy.yml up -d
下次写 compose 命令的时候,这一行先打上,别等被坑了再回来加。