Docker Compose 初學者指南:使用範例解析

更新日期: 2025 年 3 月 4 日

在開發與部署應用程式時,容器化技術(Containerization)已成為不可或缺的工具。

Docker 讓開發者能夠輕鬆地將應用程式打包並部署在任何環境中,而 Docker Compose 則進一步簡化了管理多個容器的過程。

本篇文章將介紹 Docker Compose 的概念,並透過您提供的 docker-compose.yml 檔案進行解析,讓初學者能夠快速理解如何使用它來管理應用程式的多個服務。


什麼是 Docker Compose?

Docker ComposeDocker 官方提供 的一款工具,專門用來幫助開發者 定義、管理及運行多個 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 區塊來定義應用程式的各個組件。這個專案包含三個主要的服務:

  1. web(Web 應用程式):負責處理 HTTP 請求,可能是一個 Flask、Django、Node.js 或其他 Web 伺服器。
  2. scraper(爬蟲服務):負責執行定期抓取音樂活動的腳本,將資料儲存到 MongoDB。
  3. mongodb(MongoDB 資料庫):提供儲存後端,讓 webscraper 服務存取數據。

這些服務的設定方式如下:

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,並依照定義的指令建置該映像檔。
    • 如果本機端已有相同的映像檔,則會直接使用快取版本,以提升啟動效率。
  • network_mode: "host"
    • 該選項將容器的網路模式設為 主機模式,意味著容器內的應用程式會直接使用主機的網路,而不需要額外的端口轉發(如 ports 設定)。
    • 這適用於需要與主機系統緊密整合的應用,如:
      • 需要存取本機網絡上的服務。
      • 需要與其他應用程式共用相同的網路環境。
  • environment:
    • 這裡設定了一個環境變數: - TZ=Asia/Taipei
    • 用途:將容器的時區設為 台北時間(Asia/Taipei),確保記錄的時間戳記與當地時間一致。
  • volumes:
    • 這行指令: - .:/app 表示將 本機當前目錄(. 掛載到容器內的 /app 目錄。
    • 作用
      • 讓本機的程式碼能夠即時同步到容器內,適用於開發環境。
      • 避免每次修改程式碼後,都需要重新建置映像檔。
  • depends_on:
    • 這裡定義了 web 服務依賴 MongoDBdepends_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 下載。
  • 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 內部數據可持久化儲存。

2.4 定義 Volume

volumes 區塊中,我們定義了 mongodb_data,確保 MongoDB 資料庫的數據能夠持久化:

volumes:
  mongodb_data:
  • 這表示 Docker Compose 會 自動建立一個 Volume(mongodb_data,並將 MongoDB 的數據儲存在該 Volume 內,即使容器刪除,數據也不會丟失。
  • 避免 MongoDB 服務 因容器刪除或重啟而遺失數據,確保應用的穩定運行。

同樣是 volumes,為什麼 MongoDB 和 Web 應用的效果不同?

Docker volumes 主要有兩種掛載方式:

  1. 命名 Volume(Named Volume):Docker 會管理數據存放位置,適合用於 持久化存儲
  2. 綁定掛載(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 應用上有不同的效果,關鍵在於:

  1. MongoDB 是一個資料庫,它會在 /data/db 目錄內儲存數據,所以我們需要 Volume 來持久化數據,避免資料丟失。
  2. 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

如果您的系統尚未安裝 DockerDocker Compose,請先安裝:

  • Windows / macOS:可以從 Docker 官網 下載並安裝 Docker Desktop
  • Linux:可以使用 aptyum 安裝:
sudo apt update && sudo apt install -y docker docker-compose

啟動應用

docker-compose.yml 檔案準備好後,只需要在相同目錄下執行以下指令:

docker-compose up -d

這個指令會:

  1. 根據 docker-compose.yml 啟動 webscrapermongodb 服務。
  2. 自動下載 mongo:latest 映像檔(如果本機沒有)。
  3. 以背景模式執行(-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 檔案解析了 webscrapermongodb 服務的配置。

透過 Docker Compose,可以輕鬆管理多個容器,讓開發環境更加一致,並提升應用的可維護性。

如果您是初學者,建議嘗試修改 docker-compose.yml,加入其他服務,並使用 docker-compose up 測試運行效果,這將有助於加深對 Docker Compose 的理解! 🚀

Similar Posts