Docker Compose 環境變數未生效,先分清兩件事:.env 和 --env-file 為 Compose 解析設定提供變數,服務中的 environment 與 env_file 才負責將變數傳入容器。修改設定後,restart 不會更新既有容器的環境,應先檢查解析結果,再用 up -d 套用變更。
照著部署教學操作時,最常見的情況是:.env 明明寫了值,容器裡卻沒有;改了值又重新啟動,程式仍使用舊位址。
這通常需要沿著「輸入檔案 → Compose 設定 → 容器環境 → 應用程式讀取」逐層排查。
本文適用於 Compose V2 與 Linux 容器,包括 Docker Desktop 的 Linux 容器模式。 文件核對日期為 2026 年 11 月 4 日;指令依據官方文件整理,未在本文環境中執行 Docker 容器。
如果你正在維護 Joplin Server、Syncthing 等自架服務,可以先用下面的獨立範例理解覆寫規則,再檢查實際服務設定。
四種寫法分別將變數送到哪裡
| 寫法 | 使用位置 | 主要用途 |
|---|---|---|
.env |
Compose 專案慣用的輸入檔案 | 為 ${VAR} 等插值提供值 |
--env-file ./deploy.env |
Compose 命令列選項 | 明確指定插值輸入檔案 |
env_file: ./app.env |
個別服務的設定 | 將檔案中的變數注入該服務容器 |
environment: |
個別服務的設定 | 直接設定、引用或覆寫容器變數 |
同一個檔案可以同時擔任兩種用途,但需要明確宣告。
僅將 .env 放在目錄中,不會自動把其中所有變數傳入所有容器。
例如 .env 中有 APP_MODE=production,但服務沒有任何環境變數宣告,容器通常不會因此取得 APP_MODE。
服務寫了 environment: APP_MODE: "${APP_MODE}",這條傳遞鏈才連接起來。
官方說明見 設定容器環境變數。
用不含業務資料的專案觀察覆寫結果
先確認 CLI 與實際連線的 Docker 主機。
|
|
建立獨立目錄 compose-env-lab,在其中新增以下三個檔案。
不要直接將實驗服務加入正式環境的專案。
|
|
compose.yaml:
|
|
.env:
|
|
app.env:
|
|
本例沒有連接埠映射、資料卷或特權權限。 映像檔需要從你的 Docker 主機可存取的登錄站拉取;初始實驗結束前保持檔案不變,以便比對。
先在這個目錄執行:
|
|
config -q 成功只表示設定驗證通過。
config --environment 顯示用於插值的變數;一般 config 顯示合併、解析後的服務模型。
兩者都不能證明容器已建立,更不能證明應用程式已讀取那些值。
這些輸出可能包含密碼,請只在可信任的終端機查看,分享前移除敏感值。 具體選項見 docker compose config。
啟動後只讀取需要核對的變數
|
|
若啟動 Compose 的終端機沒有同名變數覆寫,預期依序看到:
|
|
APP_MODE 來自 .env 的插值結果,覆寫了 app.env 中的同名項目。
APP_COLOR 透過服務的 env_file 注入。
APP_LABEL 是必填項目,缺少或為空時會在設定解析階段報錯。
再單獨查詢未宣告傳入容器的變數:
|
|
預期沒有輸出,指令傳回非零狀態。
這是實驗的正常結果,說明 .env 並不是將所有變數注入容器的檔案。
.env 的值為什麼被終端機覆寫
Compose 解析 ${APP_MODE} 時,啟動它的 Shell 若已有同名變數,會優先採用 Shell 的值。
所以「檔案寫的是 production,解析結果卻是 staging」時,先檢查終端機環境。
在 Bash 中可以這樣查看及清除實驗變數:
|
|
PowerShell 的對應操作為:
|
|
清除目前終端機的變數前,確認其他工作不需要這個設定。 IDE 工作、CI 作業與系統服務繼承的環境,也可能和手動開啟的終端機不同。
為減少工作目錄造成的歧義,部署指令可以明確指定設定與輸入檔案:
|
|
將 myapp 換成既有專案名稱,不要在正式部署時隨意改名。
專案名稱會參與容器、網路與預設資料卷的命名,改名可能得到另一組資源。
--env-file 的相對路徑以執行指令時的工作目錄為基準;服務 env_file 的一般相對路徑則以 Compose 檔案位置為基準。
多個 Compose 檔案、--project-directory、COMPOSE_FILE 會增加路徑關係的複雜度,排錯時先使用明確路徑縮小範圍。
同時指定多個插值輸入檔案時,後面的檔案可以覆寫前面的同名項目:
|
|
Shell 中既有的同名變數仍可能優先。
預設 .env 的搜尋細節應搭配目前的 CLI 版本核對,見 Compose 插值與檔案載入規則。
容器內的優先順序要另外檢查
確認插值輸入後,還要看服務最終如何設定容器變數。 在常見的明確賦值情境中,可以依下列覆寫關係理解:
| 情境 | 對結果的影響 |
|---|---|
docker compose run -e APP_MODE=debug |
覆寫這次臨時容器的對應變數 |
在服務的 environment 中設定 APP_MODE |
覆寫服務 env_file 的同名值 |
服務列出多個 env_file |
後面的檔案覆寫前面的同名值 |
映像檔 Dockerfile 中的 ENV |
未被執行時的同名設定覆寫時才保留 |
這裡的 environment 值本身可能來自 Shell 或 .env 插值。
不要將「值從哪裡解析出來」和「透過哪個服務欄位傳入容器」混成同一步驟。
只寫變數名稱而不給值的透傳寫法,還有未解析時移除變數的語意,排錯時優先使用明確賦值。
可以在實驗中驗證臨時覆寫:
|
|
預期輸出 debug。
這建立的是一次性容器,不會修改先前透過 up -d 啟動的 probe 容器。
也不要將 run -e 當成 up 的通用參數。
完整適用範圍與透傳案例見 官方環境變數優先順序說明。
修改檔案後,為什麼 restart 仍是舊值
容器的環境變數在建立容器時決定。
docker compose restart 重新啟動既有容器,不會根據修改後的設定重新建立容器環境。
將實驗 .env 中的 APP_MODE 改為 staging 後,可以依序比對:
|
|
若容器原本使用 production,重新啟動後仍應維持該值。
此時設定檔和執行中的容器處於不同狀態。
確認解析結果正確後,套用變更:
|
|
Compose 通常會偵測設定變更並重建受影響的服務。 確實需要強制重建時,使用:
|
|
重建會中斷服務,應安排在業務維護時段執行。 資料庫等相依服務是否也需要處理,應由實際架構決定,不要習慣性重建整個專案。
掛載的資料卷會依設定繼續使用,但容器可寫入層中的臨時修改可能遺失。 操作前應確認業務資料確實存放於持久化位置。 官方行為說明見 restart 與 up。
錢字號、空值與布林值的常見陷阱
讓變數在容器內展開
Compose 檔案中的 $VAR 通常會先由 Compose 處理。
若希望由容器中的 Shell 讀取變數,可使用 $$,並明確呼叫 Shell:
|
|
這是一個獨立的短期服務範例,執行後印出值並結束。
$$ 阻止 Compose 在主機階段展開該變數;sh -c 負責在容器內展開。
僅將變數放入不經 Shell 的參數陣列,不會自動產生 Shell 展開行為。
語法依據見 Compose Interpolation。
空字串和「未設定」的意義不同
${VAR:-default} 在變數不存在或為空時都使用預設值。
${VAR-default} 只在變數不存在時使用預設值。
${VAR:?message} 適合必須非空的輸入,可避免空位址、空路徑一路傳到執行階段。
不要在未記錄原因的情況下,用空字串暫時遮蔽正式環境設定。
服務中的明確空值可能覆寫原本有效的 env_file 設定。
YAML 中類似布林值的內容建議寫成字串:
|
|
這只能確保傳入的是字串。
應用程式將 "false" 解讀為停用,還是將所有非空字串視為真,仍取決於自身的設定解析方式。
設定正確、容器也正確,應用程式為什麼仍未改變
先確認應用程式是否支援這個變數名稱,以及是否有設定檔、命令列參數等更高優先順序的來源。
APP_URL、BASE_URL、PUBLIC_URL 並非通用協定,不能跨專案任意替換。
再檢查讀取時機:部分前端設定在建置映像檔時就寫入靜態檔案,執行時設定環境變數不會重寫既有前端產物。
需要建置參數的專案,應依專案文件設定 build.args 或專用啟動指令碼。
最後核對是否檢查了正確的服務與執行個體。 同一專案的 worker、web、scheduler 可能是三個容器,只更新其中一個不會改變另外兩個。
| 觀察結果 | 下一步 |
|---|---|
config 仍是舊值 |
檢查輸入檔案路徑、Shell 覆寫及多檔案合併 |
config 正確,exec printenv 是舊值 |
檢查專案名稱、Docker context 與容器重建 |
| 容器值正確,應用程式行為仍舊 | 檢查變數名稱、應用程式優先順序、讀取時機及實際存取的執行個體 |
exec 失敗,容器未執行 |
先查看 ps -a 與對應服務日誌 |
在實驗中可以直接執行:
|
|
業務映像檔可能沒有 printenv 或 Shell。
此時使用映像檔提供的診斷指令,或由管理員查看容器設定並移除敏感資訊;不要只為排錯就在正式映像檔中臨時安裝大量工具。
密碼、回復與實驗清理
不要將真實密碼寫進範例儲存庫,也不要完整貼上 config、inspect 或全部 env 輸出。
.env 是純文字檔案,不提供加密功能。
可以提交不含憑證的 .env.example;實際部署檔案應依專案要求限制讀取權限,並排除於版本控制之外。
應用程式支援從檔案讀取憑證時,可以考慮 Compose secrets。
它會將授權的 secret 作為容器內的檔案提供,常見位置是 /run/secrets/<name>。
_FILE 變數只是部分映像檔採用的慣例,並非所有應用程式都自動支援。
本機來源檔案仍需妥善保護,見 Compose secrets 官方說明。
變更正式環境設定前,保存上一版設定與環境輸入,並記錄專案名稱、映像檔版本及指令參數。
回復時還原那些檔案,以相同參數檢查 config -q,再執行 up -d,最後驗證應用程式行為。
設定回復不能取代資料庫備份,也不保證能逆轉應用程式已完成的資料遷移。
實驗結束後,在 compose-env-lab 目錄執行:
|
|
本例未宣告資料卷,不需要加上 -v。
不要將這條實驗指令改成全域清理操作;空間維護另見 Docker 磁碟空間清理指南。
排錯結束時,應分別確認:解析後的設定符合預期、執行中的容器已取得新值、應用程式實際行為已改變。
這三項對應不同層次,逐層確認才能避免反覆修改 .env 卻找錯原因。