Docker Compose完整指南:多容器協同、詳細範例與最佳實踐

Docker Compose完整指南:多容器協同、詳細範例與最佳實踐

在容器化技術已成為軟體開發與部署標準的一個時代,您可以使用 Docker Compose 作為一種“多容器協同管理”方案,已被廣泛應用於快速啟動開發環境、測試環境以及在生產環境中協同多服務的部署。

本文將帶領大家深入探討 Docker Compose,並提供詳細的說明與範例。文章不僅涵蓋了安裝與基本用法,也納入進階應用情境,如整合資料庫、前後端服務,以及常見的資料分析工具與監控平台(例:Metabase、Prometheus、Grafana、ELK 堆疊等)。

Docker Compose 緣起與基本概念

多容器協同的動機

一般而言,使用 Dockerfile 可以為單一應用或服務建立容器映像。但是,現代應用程式通常牽涉到多個服務。例如,一個典型的微服務架構可能需要:

  • 前端(如:Node.js、Ruby on Rails、Flask 或 React SPA)
  • 後端(如:Java、Go、Python…)
  • 資料庫(MySQL、Postgres、MongoDB…)
  • 缓存與排程工具(Redis、RabbitMQ、Kafka…)
  • 其他支援服務(Nginx、HAProxy、ElasticSearch…)

如果使用單純的 docker run,啟動每個服務的容器都需要一長串命令,且還得手動指定網路連線、port 映射以及環境變數。當服務越來越多時,就產生了巨大的維護成本。為了解決這個問題,Docker 官方團隊推出了 Docker Compose 來將多容器的架構“一次性”定義和運行。

Docker Compose 與 Dockerfile 的差異

  • Dockerfile:用於定義單個容器映像,描述了該映像如何被建置(如:從哪個 Base Image、安裝哪些套件、執行哪些指令)。
  • Docker Compose:用於定義應用程式及多容器之間的協同關係。它透過 docker-compose.yml(或 docker-compose.yaml)這種 YAML 配置檔,將多個容器整合在一個“專案(Project)”中管理,可以一次啟動、一次停止、多容器一起重新部署,也可以明確定義容器間的網路、卷(volumes)以及其他設定。

Docker Compose 架構與 V1、V2 版本沿革

Docker Compose 在早期名為 Fig,後來被 Docker 收購並重新命名。隨著時間演進,從 V1(基於 Python)到現今流行的 V2(Go 語言,與 Docker CLI 更緊密整合),官方也逐步淘汰舊版 Compose。

在 Docker Desktop 內常可看到指令 docker compose(中間有空格)即代表新版 V2,而舊版則多是 docker-compose(中間無空格,獨立二進位檔)。從 2023 年中開始,舊版 V1 逐漸被淘汰,建議使用者都升級至 Docker Compose V2,以便獲得最新功能與支援。

Docker Compose 安裝

在 Linux 上安裝

如果您使用的是 Linux 環境(如 Ubuntu、Debian、CentOS 或 Fedora),可以透過套件管理器或是直接從官方 GitHub 釋出的二進位檔來進行安裝。使用以下方式來完成安裝:

  1. 下載 Docker Compose V2 二進位檔
    sudo curl -L "https://github.com/docker/compose/releases/download/v2.17.2/docker-compose-$(uname -s)-$(uname -m)" \
      -o /usr/local/bin/docker-compose
    
  2. 賦予可執行權限
    sudo chmod +x /usr/local/bin/docker-compose
    
  3. 建立系統連結(可選)
    sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
    
  4. 確認安裝
    docker-compose version
    

    docker compose version
    

    視版本而定。若顯示正確版本資訊則代表安裝成功。

注意:部分新版 Linux 發行版或 Docker Engine 可能預設已支援 docker compose(V2),可以先嘗試 docker compose version 看看是否已就緒。若非必要也可不使用舊版 docker-compose 二進位。

在 macOS 與 Windows 上使用 Docker Desktop

對於 macOS 和 Windows 用戶來說,安裝 Docker Desktop 後通常會自動附帶最新版本的 Docker Compose(V2)。您可以直接在終端機(macOS)或 PowerShell / Command Prompt(Windows)輸入:

docker compose version

若有正確回應,即可使用最新版的 Compose 功能。

安裝驗證

完成後,可輸入下列的命令確保指令可以正常運行:

docker compose version

若成功顯示類似 Docker Compose version v2.17.x 等字樣,就代表安裝完成。

Docker Compose 核心概念與 YAML 配置檔

Docker Compose 的三個核心物件:Project、Service、Container

  1. Project:整個 Compose 專案(即一個 docker-compose.yml 檔案)可視為一個專案,包含了多個服務的定義。
  2. Service:服務層級的概念,用於描述將要運行的容器。“web”、“db”、“redis” 等皆是服務名稱的命名。
  3. Container:當執行 docker compose up 後,就會產生對應的容器。

docker-compose.yml 常見參數總覽

version: '3.8'
services:
  # 舉例:web 服務
  web:
    build: .
    image: my-web
    container_name: my-web-app
    ports:
      - "8080:80"
    environment:
      - NODE_ENV=development
    volumes:
      - ./src:/var/www/html
    networks:
      - my-network
    depends_on:
      - db
    command: ["npm", "start"]
    restart: always

  # 舉例:db 服務
  db:
    image: mysql:5.7
    container_name: my-db
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: testdb
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - my-network

networks:
  my-network:
    driver: bridge

volumes:
  db_data:
  • version:指定 compose 的版本(建議使用 3.8 或更高)。
  • services:主要定義容器服務。
    • image:指定要使用的映像名稱(可來自 Docker Hub 或自訂鏡像)。
    • build:如果要從 Dockerfile 建置映像,可使用此參數提供建置內容,如 build: .(在目前目錄尋找 Dockerfile)。
    • container_name:自訂容器名稱(可省略,由 Compose 自動產生)。
    • ports:定義主機與容器的埠對應,例如 8080:80 代表本機 8080 對應容器 80。
    • volumes:掛載卷或本地資料夾至容器內。
    • environment:設定環境變數,可使用字串或陣列方式。
    • networks:定義該服務所連接到的網路。
    • depends_on:指定服務依賴關係(如 web 需要先啟動 db)。
    • command:覆蓋容器預設的執行命令。
    • restart:重啟策略(如 always、on-failure、unless-stopped)。
  • networks:定義與容器要使用的網路模式,可以是 bridge、host 或自訂 driver。
  • volumes:定義資料卷,存放宿主機與容器中的持久性資料。

環境變數與 env_file

若要在外部定義環境變數,可使用 .env 這類設定檔案,或在 docker-compose.yml 中引用 env_file:

version: "3.8"
services:
  web:
    image: node:14
    env_file:
      - .env
    # 省略其他...

在 .env 檔中可寫:

NODE_ENV=production
API_KEY=123456

Compose 啟動時就會自動將此 .env 內容帶入容器。

使用 Build 架設自訂映像

若您要在本地自行建置映像,可在 docker-compose.yml 內使用 build:

version: '3'
services:
  myapp:
    build:
      context: ./myapp
      dockerfile: Dockerfile
    ports:
      - "3000:3000"

執行:

docker compose build
docker compose up -d

即可由該目錄下的 Dockerfile 建置出對應映像後並啟動容器。

Volumes 與檔案系統掛載

多數時候服務需要持久化存儲,或需要掛載程式碼目錄。Compose 支援多種卷掛載方式:

  1. Anonymous Volume:不命名,通常用於暫存。
  2. Named Volume:可在最底部 volumes 區域命名,如 db_data,利於持久化管理。
  3. Host Path:直接掛載主機本地路徑,如 ./src:/app/src,適合開發模式。

範例:

services:
  db:
    image: postgres
    volumes:
      - db-volume:/var/lib/postgresql/data
volumes:
  db-volume:

或以 Host Path:

services:
  web:
    image: php:8-apache
    volumes:
      - ./webdata:/var/www/html

Networks 與容器間的網路連線

Compose 會自動為同一個 docker-compose.yml 中的服務容器建立預設網路,並透過服務名稱(如 db, web)來互相 DNS 解析,同時對應端口。如果要自訂網路:

networks:
  my-network:
    driver: bridge

然後在服務區塊:

services:
  web:
    networks:
      - my-network
  db:
    networks:
      - my-network

如此 web 容器可用 db:3306(取決於服務內部對外開放的埠)來連接資料庫。

如何使用範例:Node.js + MongoDB

假設我們有一個專案需要使用 Node.js 做後端,並使用 MongoDB 做數據庫。我們希望只要執行一個命令就能同時啟動 Node.js 與 MongoDB。以下舉例說明。

撰寫 docker-compose.yml

假設我們在專案根目錄下建立一個 docker-compose.yml 檔案,內容如下:

version: "3.8"
services:
  app:
    image: node:18-alpine
    container_name: node_app
    working_dir: /app
    volumes:
      - ./:/app
    command: sh -c "npm install && npm run start"
    ports:
      - "3000:3000"
    depends_on:
      - mongo
    networks:
      - app_network

  mongo:
    image: mongo:6.0
    container_name: mongo_db
    restart: always
    ports:
      - "27017:27017"
    volumes:
      - mongodata:/data/db
    networks:
      - app_network

networks:
  app_network:
    driver: bridge

volumes:
  mongodata:

說明:

  • app 服務為一個 Node.js 容器,直接使用 node:18-alpine 作基底映像。
  • 使用 volumes 將本地整個專案掛載到容器 /app 資料夾。
  • command: sh -c “npm install && npm run start” 表示啟動容器前會自動安裝依賴套件,再執行 npm run start。
  • ports: “3000:3000″,將容器內的 3000 port 對外映射到本機的 3000 port。
  • depends_on: [mongo] 表示啟動 app 前,會先啟動 mongo。
  • mongo 服務使用官方 mongo:6.0 映像,並指定資料卷 mongodata,以保證資料庫持久化。
  • 建立一個自訂 app_network 的 bridge 型網路,讓 app 與 mongo 互通。

執行範例與測試

  1. 執行 docker compose build(若有 build 指令)
    如果使用既有映像就不用 build;本範例直接拉取 node 與 mongo,所以可省略 build。
  2. 執行 docker compose up
    docker compose up -d
    

    系統會同時拉取 node:18-alpine 與 mongo:6.0 映像,並建立兩個容器:

    • node_app
    • mongo_db
  3. 檢查運行狀態
    docker compose ps
    

    若顯示兩個服務皆為 Up 狀態,即表示成功。

  4. 測試應用
    如果您的 Node.js 應用監聽在 3000 port,可打開瀏覽器輸入 http://localhost:3000 驗證是否正常顯示。

查看資料庫與容器狀態

  • 若要查看容器日誌:
    docker compose logs -f mongo
    
  • 若要連線 Mongo 容器,可:
    docker exec -it mongo_db bash
    

    進入容器後,可使用 mongosh 連接本地執行查詢。

進階應用:多容器案例與整合示例

以下將列舉更多常見的多容器整合場景,包括 CMS、BI 工具、監控平台,以及大數據相關等。

WordPress + MariaDB

情境:在本地或伺服器上想快速啟動一個 WordPress + MariaDB 的環境,並能保留資料。

version: '3.8'
services:
  db:
    image: mariadb:10.6
    container_name: my_mariadb
    environment:
      MYSQL_ROOT_PASSWORD: "rootpass"
      MYSQL_DATABASE: "wordpress"
      MYSQL_USER: "wp_user"
      MYSQL_PASSWORD: "wp_pass"
    volumes:
      - db_data:/var/lib/mysql
    ports:
      - "3306:3306"
    networks:
      - wp-net

  wordpress:
    image: wordpress:latest
    container_name: my_wordpress
    depends_on:
      - db
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: "wp_user"
      WORDPRESS_DB_PASSWORD: "wp_pass"
      WORDPRESS_DB_NAME: "wordpress"
    ports:
      - "8080:80"
    volumes:
      - wp_html:/var/www/html
    networks:
      - wp-net

networks:
  wp-net:

volumes:
  db_data:
  wp_html:
  • 透過 depends_on 確保 MariaDB 容器先啟動。
  • WordPress 中 WORDPRESS_DB_HOST 需使用 db 服務名稱,以容器內 DNS 方式連線。
  • 所有資料均掛載到名為 db_data 與 wp_html 的 volume。

Metabase + MS SQL Server

情境:需要搭建簡單 BI(商業智慧)分析環境,Metabase 連到 SQL Server 做分析與可視化。

  1. SQL Server 容器:
    version: '3.8'
    services:
      sqlserver:
        image: mcr.microsoft.com/mssql/server:2022-latest
        container_name: sqlserver
        environment:
          ACCEPT_EULA: "Y"
          MSSQL_SA_PASSWORD: "yourStrongPassword!"
        ports:
          - "1433:1433"
        volumes:
          - ./mssql_data:/var/opt/mssql
        networks:
          - analysis-net
    networks:
      analysis-net:
    
  2. Metabase 容器(可加入在同一份 compose 檔):
    metabase:
      image: metabase/metabase:latest
      container_name: metabase
      ports:
        - "3000:3000"
      networks:
        - analysis-net
    
    • 將 Metabase 與 sqlserver 都連到 analysis-net,可直接使用 sqlserver:1433 連線資料庫。
    • 啟動後打開瀏覽器到 http://localhost:3000,並透過設定檔案或 UI 介面設定資料庫來源。

Prometheus + Grafana

情境:監控 Docker 容器指標,或其他服務的效能指標。

  • Prometheus
    • 負責資料收集(scrape metrics),常使用 prometheus.yml 作為配置。
  • Grafana
    • 數據可視化 UI。

簡易 docker-compose.yml 範例(yaml配置實例):

version: '3.8'
services:
  prometheus:
    image: prom/prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    networks:
      - monitor-net

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    networks:
      - monitor-net
    depends_on:
      - prometheus

networks:
  monitor-net:

將 Prometheus 配置檔(prometheus.yml)放在同目錄下,指明要抓取哪些容器或服務指標。

ELK 堆疊 (Elasticsearch、Logstash、Kibana)

情境:建立日誌分析平台。

version: '3.8'
services:
  elasticsearch:
    image: elasticsearch:8.5.0
    container_name: es
    environment:
      - discovery.type=single-node
    ports:
      - "9200:9200"
    networks:
      - elk-net

  logstash:
    image: logstash:8.5.0
    container_name: ls
    networks:
      - elk-net
    depends_on:
      - elasticsearch
    ports:
      - "9600:9600"

  kibana:
    image: kibana:8.5.0
    container_name: kb
    depends_on:
      - elasticsearch
    ports:
      - "5601:5601"
    networks:
      - elk-net

networks:
  elk-net:
  • elasticsearch、logstash、kibana 三者彼此連通即可形成 ELK 堆疊。
  • 連線方式:Kibana 預設 http://localhost:5601,Elasticsearch 預設 http://localhost:9200。

常用 Docker Compose 命令與操作表格

下表彙整了使用 Docker Compose(V2 語法)的常見操作命令與對應用途(你也可參考官方的文件):

命令 用途 範例
docker compose up [-d] 啟動所有在 docker-compose.yml 裡定義的服務;-d 表示後台執行 docker compose up -d
docker compose down 停止並刪除所有容器、網路(默認創建)、但不刪除 volume 與 image docker compose down
docker compose build 根據 docker-compose.yml 中的 build 配置建置映像 docker compose build
docker compose start 啟動已建立但目前停止的容器 docker compose start
docker compose stop 停止已運行的容器,但不刪除容器 docker compose stop
docker compose restart 重啟容器 docker compose restart web
docker compose ps 列出 Compose 專案相關的容器、狀態、Port 映射 docker compose ps
docker compose logs [-f] [service] 查看容器日誌;-f 持續關注;可指定特定服務 docker compose logs -f web
docker compose pull 從遠端倉庫拉取所有服務定義的映像 docker compose pull
docker compose rm 刪除已停止的容器 docker compose rm
docker compose exec <service> bash 進入某個容器進行操作(類似 docker exec -it) docker compose exec db bash
docker compose port <service> <port> 查詢服務容器內部埠對應宿主機的埠映射 docker compose port web 3000
docker compose version 顯示 Compose 版本資訊 docker compose version

常見問題 (FAQ)

為何要使用 Docker Compose 而非手動 docker run?

當只有一個容器時,手動 docker run 當然夠用。然而實際應用幾乎都需要多容器(前端、後端、DB…),若每次都要手動串接大量參數,維護成本高、錯誤率也高。Docker Compose 提供了易讀的 YAML 檔集中管理,可一次執行 docker compose up -d 就啟動所有容器,非常方便。

Docker Compose V1 與 V2 差別是什麼?

  • V1 以 docker-compose (中間無空格)單一二進位檔執行,基於 Python。
  • V2 則是透過 docker compose 子指令整合到 Docker CLI 中,更符合新一代 Docker 環境。官方已於 2023 年起逐漸淘汰 V1,建議使用 V2。

可以在生產環境使用 Docker Compose 嗎?

Compose 主要用於「單台伺服器的多容器協同」。若在生產環境只有單台機器,Compose 當然可以快速部署。但若是要建立大型叢集或做更進階的自動擴展、滾動更新,建議使用 Kubernetes 或 Docker Swarm 等分散式容器管理平台。Compose 的 deploy 區段在 swarm mode 下也能派上用場,但普遍還是 K8s 在生產環境更常見。

depends_on 能否保證服務已就緒後才啟動?

depends_on 只會保證容器按順序啟動,但不保證容器中服務真正啟動完成。若需要確保 DB 真的能連接,建議搭配健康檢查(healthcheck)或像 wait-for-it.sh 或 wait-service 之類的機制。

資料卷 (Volumes) 該如何備份與清理?

  • Docker Compose 使用到的 Volume 在默認情況下會保留,即使容器已刪除。清理時可用 docker volume rm <volume>。
  • 備份可透過 docker run –rm -v my_volume:/data -v $(pwd):/backup busybox tar cvf /backup/backup.tar /data 等方式。

如何在同一台主機上同時執行多個 docker-compose.yml?

只要確保不同 Compose 專案的容器名稱、網路名稱、port 映射等不衝突即可。例如可在不同目錄下建立 docker-compose.yml 檔並執行。如果擔心名稱衝突,可使用 -p 或 –project-name 參數自訂專案名稱。

如何自動重啟容器?

在 docker-compose.yml 裡的每個服務段落可加上 restart: always 或 restart: on-failure 等策略。如果遇到容器崩潰,可自動重啟。

是否能在 Docker Compose 中整合 secrets 來管理敏感資訊?

在 Compose v3.1+ 開始提供 secrets 機制,類似 Docker Swarm。可透過 secrets: 配置機制將機密資料加載到容器內。也可用 environment variable 的方式,但不建議直接將密碼硬編碼在檔案中,可搭配 .env 檔或 CI/CD 管理。

當前使用 Docker Compose 的 YAML 檔已經很複雜時如何維護?

  • 可以使用多個 YAML 檔,透過 docker compose -f base.yml -f override.yml up -d 來做環境差異的覆蓋。例如分為 docker-compose.yml(預設) 與 docker-compose.override.yml(開發或測試設定)。
  • 也可以使用 anchor & alias 的 YAML 語法來減少重複定義。

總結

Docker Compose 是一個能大幅簡化多容器部署流程的工具,不論在開發、測試或小型生產環境,都能極大提升維運效率與環境一致性。

總體而言,Docker Compose 不僅能在開發測試階段提高效率與可重現性,也能透過 docker compose 指令組合在小型生產部署中提供多容器協同運行的便利。希望本文從入門到進階的範例,能協助您更熟練掌握 Compose 的各種技巧與應用情境。

資料來源

返回頂端