在現代軟體開發的浪潮中,容器化技術已從一個新穎的概念演變為不可或缺的標準實踐。Docker 以其輕量、高效、可攜的特性,徹底改變了應用程式的打包、分發與部署方式。然而,當應用程式的架構變得複雜,由多個互相依賴的服務(例如前端、後端 API、資料庫、快取服務)組成時,單獨管理每一個 Docker 容器的生命週期就成了一項繁瑣且容易出錯的挑戰。要部署容器,尤其是多個容器和服務時,需要更有效率的方法。
為了解決這個痛點,Docker Compose 應運而生。它是一個用於定義和執行多容器 Docker 應用程式的強大工具。透過一個簡單的 YAML 設定檔,開發者可以精確描述整個應用程式的服務架構、網路配置、儲存卷等,然後僅需一個命令,就能一鍵啟動、關閉或管理整個應用程式堆疊。
本篇文章是系列文的一部分,將深入探討 Docker Compose 的各個層面,從核心概念、安裝設定,到 docker-compose.yml 文件的詳細語法解析,再結合豐富的實戰範例與進階技巧。無論您是初次接觸 Docker 的新手,還是希望提升容器管理效率的開發者,本指南都將為您提供一份詳盡且具實踐價值的參考。
什麼是 Docker Compose?核心優勢概覽
簡單來說,Docker Compose 是一個「多容器應用程式的劇本」。開發者在這個劇本(docker-compose.yml yaml檔案)中,定義好應用程式需要的所有角色(各個服務容器)、他們之間的溝通方式(網路)以及他們的道具和記憶(儲存卷)。然後,Docker Compose 這位導演,就會根據劇本,完美地協調所有角色,讓整個應用程式順利上演。
如何使用 Docker Compose 帶來的主要優勢包括:
- 簡化複雜的容器管理:告別冗長且容易出錯的 docker run 指令鏈。只需一個 docker-compose up 命令,即可啟動所有服務。
- 實現環境一致性:徹底解決「在我的電腦上可以跑」的經典難題。docker-compose.yml 文件確保了從開發、測試環境到生產部署環境的配置完全一致,極大地降低了因環境差異導致的問題。
- 提升開發與協作效率:開發團隊成員只需獲取程式碼和 docker-compose.yml 文件,就能快速在本機建立起完整的開發環境。這對於微服務架構的應用程式尤其重要,能夠讓開發者專注於自身負責的服務,而無需擔心複雜的環境依賴。
- 宣告式設定,易於版本控制:YAML 格式的配置文件直觀易讀,並且可以與應用程式的原始碼一同納入 Git 等版本控制系統,讓整個應用程式的基礎架構也擁有了清晰的變更歷史。
安裝與設定
在開始使用 Docker Compose 之前,您需要先安裝 Docker Engine。
Windows 與 macOS:
最簡單的方式是安裝 docker desktop。Docker Compose 已經作為其核心元件被整合在內,無需額外安裝。
Linux:
您可以先使用官方指引安裝 Docker Engine,然後再安裝 Docker Compose。雖然舊版是透過 pip 或下載二進位檔案安裝,但現在推薦的方式是將其作為 Docker 的一個外掛來安裝。您可以使用以下指令來安裝:
sudo apt-get update sudo apt-get install docker-compose-plugin
安裝完成後,可以透過使用以下命令驗證版本,確認安裝成功:
docker compose version
docker-compose.yml:應用程式的藍圖
docker-compose.yml 是 Docker Compose 的核心,它使用 YAML(YAML Ain’t Markup Language)格式來定義應用程式的配置。這個 yaml檔案 是一種可讀性極高的資料序列化語言,對縮排非常敏感,錯誤的縮排會導致解析失敗。
一個典型的 docker-compose.yml 配置文件主要包含以下幾個頂層鍵:
- version (已棄用但仍常見): 在舊版本中用來指定 Compose 文件格式的版本。在新版的 Docker Compose 中,這個欄位已非必要,但為了相容性,您仍可能在許多範例中看到它。
- services: 這是最重要的部分,用來定義應用程式中的各個服務(容器)。
- networks: 定義服務可以連接的自訂網路,提供容器間的隔離與通信。
- volumes: 定義具名儲存卷,用於數據的持久化。
- secrets: 用於管理敏感資料,如密碼、API 金鑰等。
- configs: 用於管理非敏感的配置文件。
services:定義應用程式的組件
在 services 區塊下,您可以定義一個或多個服務。每個服務都對應一個容器,並擁有一系列的設定選項。
以下是一個包含 web服務、Redis 快取和 PostgreSQL 資料庫(或 mysql)的範例,我們將以此來解析各個常用指令:
# docker-compose.yml
services:
webapp:
build:
context: .
dockerfile: Dockerfile
container_name: my_web_app
ports:
- "8000:5000"
volumes:
- .:/app
environment:
- FLASK_ENV=development
- DATABASE_URL=postgresql://user:password@db:5432/mydatabase
depends_on:
- db
- cache
restart: on-failure
db:
image: postgres:14-alpine
container_name: my_postgres_db
environment:
POSTGRES_DB: mydatabase
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d mydatabase"]
interval: 10s
timeout: 5s
retries: 5
restart: always
cache:
image: redis:7-alpine
container_name: my_redis_cache
restart: always
volumes:
postgres_data:
build vs image
image: 直接指定要使用的 Docker 映像檔。Compose 會先在本地尋找,若找不到則會從 Docker Hub(或指定的登錄檔)執行 docker pull 來拉取。
- 範例:db 服務使用了官方的 postgres:14-alpine 容器映像。
build: 如果您的服務需要自訂的映像檔,可以使用 build 指令。
- context: 指定 Dockerfile 所在的資料夾路徑。. 表示當前目錄。
- dockerfile: 指定 Dockerfile 的檔案名稱,如果不是預設的 Dockerfile。
- 範例:webapp 服務會根據當前資料夾下的 Dockerfile 來建置容器映像。
container_name
指定一個自訂的容器名稱。若不指定,Compose 會自動生成一個格式為 <專案目錄名>_<服務名>_<編號> 的名稱。指定名稱有助於指令稿編寫和辨識,是選擇性的。
ports
將主機的端口映射到容器的端口,格式為 “HOST_PORT:CONTAINER_PORT”。
- 範例:”8000:5000″ 將主機的 8000 端口映射到 webapp 容器的 5000 端口。這意味著您可以透過 http://localhost:8000 存取您的 Web 應用程式。
volumes
volumes 是實現資料持久化和程式碼同步的關鍵,主要有兩種形式:
具名儲存卷 (Named Volume):
- 語法:volume_name:/path/in/container
- 這是 Docker 官方推薦的資料持久化方式。Docker 會在主機上的一個特定目錄(由 Docker 管理)中建立並管理這個儲存卷。
- 它的生命週期獨立於容器,即使容器被刪除,數據依然存在。
- 範例:db 服務中的 postgres_data:/var/lib/postgresql/data。postgres_data 在文件末尾的 volumes 頂層鍵中定義。這確保了 PostgreSQL 的資料庫檔案在容器重啟或重建後不會遺失。
綁定掛載 (Bind Mount):
- 語法:/path/on/host:/path/in/container
- 直接將主機上的一個文件或資料夾掛載到容器中。
- 這在開發環境中非常實用,可以將本地的程式碼資料夾掛載到容器中。當您在本地修改程式碼時,變更會即時反映到容器內,無需重新建置映像檔。
- 範例:webapp 服務中的 .:/app。它將當前專案目錄掛載到容器的 /app 目錄,實現了開發時的熱重載。
environment 和 env_file
- environment: 用於設定環境變數。可以是一個列表或一個字典。
- 範例:db 服務設定了 POSTGRES_DB 等變數,用於初始化資料庫。
- env_file: 從一個 env file 中讀取環境變數。這有助於將敏感資訊(如密碼、API 金鑰)與 docker-compose.yml 分離。預設會讀取專案根目錄下的 .env 文件。
yaml services: webapp: env_file: – ./common.env – ./webapp.env
depends_on
定義服務之間的啟動依賴關係。Compose 會按照依賴順序啟動服務。
- 範例:webapp 服務設定了 depends_on: [db, cache],這意味著 Compose 會先啟動 db 和 cache 服務,然後再啟動 webapp。
- 重要提示:depends_on 只保證容器的啟動順序,並不保證容器內的應用程式(如資料庫服務)已經準備好接收連線。
healthcheck
為了解決 depends_on 的局限性,healthcheck 應運而生。它允許您定義一個命令來檢查容器內的服務是否健康。一個不健康的容器將不會被視為「已就緒」。
- 範例:db 服務的 healthcheck 使用 pg_isready 指令來確認 PostgreSQL 資料庫是否真的可以接受連線。這比單純的 depends_on 更可靠。
restart
定義容器的重啟策略,以應對容器意外退出的情況。
- no: 預設值,不自動重啟。
- always: 無論退出狀態碼是什麼,總是自動重啟。
- on-failure: 僅當退出狀態碼非 0 時才重啟。
- unless-stopped: 總是重啟,除非容器是被人為停止的(例如執行 docker stop)。
networks
Compose 會為每個專案建立一個預設的橋接網路,所有服務都會連接到這個網路上。在網路內部,服務之間可以使用服務名稱作為主機名直接進行通信。
- 例如,在 webapp 服務中,資料庫的連線 URL 可以寫成 postgresql://user:password@db:5432/mydatabase,這裡的 db 就是 db 服務的名稱,Compose 會自動將其解析為 db 容器的內部 IP。
- 您也可以定義自訂網路,以實現更複雜的網路拓撲。
核心 Docker Compose 指令
掌握了 docker-compose.yml 的撰寫後,接下來就是使用 docker compose(注意,新版建議使用 docker compose 而非 docker-compose)命令來管理您的應用程式。一個簡單的 hello world 範例可以只包含一個服務並輸出訊息。
指令 | 說明 | 常用參數 |
---|---|---|
docker compose up | 建立並啟動所有服務。它會整合建置、建立、啟動和附加日誌的過程。 | -d: 在背景(detached mode)執行,即 docker compose up d。 –build: 強制重新建置映像檔。 –scale <service>=<num>: 擴展特定服務的實例數量。 |
docker compose down | 停止並移除所有服務、網路。 | -v: 同時移除具名儲存卷,即 docker compose down v。 –rmi all: 移除所有建置的映像檔。 |
docker compose start | 啟動已存在的服務容器。 | |
docker compose stop | 停止正在執行的服務容器。 | |
docker compose restart | 重啟服務容器。 | |
docker compose ps | 列出專案中所有容器的狀態,類似於 docker ps。 | |
docker compose logs | 查看服務的日誌輸出。 | -f: 持續追蹤日誌輸出。 <service_name>: 只查看特定服務的日誌。 |
docker compose build | 建置或重建服務的映像檔。 | <service_name>: 只建置特定服務。 |
docker compose exec | 在一個正在執行的容器內執行命令。 | <service_name> <command>: 例如 docker compose exec webapp /bin/bash。 |
docker compose run | 為一個服務啟動一個新容器並執行一次性命令。 | –rm: 命令結束後自動移除容器。 |
docker compose rm | 移除已停止的服務容器。 | -f: 強制移除。 -s: 停止容器再移除。 |
up vs run vs exec
- up: 用於啟動並運行在 docker-compose.yml 中定義的「長期服務」,如 Web 伺服器、資料庫。
- run: 用於執行「一次性任務」,例如資料庫遷移、資料初始化腳本。它會建立一個新的臨時容器來執行命令。
- exec: 用於在「已經在運行的容器」內部執行命令,常用於偵錯,例如進入容器的 shell 環境。
進階技巧:多環境配置
在實際專案中,開發、測試環境、生產部署環境的配置通常有所不同。例如,開發環境需要掛載本地程式碼並開啟偵錯模式,而生產環境則需要使用不同的資料庫密碼和關閉偵錯。Docker Compose 提供了優雅的方式來處理這種差異。
Compose 預設會讀取 docker-compose.yml 和 docker-compose.override.yml 兩個文件。您可以:
- docker-compose.yml (基礎配置): 存放所有環境通用的配置,如服務定義、建置指令等。
- docker-compose.override.yml (開發環境覆蓋): 存放僅用於開發環境的配置。例如,掛載本地程式碼、映射偵錯端口、設定開發用的環境變數。這個文件通常會被納入版本控制,方便團隊成員共享。
- docker-compose.prod.yml (生產環境覆蓋): 存放生產部署環境的特定配置,如密碼、資源限制等。這個文件通常不納入版本控制,而是透過 CI/CD 工具或環境變數來管理。
當您執行 docker compose up 時,它會自動合併 docker-compose.yml 和 docker-compose.override.yml。
如果要使用生產環境的配置,可以明確指定文件:
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
Compose 會按照指定的順序合併文件,後者會覆蓋前者的同名配置。
常見問題 (FAQ)
Q1: docker run 和 docker compose up 有什麼區別?
A1: docker run 是用來操作單一容器的命令,您需要為每個容器手動設定網路、儲存、端口等。而 docker compose up 則是基於 docker-compose.yml 文件來管理一整個應用程式(包含多個容器),它會自動處理服務之間的網路連接和依賴關係,是一個更高層次的管理工具。
Q2: Docker Compose 中的容器如何互相通信?
A2: 當您執行 docker compose up 時,Compose 會建立一個預設的自訂橋接網路,並將所有服務都連接到這個網路上。在這個網路內部,任何一個容器都可以透過其他服務的「服務名稱」作為主機名來直接訪問對方。例如,webapp 服務可以透過 http://db:5432 來訪問 db 服務。
Q3: 如何在 Docker Compose 中實現資料持久化?
A3: 主要有兩種方式。對於資料庫、使用者上傳的檔案等需要長期保存的數據,強烈建議使用「具名儲存卷 (Named Volume)」。對於開發環境中需要與本地同步的程式碼,則使用「綁定掛載 (Bind Mount)」。
Q4: depends_on 能保證我的資料庫服務完全準備好嗎?
A4: 不能。depends_on 僅確保容器的啟動順序,但無法保證容器內的應用程式(如 PostgreSQL 服務)已經初始化完畢並準備好接受連線。更可靠的方式是結合使用 depends_on 和 healthcheck,或者在您的應用程式程式碼中實現連線重試的邏輯。
Q5: 我可以在同一個服務中同時使用 build 和 image 嗎?
A5: 可以。當兩者並存時,Compose 會使用 build 區塊的設定來建置映像檔,然後給這個建置好的映像檔打上 image 區塊指定的標籤(tag)。這有助於管理自訂映像檔的版本。
Q6: 如何安全地管理密碼等敏感資訊?
A6: 避免將密碼直接寫在 docker-compose.yml 中。推薦的方法有:
- 使用 .env 文件(env file),並將其加入 .gitignore,避免提交到版本庫。
- 在 CI/CD 環境中,透過系統的環境變數注入。
- 對於更安全的場景(如 Swarm 或 Kubernetes),使用 Docker Secrets 或 Kubernetes Secrets。
總結
Docker Compose 不僅僅是一個工具,它更是一種現代化的開發哲學。它將基礎設施即程式碼(Infrastructure as Code)的理念帶入了本地開發和中小型部署場景,極大地提升了開發流程的標準化、自動化和可靠性。
透過這份指南,我們從 Docker Compose 的核心價值出發,深入解析了其配置文件的每一個關鍵細節,並掌握了核心的管理命令。您現在應該具備了使用 Docker Compose 來建構、管理和部署容器化應用程式的堅實基礎。
雖然對於大規模、高可用的生產環境,Kubernetes 這樣的容器編排平台是最終的選擇,但 Docker Compose 在開發、測試以及中小型專案的部署中,依然是無可替代的最佳利器。將 Docker Compose 融入您的日常工作流程,將為您和您的團隊帶來前所未有的便利與效率。