1346 字
7 分鐘

Docker Compose pre_start 怎麼用?用 init container 做啟動前準備

以前要在 Docker Compose 啟動前跑 migration、建立資料夾或修正 volume 權限,常見做法是把命令塞進 entrypoint,或另外維護一個一次性 service。Docker Compose 現在提供 pre_start,可以在主服務真正啟動前,以獨立的 ephemeral container 依序執行這些準備工作。

官方 Compose service reference 將 pre_start 標示為 Docker Compose 5.3.0 以上功能。它適合處理「主服務尚未開始接收流量前必須完成」的步驟,但不等於把所有初始化程式都搬進 YAML 就安全;命令的重入性、權限與失敗後的回復仍要由專案負責。

pre_start 的執行邊界#

pre_start 有三個值得先記住的行為:

  • 每個 step 都在自己的 ephemeral container 執行,並依宣告順序完成。
  • 所有 step 都以 exit code 0 結束後,主服務才會啟動;任何非零結果都會讓該服務和依賴它的服務 bring-up 失敗。
  • step 可以使用父服務的 image,也可以指定另一個 image;它會在主服務 container 建立後、啟動前執行。

因此,pre_start 和「主程式啟動後再背景執行一個命令」是不同的生命週期。前者可以阻擋主服務啟動,後者不一定能保證準備工作已完成。

用 migration 與 volume 權限做一個範例#

以下範例示範兩個啟動前步驟:第一個使用 app image 執行 migration,第二個使用 BusyBox 修正共用 volume 的擁有者。manage.py、volume 路徑和 UID 都是示意,請換成專案實際命令。

services:
app:
image: example/app:latest
depends_on:
db:
condition: service_healthy
pre_start:
- command: ["./manage.py", "migrate"]
- image: busybox
command: ["sh", "-c", "chown -R 1000:1000 /data"]
user: root
volumes:
- app-data:/data
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER:-postgres}"]
interval: 5s
timeout: 5s
retries: 10
volumes:
app-data:

depends_on 先等 db 通過 healthcheck,pre_start 再處理 app 的 migration 和 volume。這裡的重點是把「相依服務已就緒」與「本服務啟動前要完成的準備」分成兩個條件;如果想先理解 service_healthy,可以看 Docker Compose 的 healthcheck 與啟動順序

pre_start、entrypoint、post_start 怎麼選#

需求合適的邊界原因
服務啟動前必須完成 migration 或檔案準備pre_startstep 失敗會阻擋主服務啟動
每個 container 都要執行主程式初始化entrypoint/command邏輯和主服務共用同一個 container 生命週期
服務已啟動後做不影響 ready 的登錄或通知post_start官方不保證 hook 和 entrypoint 的先後順序
主服務停止前保存資料pre_stop只在特定停止流程前執行,突然終止時不保證觸發
只需要等待資料庫或 cache 就緒depends_on + healthcheck這是依賴關係,不是本服務的初始化命令

不要把 post_start 當成 pre_start 的替代品。官方 lifecycle hooks 文件特別提醒,post-start hook 的執行時間沒有保證;如果 app 必須等 migration 完成才能提供服務,應把步驟放在真正能阻擋啟動的邊界。

重跑時機與 scaled service 的陷阱#

成功的 pre_start step 在定義沒有變化時,不會因為主服務依 restart policy 重啟就再次執行。它會在 step 定義改變、上次失敗,或 service 被重新建立時再跑。若 migration 需要每次 container restart 都執行,pre_start 可能不是正確位置。

當服務有多個 replica 時,per_replica: false 可以讓某個 step 在整個 service 只跑一次,但它只能使用 named volume 或 bind mount 這類共享資源;tmpfs 和 anonymous volume 等 per-instance mount 不能被單一 step 代表。需要每個 replica 各自準備時,則要明確評估預設的 per-replica 行為,以及命令是否具備重入性。

上線前先檢查 Compose 版本與實際模型#

先在執行部署的環境確認版本,再驗證 YAML 解析結果:

Terminal window
docker compose version
docker compose config
docker compose up -d
docker compose ps
docker compose logs app db

如果版本低於官方要求,pre_start 可能無法被目前的 Compose 實作接受;不要只在本機升級,還要檢查 CI、開發者容器和正式部署主機的 Compose 版本。docker compose config 能先把插值、合併檔和實際模型攤開,方便確認 step、volume 與 depends_on 是否真的套用。

結論:把啟動前準備寫成可驗證的 gate#

pre_start 的價值是把 init container 變成 Compose service lifecycle 的一部分:成功才啟動主服務,失敗就停止 bring-up。實作時先確認 Compose 版本,再把 dependency readiness、migration、權限與 scaled service 的執行次數分開驗證;不要只把 entrypoint 裡的長腳本原封不動搬進 YAML。

常見問題#

Q: pre_start 會在每次 container restart 時執行嗎?#

A: 不會以 restart policy 作為重新執行條件。官方文件指出,已成功且定義未變的 step 不會因為服務重啟再次執行;定義變更、先前失敗或 service 被重新建立時才會重新跑。

Q: pre_startdepends_on: service_healthy 可以一起用嗎?#

A: 可以。depends_on 負責等待相依服務通過 healthcheck,pre_start 再執行本服務啟動前的 migration 或檔案準備。兩者處理的是不同生命週期條件,不能互相取代。

Q: 所有環境都能直接使用 pre_start 嗎?#

A: 先確認執行環境的 Docker Compose 版本。Docker Docs 目前將 pre_start 標示為 Docker Compose 5.3.0 以上;本機、CI 與部署主機的版本都要分別檢查。

參考資料:

Docker Docs:Define services in Docker Compose

Docker Docs:Using lifecycle hooks with Compose

Docker Docs:Control startup and shutdown order in Compose

Docker Compose pre_start 怎麼用?用 init container 做啟動前準備
https://laplusda.com/posts/docker-compose-pre-start-init-containers/
作者
Zero
發佈於
2026-08-23
許可協議
CC BY-NC-SA 4.0
這篇文章有幫助嗎?

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