1191 字
6 分鐘

Docker Compose 的 env_file 與 ${VAR} 怎麼分?解決變數插值為空

你可能遇過這種 Docker Compose 錯誤:runtime.env 明明有 IMAGE_TAG,但 compose.yaml 裡的 ${IMAGE_TAG} 還是變成空字串,最後得到一個無效的 image reference。原因通常不是檔案沒有讀到,而是把兩種不同階段的 environment file 當成同一個設定。

直接記法是:services.<name>.env_file 把值送進 container;.env、CLI --env-file 或 shell 才是 Compose 在解析 ${VAR} 時使用的插值來源。 先用 docker compose config 看解析後的 model,再啟動服務。

env_file--env-file 的工作位置不同#

設定作用階段適合解決的問題
services.web.env_filecontainer 建立後的執行環境PORTLOG_LEVEL 或 runtime 設定交給 web
專案 .envCompose 解析 model 時的預設插值來源image: "web:${TAG}" 找到 TAG
docker compose --env-file ...Compose CLI 解析 model 時的明確輸入CI、staging、production 使用不同的插值檔
shell environmentCompose 解析 model 時的最高優先來源一次性的部署覆寫或 CI 明確傳值

env_file 是 service 的設定,不會在 Compose 已經解析 image、volume、port 或 build argument 之後回頭補值。這也是為什麼只改 runtime.env,卻看不到 image: "my-web:${IMAGE_TAG}" 改變。

先重現「容器有值、model 沒值」的情境#

下面的設定把兩個階段放在一起,正好能看出問題:

services:
web:
env_file:
- ./runtime.env
image: "my-web:${IMAGE_TAG}"

runtime.env 可以讓 web container 在啟動後讀到 IMAGE_TAG,但 Compose 要先在建立 application model 時解析 image。若執行指令的 shell、CLI --env-file 或 project .env 沒有 IMAGE_TAG${IMAGE_TAG} 可能被警告後替換成空字串。

.env--env-file 提供插值來源#

專案預設使用 .env#

.env
IMAGE_TAG=2026.08
PUBLIC_ORIGIN=https://example.com
services:
web:
image: "my-web:${IMAGE_TAG}"
environment:
PUBLIC_ORIGIN: "${PUBLIC_ORIGIN}"

Compose 沒有明確傳入 --env-file 時,會依 project directory 的規則尋找 .env。如果使用 -f--project-directoryCOMPOSE_FILE,專案目錄可能不是你目前 shell 所在的位置,所以不要只看檔案是否存在,要檢查實際解析結果。

CI 或多環境使用 --env-file#

把 environment file 放在明確的位置,並在每個工作流寫出來源:

config/.env.ci
IMAGE_TAG=2026.08-rc1
PUBLIC_ORIGIN=https://staging.example.com
Terminal window
docker compose --env-file ./config/.env.ci config
docker compose --env-file ./config/.env.ci up -d

--env-file 是 Compose CLI 的輸入;它和 services.web.env_file 不同。若兩者都存在,可以讓前者解析 image tag,後者把 container 啟動後才需要的額外值交給服務。

需要值時,用 required expression 讓它提早失敗#

如果空字串會產生無效 image、錯誤 host path 或連錯資料庫,不要讓錯誤拖到 container 啟動後才出現:

services:
web:
image: "my-web:${IMAGE_TAG:?請先設定 IMAGE_TAG}"
environment:
PUBLIC_ORIGIN: "${PUBLIC_ORIGIN:?請先設定 PUBLIC_ORIGIN}"

需要預設值時才使用 :-

services:
web:
environment:
LOG_LEVEL: "${LOG_LEVEL:-info}"

${VAR:-default} 會把未設定或空字串都視為缺少;${VAR?error} 只檢查是否已設定。選擇哪一種,要看空值是否與你的部署契約相容。

先看 Compose 真正使用的值#

不要直接把完整設定檔倒進 CI log,因為解析後的 model 可能包含密碼或連線字串。先看插值環境,再針對非敏感欄位檢查:

Terminal window
set -euo pipefail
docker compose --env-file ./config/.env.ci config --environment
docker compose --env-file ./config/.env.ci config > /tmp/compose.resolved.yaml
rg 'image:|PUBLIC_ORIGIN:|LOG_LEVEL:' /tmp/compose.resolved.yaml

docker compose config --environment 會列出 Compose 用來插值的環境;docker compose config 則輸出解析後的 model。兩個指令要和 CI 使用相同的工作目錄、-f 檔案與 --env-file 參數,否則你驗證的是另一份設定。

若設定拆在多個 Compose application,先參考 Compose include 的相對路徑、變數與名稱衝突。若問題是 app 太早連資料庫,則看 healthcheck 與 service_healthy 的啟動順序;那是服務就緒問題,不是變數插值問題。

不要把 Compose CLI 行為套到 Swarm#

Docker 官方文件特別註明,.env 的 substitution 是 Docker Compose CLI 的功能,docker stack deploy 不支援同一套插值行為。若最後部署入口是 Swarm,請用實際的 stack deploy 路徑測試,不要因為 docker compose config 成功就推論另一個命令也會得到相同 model。

結論是:用 .env--env-file 或 shell 解決 ${VAR};用 service env_file 提供 container 的 runtime environment。把這兩層拆開,再用 config --environmentconfig 驗證,Compose 的空 image tag 通常就能在啟動前被抓出來。

常見問題#

Q: service 的 env_file 可以填入同一份 Compose 裡的 ${VAR} 嗎?#

A: 不要依賴這種行為。service env_file 是給 container runtime environment 的輸入,${VAR} 是 Compose 建立 model 時的插值。請改用 project .env、CLI --env-file 或 shell environment。

Q: Compose 的插值來源哪個優先?#

A: 官方插值文件列出的順序是 shell environment 高於 CLI --env-file,而沒有傳入 --env-file 時才使用 project .env。用 docker compose config --environment 檢查實際值,不要用檔案名稱猜 precedence。

Q: 為什麼 docker compose config 只顯示空字串,不直接失敗?#

A: 未設定的變數可能被警告後替換成空字串。對必填值使用 ${VAR:?error}${VAR?error},讓無效 image、路徑或 host 在解析階段就停止。

參考資料:

Docker Docs:Compose variable interpolation

Docker Docs:Set environment variables within your container’s environment

Docker Docs:Compose file services — env_file

Docker Docs:docker compose config

Docker Compose 的 env_file 與 ${VAR} 怎麼分?解決變數插值為空
https://laplusda.com/posts/docker-compose-env-file-interpolation/
作者
Zero
發佈於
2026-08-18
許可協議
CC BY-NC-SA 4.0
這篇文章有幫助嗎?

回報錯字、失效連結,或告訴我你想看的延伸主題。