Docker Compose YAML 完整教學:從零開始打造多容器自動化部署流程
在現代的微服務(Microservices)架構中,單一容器的運行早已無法滿足複雜的應用需求。一個典型的現代化 Web 應用,通常需要包含前端網頁伺服器、後端 API 邏輯、資料庫、快取機制(如 Redis)以及訊息佇列(如 RabbitMQ)。如果我們使用傳統的 docker run 指令來逐一啟動這些服務,不僅過程極其繁瑣,更會面臨網路連線、環境變數、啟動順序等一系列難以管理的痛點。
這就是 Docker Compose 出現的原因。透過一個單一的 docker-compose.yml 設定檔,你可以將整個應用程式的基礎設施「程式碼化」(Infrastructure as Code, IaC),實現一鍵部署、一鍵啟動、一鍵銷毀。
本篇 Docker Compose YAML 完整教學 將帶領你從基礎語法開始,深入探討如何撰寫高效、安全且具備擴展性的 YAML 配置,並透過實戰案例讓你掌握多服務部署的核心技術。
1. 認識 Docker Compose:為什麼你不再需要手動執行 Docker Run?
在深入研究 YAML 語法之前,我們必須先理解 Docker Compose 解決的核心問題。
Docker 與 Docker Compose 的核心差異
許多初學者會混淆 Docker 與 Docker Compose 的角色。簡單來說: * Docker:是一個容器化引擎,負責建立、執行與管理單個容器(Container)。 * Docker Compose:是一個工具(Tool),用於定義與執行多容器的 Docker 應用程式。它建立在 Docker 之上,透過讀取 YAML 檔案來管理一組相互關聯的容器。
什麼是「多容器編排」 (Orchestration)?
當你的應用程式拆分為多個服務時,你需要處理以下挑戰: 1. 依賴關係:資料庫必須在 API 啟動前準備就緒。 2. 網路通訊:API 服務如何透過特定的名稱找到資料庫服務? 3. 環境一致性:開發、測試、生產環境的配置如何保持同步?
Docker Compose 提供了一種「宣告式」的機制。你只需要告訴 Docker:「我需要一個 Nginx、一個 Python App 和一個 PostgreSQL」,Docker Compose 就會自動處理網路建立、磁碟掛載與啟動順序。如果你正在尋找更多關於自動化部署的資源,可以參考我們的 Docker Compose 實戰指南 來深化你的知識。
Docker Compose 的核心價值:可重複性與一致性
使用 Docker Compose 的最大好處在於可重複性。當你將 docker-compose.yml 提交到 Git 版本控制系統後,任何開發者或 CI/CD 流水線只要執行 docker-compose up,就能在完全相同的環境下重現整套服務架組成的架構,徹底解決了「在我的電腦上明明可以跑」的經典問題。
2. Docker Compose YAML 檔案結構深度解析
YAML (YAML Ain't Markup Language) 是一種人類可讀性極高的資料序列化格式。在 Docker Compose 中,正確的縮排(Indentation)是成敗的關鍵。
YAML 語法基礎與注意事項
在撰寫 Compose 檔案時,請務必遵守以下規則:
* 使用空格而非 Tab:YAML 不支援 Tab 鍵,請務限定位使用空格(通常是 2 個或 4 個)。
* 鍵值對 (Key-Value Pairs):使用冒號加空格 key: value 的格式。
* 列表 (Lists):使用橫線 - 開頭來表示陣列或清單。
* 大小寫敏感:Services 與 services 是不同的,請務必使用小寫。
核心組成要素:Version, Services, Networks, Volumes
一個完整的 docker-compose.yml 通常包含以下四個主要區塊:
version:指定 Compose 檔案的版本格式(雖然在最新的 Docker Compose V2 中這已不再是強制要求,但保留版本號仍是良好的實踐)。services:這是最核心的部分,定義了每一個容器的行為、映像檔、環境變數、連接埠映射等。networks:定義容器之間的通訊網路。透過自定義網路,你可以實現服務間的隔離與安全通訊。volumes:定義持久化儲存空間。確保容器刪除後,資料庫中的數據不會隨之消失。
逐行拆解:一個標準的 docker-compose.yml 範例
讓我們透過一個簡單的結構來觀察各個元件如何協作:
version: '3.8' # 指定版本
services:
web-app: # 服務名稱
image: nginx:latest # 使用的映像檔
ports:
- "8080:80" # 主機連接埠:容器連接埠
networks:
- frontend
networks:
frontend: # 定義一個名為 frontend 的網路
driver: bridge
3. 實戰演練:從零開始部署一個 Web + Database + Redis 系統
為了讓你真正掌握技術,我們將模擬一個真實的開發場景:部署一個包含 Nginx (反向代理)、Python API (應用程式)、PostgreSQL (資料庫) 與 Redis (快取) 的完整系統。
環境準備與專案目錄結構
在開始之前,建議建立如下的目錄結構,這有助於管理你的程式碼與設定檔:
my-project/
├── docker-compose.yml
├── .env # 存放敏感資訊(如密碼)
├── nginx/
│ └── default.conf # Nginx 設定檔
├── app/
│ ├── main.py # Python 程式碼
│ └── requirements.txt
└── data/ # 用於掛載資料庫持久化
撰寫 docker-compose.yml(包含詳細註解)
請將以下內容複製到你的 docker-compose.yml 中。這是一個具備生產力水準的配置範例。
version: '3.8'
services:
# 1. Nginx 反向代理服務
proxy:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- api
networks:
- web_network
# 2. Python API 應用程式
api:
build: ./app # 使用當前目錄下的 Dockerfile 進行構建
environment:
- DATABASE_URL=postgresql://user:password@db:5432/mydb
- REDIS_HOST=cache
depends_on:
- db
- cache
networks:
- web_network
- backend_network
# 3. PostgreSQL 資料庫
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: user
POSTG驗證_PASSWORD: password
POSTGRES_DB: mydb
volumes:
- db_data:/var/lib/postgresql/data
networks:
- backend_network
# 4. Redis 快取服務
cache:
image: redis:7-alpine
networks:
- backend_network
# 定義網路隔離
networks:
web_network:
driver: bridge # 用於前端與 API 溝通
backend_network:
driver: bridge # 用於 API 與 DB/Redis 溝通,確保 DB 不直接暴露在外部
# 定義持久化磁碟卷
volumes:
db_data: # 命名卷,確保資料庫重啟後數據不丟失
關鍵參數詳解
在上述範例中,有幾個進階參數是開發者必須精通的:
build:與image不同,build會告訴 Docker Compose 去找尋指定的路徑下的Dockerfile來現場製作映像檔。這對於開發階段非常有用。depends_on:這定義了啟動順序。在上面的例子中,api會等待db與cache啟動後才開始執行。但請注意,depends_on只保證容器「啟動」,不保證內部的資料庫服務已經「準備好接收連線」,因此在程式碼中仍需加入重試機制。volumes(Bind Mount vs Named Volume):- Bind Mount (
./nginx/...:/etc/...):將主機的特定路徑掛載進容器,適合存放設定檔,方便即時修改。 - Named Volume (
db_data:/var/lib/...):由 Docker 管理的命名卷,效能較好,適合存放資料庫等需要高 IO 的數據。
- Bind Mount (
networks(網路隔離):我們建立了web_network與backend_network。注意到proxy只能連到api,而db卻無法被proxy直接存取。這種隔離機制是提升系統安全性的核心手段。
執行指令:掌控你的容器生命週期
學會了撰寫 YAML,接下來就是如何操作。請在專案目錄下執行以下指令:
- 啟動所有服務(後台執行):
docker-le-compose up -d - 查看服務運行狀態:
docker-compose ps - 查看服務日誌(除錯必備):
docker-compose logs -f api - 停止並移除所有容器與網路:
docker-compose down - 重新構建並啟動(當你修改了 Dockerfile 時):
docker-compose up -d --build
如果你在部署過程中遇到環境變數配置的困難,可以利用我們的 DevOps 自動化工具集 來優化你的工作流程。
4. 進階技巧:優化你的 Docker Compose 配置
當你的專案規模擴大,單純的 docker-compose.yml 會變得難以維護。以下是專業開發者會使用的三種進階技巧。
使用 .env 檔案管理環境變數
絕對不要將資料庫密碼或 API Key 直接寫死在 docker-compose.yml 中。這會導致安全風險,且不利於不同環境的切換。
建立一個 .env 檔案:
DB_PASSWORD=super_secret_password_12html
API_PORT=8000
然後在 docker-compose.yml 中引用:
services:
db:
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
這樣一來,你只需要在 .env 中修改,就能在不更動主配置檔案的情況下切換環境。
網路隔離 (Networks) 的實作與重要性
在微服務架構中,安全性來自於「最小權限原則」。你不希望你的資料庫直接暴露在公網(Public Network)上。透過建立兩個不同的網路(如前文範例所示),你可以確保只有 API 服務具備存取資料庫的權力,而 Nginx 只能看到 API。這能有效防止攻擊者透過 Web 漏洞直接對資料庫進行掃描或攻擊。
多階段部署 (Multiple Compose Files) 的應用場景
在開發(Development)與生產(Production)環境中,配置往往不同。例如,開發環境需要掛載程式碼(Hot Reload),但生產環境則需要使用預先構建好的映像檔。
你可以建立兩個檔案:
1. docker-compose.yml (基礎配置)
2. docker-compose.override.yml (開發專用,自動覆蓋基礎配置)
當你執行 docker-compose up 時,Docker 會自動合併這兩個檔案。這讓你能夠保持基礎配置的乾淨,同時靈活地在本地開發時加入偵錯工具或額外的掛載路徑。
5. 效能與安全性最佳實踐 (Best Practices)
為了讓你的 Docker Compose 配置達到專業級水準,請遵循以下準則:
避免使用 latest 標籤
在 image: nginx:latest 中使用 latest 是非常危險的。當 Nginx 發布新版本並引入破壞性變更(Breaking Changes)時,你的服務可能會在自動更新後突然崩潰。永遠指定明確的版本號,例如 nginx:1.25-alpine。
資源限制 (Resource Limits) 的設定
如果你的伺服器同時運行多個服務,一個失控的服務(例如記憶體洩漏的 Python App)可能會耗盡主機的所有資源,導致整個系統癱瘓。你可以在 Compose 中加入資源限制:
services:
api:
deploy:
resources:
limits:
cpus: '0.50' # 限制最多使用 0.5 個 CPU
memory: 512M # 限制最多使用 512MB 記憶體
最小權限原則與 User 配置
預設情況下,容器內的進程通常以 root 身份執行。為了安全起見,建議在 Dockerfile 中建立一個非 root 用戶,並在 Compose 中透過 user: "1000:1000" 來指定執行身份,減少容器逃逸攻擊的風險。
6. Docker Compose vs. Kubernetes (K8s):你該如何選擇?
隨著技術進階,你可能會遇到另一個強大的工具:Kubernetes。那麼,在什麼樣的場景下該使用 Docker Compose,何時該轉向 K8s 呢?
以下是兩者的詳細比較:
| 特性 | Docker Compose | Kubernetes (K8s) |
|---|---|---|
| 主要用途 | 單機多容器開發與簡單部署 | 分散式集群編排與大規模生產環境 |
| 學習曲線 | 低,非常容易上手 | 極高,需要深厚的運維知識 |
| 擴展性 (Scaling) | 僅限於單一主機的擴展 | 支援跨多台伺服器的水平擴展 |
| 自我修復 | 基本的容器重啟功能 | 強大的自動化健康檢查與自動重啟 |
| 複雜度 | 低,適合小型專案、CI/CD 測試 | 高,適合大型微服務架構 |
| 網路管理 | 簡單的橋接網路 (Bridge) | 複雜的 Service, Ingress, CNI 網路 |
總結建議: * 如果你正在進行本地開發、單機小規模部署或是自動化測試環境,Docker Compose 是你的不二之選。 * 如果你的應用需要跨伺服器擴展、具備高可用性 (High Availability) 且面臨大規模流量,則應考慮學習 Kubernetes。
7. 常見問題與疑難排解 (FAQ)
Q1: 我修改了 docker-compose.yml 後,如何讓變更生效?
A: 最安全的方法是執行 docker-compose up -d。Docker Compose 會自動偵測設定檔的變更,並僅重新建立(Recreate)那些發生變動的服務,而不會影響其他未變動的服務。
Q2: docker-compose down 會刪除我的資料庫數據嗎?
A: 這取決於你如何配置。如果你使用的是 Named Volume(如範例中的 db_data),執行 down 僅會移除容器與網路,數據會保留。但如果你使用了 -v 參數(即 docker-compose down -v),則會連同所有命名卷一起刪除,請務必小心!
Q3: 為什麼我的 API 服務啟動了,但卻連不到資料庫?
A: 這通常有兩個原因:
1. 啟動順序問題:資料庫容器雖然啟動了,但內部的資料庫引擎還在初始化。建議在程式碼中加入「重試連線」的邏輯。
2. 網路配置錯誤:請檢查兩個服務是否位於同一個 networks 區塊下。
Q4: 如何在 Docker Compose 中使用本地開發的程式碼?
A: 使用 volumes 的 Bind Mount 功能。例如:./app:/app,這會將你主機上的 ./app 目錄直接映射到容器內,你在主機修改程式碼,容器內會立即同步,實現熱更新。
Q5: 可以在 Docker Compose 中直接使用 build 指令嗎?
A: 可以。build: . 會告訴 Compose 在當前目錄尋找 Dockerfile。這對於開發階段非常方便,讓你不需要手動執行 docker build。
Q6: 為什麼我的 depends_on 沒有生效?
A: 如前所述,depends_on 只保證「容器啟動順序」,不保證「服務就緒」。如果你的應用程式在資料庫完全啟動前就嘗試連線並失敗,程式可能會直接崩潰。建議配合 healthcheck 功能使用。
結論
Docker Compose YAML 是一項極其強大的技術,它將複雜的容器化部署流程簡化為可維護、可重複且可版本化的設定檔。透過掌握 服務定義、網路隔離、磁碟掛載、環境變數管理 以及 資源限制,你能夠建立出既專業又穩定的開發與部署環境。
從單機開發到微服務架構,Docker Compose 是每一位現代開發者與 DevOps 工程師必備的利器。現在,就開始嘗試撰寫你的第一個 docker-compose.yml,將你的應用程式從手動部署的泥淖中解脫出來吧!