Docker Compose 初學者指南:使用範例解析
更新日期: 2025 年 3 月 4 日
本文為 Docker 進階介紹 系列文,第 7 篇:
- 初學者指南:深入了解 WSL 2(Windows Subsystem for Linux 2)
- 虛擬機器(VM)是什麼?完整入門指南
- 什麼是核心(Kernel)?初學者完整指南
- Docker vs. 虛擬機器(VM):初學者完整比較指南
- 如何在 WSL 2 + Docker 環境中開發 Django:安裝順序與最佳實踐
- 初學者指南:什麼是 Dockerfile?—— 以實際範例解析
- Docker Compose 初學者指南:使用範例解析 👈進度
- Docker Compose:up vs up -d 的差異與應用
- Linux 常見指令入門:從 sudo 到日常操作
- Linux 解決方案:VSCode 無法儲存檔案權限問題
閱讀本文前,建議先理解 Docker 基本介紹系列文 相關概念。
在開發與部署應用程式時,容器化技術(Containerization)已成為不可或缺的工具。
Docker 讓開發者能夠輕鬆地將應用程式打包並部署在任何環境中,而 Docker Compose 則進一步簡化了管理多個容器的過程。
本篇文章將介紹 Docker Compose 的概念,並透過您提供的 docker-compose.yml
檔案進行解析,讓初學者能夠快速理解如何使用它來管理應用程式的多個服務。
什麼是 Docker Compose?
Docker Compose 是 Docker 官方提供 的一款工具,專門用來幫助開發者 定義、管理及運行多個 Docker 容器。
在開發現代應用程式時,往往不只需要一個單一的容器,而是由多個彼此協作的服務組成。
例如,一個典型的 Web 應用可能包含:
- 應用伺服器(Web Server):負責處理使用者的請求,提供前端頁面或 API(例如 Nginx、Node.js)。
- 資料庫(Database):存儲應用程式的數據(例如 MySQL、PostgreSQL、MongoDB)。
- 背景工作(Background Worker):執行長時間運行的任務,如爬蟲、排程任務、訊息隊列處理(例如 Celery、Redis)。
若要手動啟動這些服務,每個容器都需要單獨執行 docker run
命令,不僅繁瑣,還容易因錯誤的設定導致服務無法正常連接。
因此,Docker Compose 透過 YAML 檔案(docker-compose.yml
)來統一管理所有容器的設定,讓開發者能夠 用簡單的指令一次啟動、停止或管理整個應用環境。
Docker Compose 的主要優勢
Docker Compose 主要解決了傳統 Docker 命令管理多個容器的痛點,使開發流程更簡單、高效,並確保環境一致性。以下是其三大主要優勢:
1️⃣ 簡化容器管理
傳統上,若要啟動多個容器,必須使用 docker run
指令手動執行:
docker run -d --name mongo_db -p 27017:27017 mongo:latest
docker run -d --name web_app --link mongo_db:mongo -v $(pwd):/app -e TZ=Asia/Taipei web_app_image
docker run -d --name scraper --link mongo_db:mongo -e TZ=Asia/Taipei scraper_image
這種方式不僅需要多行命令,還要確保各個容器之間的網路連接與依賴關係正確。
Docker Compose 讓這一切變得簡單,開發者只需撰寫 docker-compose.yml
,然後一行指令即可啟動:
docker-compose up -d
這樣就能自動建立、啟動所有定義好的服務,避免手動輸入長串命令帶來的繁瑣與錯誤。
2️⃣ 提升開發效率
適用於微服務架構(Microservices Architecture) 現代應用程式經常採用微服務架構。
每個功能模組都可能是一個獨立的容器,Docker Compose 允許開發者:
- 同時啟動、停止、重啟所有服務,大幅提升開發測試效率。
- 自動處理容器依賴關係,確保某些服務(如資料庫)在應用程式啟動前已經準備就緒。
- 支援開發與測試環境,允許快速建立與銷毀環境,而不影響正式環境。
例如,當 web
服務 需要等待 MongoDB 先啟動 時,Docker Compose 允許我們在 docker-compose.yml
設定:
depends_on:
- mongodb
這樣在執行 docker-compose up
時,MongoDB 會先啟動,然後 web
服務才會啟動,確保應用程式能夠正確存取資料庫。
3️⃣ 環境一致性
確保「開發、測試、部署環境」一致,避免「在我電腦上可以跑」的問題 傳統開發方式。
開發者可能在本機手動安裝 MongoDB、Nginx 或其他依賴,但當換到測試或部署環境時,因為版本不同、環境變數不同,可能會導致應用程式無法正常運作。
Docker Compose 透過 docker-compose.yml
讓所有環境的設定都統一,如:
- 版本固定(例如
image: mongo:latest
確保 MongoDB 使用最新版)。 - 依賴服務自動配置(
depends_on
確保資料庫先啟動)。 - 環境變數一致(
environment
設定相同的時區、API Key 等)。
這樣,即使應用程式換到其他開發者的電腦、測試環境,或是正式部署到伺服器,都能保證完全相同的運行環境。
graph TD; A["Docker Compose"] -->|"管理"| B["Web 應用 (web)"] A -->|管理| C["爬蟲服務 (scraper)"] A -->|管理| D["資料庫 (mongodb)"] B -->|依賴| D C -->|依賴| D D -->|持久化數據| E[Volume: mongodb_data] subgraph "Docker 容器" B C D end subgraph "本機或雲端" E end
docker-compose.yml
檔案解析
現在我們來解析以下 docker-compose.yml
範例,並逐步說明它的功能。
services:
web:
build: .
network_mode: "host"
environment:
- TZ=Asia/Taipei
volumes:
- .:/app
depends_on:
- mongodb
scraper:
build: .
environment:
- TZ=Asia/Taipei
depends_on:
- mongodb
working_dir: /app
command: ["python3", "/app/music_events/scripts/scraper.py"]
restart: always
mongodb:
image: mongo:latest
container_name: mongo_db
restart: always
ports:
- "27017:27017"
volumes:
- mongodb_data:/data/db
volumes:
mongodb_data:
在 docker-compose.yml
檔案中,我們透過 services
區塊來定義應用程式的各個組件。這個專案包含三個主要的服務:
web
(Web 應用程式):負責處理 HTTP 請求,可能是一個 Flask、Django、Node.js 或其他 Web 伺服器。scraper
(爬蟲服務):負責執行定期抓取音樂活動的腳本,將資料儲存到 MongoDB。mongodb
(MongoDB 資料庫):提供儲存後端,讓web
和scraper
服務存取數據。
這些服務的設定方式如下:
Web 應用服務 (web
)
Web 服務的設定如下:
web:
build: .
network_mode: "host"
environment:
- TZ=Asia/Taipei
volumes:
- .:/app
depends_on:
- mongodb
設定解析:
build: .
- 這表示該服務的 Docker 映像檔(image) 將從目前目錄的
Dockerfile
建立。 - 當
docker-compose up
執行時,它會自動在當前目錄查找Dockerfile
,並依照定義的指令建置該映像檔。 - 如果本機端已有相同的映像檔,則會直接使用快取版本,以提升啟動效率。
- 這表示該服務的 Docker 映像檔(image) 將從目前目錄的
network_mode: "host"
- 該選項將容器的網路模式設為 主機模式,意味著容器內的應用程式會直接使用主機的網路,而不需要額外的端口轉發(如
ports
設定)。 - 這適用於需要與主機系統緊密整合的應用,如:
- 需要存取本機網絡上的服務。
- 需要與其他應用程式共用相同的網路環境。
- 該選項將容器的網路模式設為 主機模式,意味著容器內的應用程式會直接使用主機的網路,而不需要額外的端口轉發(如
environment:
- 這裡設定了一個環境變數:
- TZ=Asia/Taipei
- 用途:將容器的時區設為 台北時間(Asia/Taipei),確保記錄的時間戳記與當地時間一致。
- 這裡設定了一個環境變數:
volumes:
- 這行指令:
- .:/app
表示將 本機當前目錄(.
) 掛載到容器內的/app
目錄。 - 作用:
- 讓本機的程式碼能夠即時同步到容器內,適用於開發環境。
- 避免每次修改程式碼後,都需要重新建置映像檔。
- 這行指令:
depends_on:
- 這裡定義了
web
服務依賴 MongoDB:depends_on: - mongodb
- 作用:
- 確保 MongoDB 服務在 Web 服務啟動前已經準備就緒,避免應用程式因找不到資料庫而發生錯誤。
- 這裡定義了
爬蟲服務 (scraper
)
爬蟲服務負責定期抓取音樂活動數據,並將其存入 MongoDB。它的設定如下:
scraper:
build: .
environment:
- TZ=Asia/Taipei
depends_on:
- mongodb
working_dir: /app
command: ["python3", "/app/music_events/scripts/scraper.py"]
restart: always
設定解析:
build: .
- 與
web
服務相同,這行指令表示使用當前目錄的Dockerfile
建置映像檔。
- 與
environment:
- 設定環境變數
TZ=Asia/Taipei
,確保時區一致。
- 設定環境變數
depends_on:
- 這行指令:
depends_on: - mongodb
確保爬蟲程式在 MongoDB 服務準備好後才會啟動,以防止爬蟲嘗試存取尚未啟動的資料庫。
- 這行指令:
working_dir: /app
- 設定 容器內的工作目錄 為
/app
,這樣所有的程式執行時,都會以/app
作為基礎目錄。
- 設定 容器內的工作目錄 為
command:
- 這裡設定爬蟲服務在啟動時執行的命令:
command: ["python3", "/app/music_events/scripts/scraper.py"]
- 這行指令會執行
python3 /app/music_events/scripts/scraper.py
,開始爬取音樂活動數據。 command
陣列的格式避免了 Shell 解析問題,確保指令正確執行。
- 這行指令會執行
- 這裡設定爬蟲服務在啟動時執行的命令:
restart: always
- 這個設定確保容器在異常關閉後會自動重新啟動:
- 如果容器崩潰(例如因錯誤導致程序終止),Docker 會自動重新啟動該容器。
- 適合長時間運行的爬蟲服務,確保其持續運行。
- 這個設定確保容器在異常關閉後會自動重新啟動:
MongoDB 資料庫 (mongodb
)
MongoDB 服務提供 Web 應用和爬蟲服務使用的資料庫,設定如下:
mongodb:
image: mongo:latest
container_name: mongo_db
restart: always
ports:
- "27017:27017"
volumes:
- mongodb_data:/data/db
設定解析:
image: mongo:latest
- 指定使用 MongoDB 官方映像檔,並拉取最新版本(
latest
)。 - 若本機沒有該映像檔,Docker 會自動從 Docker Hub 下載。
- 指定使用 MongoDB 官方映像檔,並拉取最新版本(
container_name: mongo_db
- 指定容器名稱為
mongo_db
,方便管理與識別。
- 指定容器名稱為
restart: always
- 確保 MongoDB 容器在異常關閉後自動重啟。
ports:
ports: - "27017:27017"
- 作用:
- 將 本機的 27017 端口 映射到 容器內的 27017 端口,讓本機應用程式可以直接存取 MongoDB。
27017
是 MongoDB 預設的連接端口。
- 作用:
volumes:
volumes: - mongodb_data:/data/db
- 作用:
- 使用 Docker Volume(
mongodb_data
)來存儲 MongoDB 的數據,避免容器刪除後資料遺失。 - 資料會存放在
/data/db
目錄,確保 MongoDB 內部數據可持久化儲存。
- 使用 Docker Volume(
- 作用:
2.4 定義 Volume
在 volumes
區塊中,我們定義了 mongodb_data
,確保 MongoDB 資料庫的數據能夠持久化:
volumes:
mongodb_data:
- 這表示 Docker Compose 會 自動建立一個 Volume(
mongodb_data
),並將 MongoDB 的數據儲存在該 Volume 內,即使容器刪除,數據也不會丟失。 - 避免 MongoDB 服務 因容器刪除或重啟而遺失數據,確保應用的穩定運行。
同樣是 volumes
,為什麼 MongoDB 和 Web 應用的效果不同?
Docker volumes
主要有兩種掛載方式:
- 命名 Volume(Named Volume):Docker 會管理數據存放位置,適合用於 持久化存儲。
- 綁定掛載(Bind Mount):直接掛載本機目錄到容器,適合用於 開發環境的程式碼同步。
在您的 docker-compose.yml
中:
- MongoDB 使用的是命名 Volume(
mongodb_data:/data/db
),確保 MongoDB 的資料持久化。 - Web 應用使用的是綁定掛載(
.:/app
),確保 開發時程式碼變更能立即反映到容器內。
MongoDB:volumes: mongodb_data:/data/db
volumes:
- mongodb_data:/data/db
行為:
- 這是 命名 Volume,Docker 會在內部創建一個持久化存儲區(
mongodb_data
),並將其掛載到容器內的/data/db
目錄。 - 即使刪除 MongoDB 容器,數據仍然保留,因為 Volume 與容器是獨立的。
- 適用於 資料庫、上傳文件等需要持久存儲的應用場景。
效果:
✅ MongoDB 內的資料庫數據不會因容器刪除而消失。
✅ 即使 docker-compose down
,數據仍然存在,容器重啟後可以繼續使用。
✅ Docker 會自動管理 Volume,不需要開發者手動指定存放路徑。
Web 應用:volumes: .:/app
volumes:
- .:/app
行為:
- 這是 綁定掛載(Bind Mount),直接將本機當前目錄(
.
)映射到容器內的/app
目錄。 - 這樣 本機的程式碼變更會立即同步到容器內,不需要重新建置映像檔或重啟容器。
- 主要用於 開發環境,讓開發者可以即時修改程式碼並立即看到變更結果。
效果:
✅ 開發時可以直接修改程式碼,容器內應用程式會立即更新,提升開發效率。
✅ 適合 Node.js、Flask、Django 等動態開發框架,程式碼變更時不需要重啟容器。
🚨 但如果刪除 Web 容器,本機程式碼仍然保留,因為它存在於本機,不是 Docker Volume。
兩者的本質區別
特性 | MongoDB (持久化數據) | Web 應用 (程式碼同步) |
---|---|---|
掛載方式 | 命名 Volume(Named Volume) | 綁定掛載(Bind Mount) |
數據存放位置 | Docker 內部管理的 Volume | 本機目錄 |
主要用途 | 儲存數據,確保數據持久化 | 開發時程式碼同步,不影響正式環境 |
容器刪除後數據是否保留? | ✅ 會保留 | 🚨 不適用,程式碼本來就在本機 |
是否適合正式環境? | ✅ 適合,確保數據安全 | 🚨 不適合,正式環境應該將程式碼內建到映像檔 |
volumes
的作用取決於應用程式的行為
相同的 volumes
設定,之所以在 MongoDB 和 Web 應用上有不同的效果,關鍵在於:
- MongoDB 是一個資料庫,它會在
/data/db
目錄內儲存數據,所以我們需要 Volume 來持久化數據,避免資料丟失。 - Web 應用是一個程式碼執行環境,它不會自行產生需要持久化的數據,所以我們使用綁定掛載來讓程式碼保持同步,而不影響正式環境。
什麼時候該使用哪種 volumes
設定?
如果你的應用程式會產生需要長期儲存的數據(如資料庫、上傳檔案),請使用 命名 Volume,例如:
volumes:
- db_data:/var/lib/postgresql/data
✅ 適用於資料庫(MySQL、PostgreSQL、MongoDB)、檔案存儲服務。
如果你的應用程式只需要開發時即時同步程式碼,請使用 綁定掛載,例如:
volumes:
- .:/usr/src/app
✅ 適用於開發環境的 Web 應用(Node.js、Flask、Django)。
如何使用 Docker Compose 啟動這個應用?
現在我們已經解析了 docker-compose.yml
,接下來,我們來看看如何執行這個應用。
安裝 Docker & Docker Compose
如果您的系統尚未安裝 Docker 和 Docker Compose,請先安裝:
- Windows / macOS:可以從 Docker 官網 下載並安裝 Docker Desktop。
- Linux:可以使用
apt
或yum
安裝:
sudo apt update && sudo apt install -y docker docker-compose
啟動應用
當 docker-compose.yml
檔案準備好後,只需要在相同目錄下執行以下指令:
docker-compose up -d
這個指令會:
- 根據
docker-compose.yml
啟動web
、scraper
和mongodb
服務。 - 自動下載
mongo:latest
映像檔(如果本機沒有)。 - 以背景模式執行(
-d
參數),不會佔用終端機。
graph TD; A[執行 \`docker-compose up\`] -->|讀取 \`docker-compose.yml\`| B[解析 \`services\` 定義] B -->|檢查是否已經存在對應的映像檔| C[如果不存在,則根據 \`build\` 建置映像檔] C --> D[建立並啟動容器] D -->|檢查 \`depends_on\` 依賴關係| E[確保依賴服務(如 MongoDB)先啟動] E -->|初始化 \`volumes\`| F[掛載 Volume(如 \`mongodb_data\`)] F -->|初始化 \`network\`| G[建立並配置 Docker 網路] G -->|啟動 \`web\`、\`scraper\` 等服務| H[服務開始運行] H -->|監控 \`restart\` 設定| I[如果 \`restart: always\`,則異常時自動重啟]
查看執行狀態
您可以使用以下指令查看目前運行的容器:
docker ps
如果要查看個別服務的日誌,可以執行:
docker-compose logs web
docker-compose logs scraper
docker-compose logs mongodb
停止與刪除容器
如果要停止所有服務,可以執行:
docker-compose down
這個指令會:
- 停止並移除所有定義的容器。
- 但 不會刪除
mongodb_data
Volume,因此 MongoDB 的數據仍然存在。
如果希望刪除 所有的容器與 Volume,請執行:
docker-compose down -v
結論
這篇文章介紹了 Docker Compose 的基本概念,並透過提供的 docker-compose.yml
檔案解析了 web
、scraper
和 mongodb
服務的配置。
透過 Docker Compose,可以輕鬆管理多個容器,讓開發環境更加一致,並提升應用的可維護性。
如果您是初學者,建議嘗試修改 docker-compose.yml
,加入其他服務,並使用 docker-compose up
測試運行效果,這將有助於加深對 Docker Compose 的理解! 🚀