AI 工作實務
compose.yaml 多服務實作:讓 API 等待 PostgreSQL,驗證資料持久化與故障回復
把 API 和資料庫一起啟動,只完成多服務系統的一半。這份練習用兩個容器驗證三件事:資料庫準備好後才啟動 API、資料庫停止時回傳明確錯誤,以及重建容器後仍讀得到同一筆測試資料。

把 API 和資料庫一起啟動,只完成多服務系統的一半。這份練習用兩個容器驗證三件事:資料庫準備好後才啟動 API、資料庫停止時回傳明確錯誤,以及重建容器後仍讀得到同一筆測試資料。
專題編輯:Derek Chou|AI 技術與架構編輯 · 文件核對 2026.11.09

已有 Dockerfile,為什麼還需要 Compose?
Dockerfile 描述單一映像如何建置;Compose 把多個服務的映像、網路、啟動條件和資料儲存放在同一份應用設定中。若還不熟悉映像與容器的差異,可先讀Docker 容器部署入門。本文接續處理 API 與 PostgreSQL 的共同啟動、健康狀態及資料生命週期,不重做單容器入門。
假設工程師交付了一個報價服務:api 可正常啟動,卻在第一筆查詢時找不到資料庫;另一位同事重建容器後,測試資料又全部消失。兩個問題分別屬於「依賴是否可用」和「資料存在哪裡」。它們需要不同驗收,不能只用容器清單上的 running 回答。
本練習刻意縮成 API 加 DB,不加入前端、Redis 或訊息佇列。API 只維護一個合成計數器,沒有客戶資料,也沒有登入功能。完成後你會拿到一組能重跑的配置、HTTP 驗證,以及容器重建前後的讀回結果;這些證據適用於練習環境,不代表正式服務已具備備份、容錯或安全防護。
環境、附件與本次驗收範圍
需要可執行 Linux 容器的 Docker Engine/Docker Desktop、Docker Compose v2、Bash 和 Python 3。先執行 docker version 與 docker compose version,確認 Docker daemon 可連線。macOS 的 Docker Desktop 仍是透過 Linux 虛擬機運行這組容器;本文沒有驗證 Windows containers。
下載完整練習檔,解壓後的主要檔案如下:
compose.yaml
api/Dockerfile
api/requirements.txt
api/app.py
verify.sh
README.md
API 使用 Python 3.12 映像與固定的 psycopg[binary]==3.2.9。DB 採 PostgreSQL 18 官方映像。postgres:18 與 python:3.12-slim 是會更新的標籤;練習會記錄實際版本與 DB image digest。若要重建完全相同的供應鏈,還需保存並指定兩個映像的 digest,不能把大版本標籤當成不可變版本。
步驟一:讀懂 compose.yaml 的邊界
檔案中的核心配置如下,完整版本含 API 自身的健康檢查:
services:
api:
build: ./api
ports:
- "127.0.0.1:${API_PORT:-8000}:8000"
environment:
DATABASE_HOST: db
DATABASE_NAME: appdb
DATABASE_USER: appuser
secrets: [db_password]
depends_on:
db:
condition: service_healthy
db:
image: postgres:18
environment:
POSTGRES_DB: appdb
POSTGRES_USER: appuser
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets: [db_password]
volumes: ["db_data:/var/lib/postgresql"]
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"]
interval: 3s
timeout: 3s
retries: 20
volumes:
db_data:
secrets:
db_password:
file: ./secrets/db_password.txt
Compose 內部以服務名 db 解析資料庫位置;API 裡的 localhost 指向 API 容器本身,不是 DB。DB 沒有宣告 ports,因此本練習不把 PostgreSQL port 發布到主機。API 的主機端綁定 127.0.0.1,目的是讓驗證入口留在本機;這仍不能取代容器隔離、主機防火牆或登入授權。
depends_on 的長格式搭配 service_healthy,讓 Compose 等 DB 健康檢查通過後才建立依賴服務。這個條件處理的是啟動順序;DB 日後中斷,API 仍要自己處理失敗。本例每次請求重新連線,連線失敗時回傳 HTTP 503,沒有宣稱具備自動修復資料庫的能力。Docker 啟動順序文件
PostgreSQL 18 官方映像採用含主版本的資料目錄配置,本例將 named volume 掛到 /var/lib/postgresql。不要把舊版教學的資料路徑直接複製到新映像,也不要用換標籤的方式假裝完成跨大版本資料升級。PostgreSQL 官方映像說明
步驟二:在獨立專案中執行驗證
在解壓後的練習資料夾執行:
bash verify.sh
腳本會產生獨立的 tdr-compose-lab-程序編號 專案名稱,選擇本機空閒 port,建立隨機測試密碼,再執行 docker compose config --quiet 和 docker compose up --build -d --wait。密碼只供本次練習初始化 DB,不列印到輸出,也不應提交到 Git。
Compose secrets 讓服務從 /run/secrets/db_password 讀取檔案;它不是把本機來源檔自動加密。檔案仍須受到主機權限及版本控制排除規則保護,正式環境也需要自己的機密生命週期。Compose secrets 文件
若出現 cannot connect to Docker daemon,應先啟動 Docker;若建置下載失敗,保留網路或 registry 錯誤,再恢復來源。不要以略過建置或移除健康檢查讓流程變綠。驗證腳本只清理自己建立的 Compose 專案,請勿改成指向現有正式專案。
步驟三:驗證可用、故障及資料讀寫
API 提供三個端點:GET /health 實際向 DB 執行查詢;POST /visits 將測試計數加一;GET /visits 讀取當前值。驗證依序檢查健康回應、寫入得到 1、讀回仍為 1。這比只看程序活著更接近應用依賴是否可用。
接著腳本停止 DB,再呼叫 /health。此時預期 HTTP 503,而非成功訊息或無限等待;API 回應只包含通用錯誤,不把資料庫連線細節交給呼叫者。DB 恢復後,下一次請求重新建立連線。這個簡單策略足以教學,但高流量服務仍需設計連線池、有限重試、逾時與監控。
恢復 DB 時,腳本使用下列指令,最多等待 60 秒讓設定中的 DB 健康檢查通過:
docker compose up -d --wait --wait-timeout 60 db
這個寫法在 Compose v2.38.2 的官方文件已列出。該版的 start 沒有 --wait,因此不要直接套用最新文件的所有參數。此練習不改 DB 配置或映像,up 會啟動停止的服務;若配置或映像有變更,則可能重建容器並保留掛載的 volume。應記錄實際 Compose 版本,並以該次完整驗證結果判斷是否成功。v2.38.2 up 文件、v2.38.2 start 文件
真正的結果以 HTTP 狀態與資料讀回為準。看到 DB 容器正在執行,只表示程序存在;看到健康檢查通過,也只涵蓋檢查所測的項目,不代表所有業務流程成功。
步驟四:重建容器,確認資料仍在
腳本先執行不帶 -v 的 docker compose down,再 up -d --wait,最後重新讀取 /visits。預期值仍是 1,表示本次資料跨越容器重建保存在 named volume 中。Compose down 文件
這不是備份還原測試。volume 還在與資料可從異地備份恢復,是兩種證據;主機磁碟損壞、誤刪 volume、資料邏輯毀損,都不會因為用了 named volume 自動解決。要驗證備份,需另外保存資料庫備份、建立空白資料庫、還原並核對關鍵資料,不可把容器重建結果寫成災難復原完成。
腳本結束時會刪除自己建立的測試容器與測試 volume。 這是合成資料的練習清理,不應把同一個 down -v 套用到有價值的資料庫。清理後還會依專案標籤確認容器、網路與 volume 均已移除,並確認合成密碼檔不存在;只有功能驗證與清理皆成功,才輸出 COMPOSE_LAB_PASS。原測試失敗會保留其非零狀態;即使功能成功,清理失敗也以非零結束,細節寫入 evidence/cleanup.log。
交付給下一位工程師前,再看四個差異
| 容易混為一談的狀態 | 應保留的證據 |
|---|---|
| YAML 可解析與服務可運作 | config 檢查+實際 HTTP 請求 |
| 容器 running 與 DB 可接受查詢 | 健康查詢及錯誤回應 |
| 容器重建保留資料與備份可還原 | 前者讀回;後者另做空白環境還原 |
| 大版本標籤與精確可重現映像 | 實際 image digest 與依賴版本 |
本例的資料庫初始化帳號只用於隔離練習,沒有完成正式服務所需的最小權限設計;API 亦未加入認證、TLS、流量限制和監控。把它帶入企業專案時,先替換為專用應用帳號、制定遷移與備份策略,再按實際負載測試。Compose 的價值,是讓服務關係成為可以核對的設定;正式營運責任仍須逐項落實。
常見問題
只有 depends_on: [db] 不行嗎? 它能描述相依啟動順序,卻沒有本例的健康條件。需要等待 DB 就緒時,使用健康檢查及對應條件,並保留應用端錯誤處理。
密碼換了,舊 volume 的 DB 密碼也會跟著換嗎? 不應如此假設。官方映像的初始化變數主要在資料目錄為空時生效;修改已有資料庫的帳密需要正式變更程序。這也是練習使用全新專案與測試 volume 的原因。
可以直接公開這個 API 嗎? 這個端點允許未登入者改變計數,設計目的只限本機驗證。對外服務須另做身分、授權、資源限制與資料規則。
資料來源與素材說明
官方文件核對日:2026 年 11 月 9 至 10 日。程式是本篇原創教學樣本;它驗證特定隔離情境,不宣稱已部署讀者的正式系統。配圖為概念示意,非 Docker 操作截圖;版本、命令與結果以附檔驗證紀錄為準。
內容提供:TARAISG。本文由 AI 協助整理與查核;專題編輯為天地人 AI 編輯計畫的策展角色,未宣稱經具名人工或專家審核。
本文由 TARAISG(TIANDIREN AI SOLUTION GROUP)使用 AI 模型產生正文、整理來源並設計實務工具。方法依據與限制列於文末;案例為明確標示的教學假設。未有具名紀錄時,不宣稱經人工或專家審核。
查看內容製作與更正說明