一鍵部署複雜應用:Docker Compose讓開發流程化繁為簡

一鍵部署複雜應用:Docker Compose讓開發流程化繁為簡

在現代軟體開發的浪潮中,容器化技術已從一個新穎的概念演變為不可或缺的標準實踐。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 帶來的主要優勢包括:

  1. 簡化複雜的容器管理:告別冗長且容易出錯的 docker run 指令鏈。只需一個 docker-compose up 命令,即可啟動所有服務。
  2. 實現環境一致性:徹底解決「在我的電腦上可以跑」的經典難題。docker-compose.yml 文件確保了從開發、測試環境到生產部署環境的配置完全一致,極大地降低了因環境差異導致的問題。
  3. 提升開發與協作效率:開發團隊成員只需獲取程式碼和 docker-compose.yml 文件,就能快速在本機建立起完整的開發環境。這對於微服務架構的應用程式尤其重要,能夠讓開發者專注於自身負責的服務,而無需擔心複雜的環境依賴。
  4. 宣告式設定,易於版本控制: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 兩個文件。您可以:

  1. docker-compose.yml (基礎配置): 存放所有環境通用的配置,如服務定義、建置指令等。
  2. docker-compose.override.yml (開發環境覆蓋): 存放僅用於開發環境的配置。例如,掛載本地程式碼、映射偵錯端口、設定開發用的環境變數。這個文件通常會被納入版本控制,方便團隊成員共享。
  3. 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 融入您的日常工作流程,將為您和您的團隊帶來前所未有的便利與效率。

資料來源

返回頂端