在現代軟體開發與維運實務中,將命令行工具容器化是提升環境一致性與管理效率的關鍵策略。本文從 Docker 容器執行 Terraform 的流程切入,說明如何藉由容器封裝基礎設施即代碼(IaC)工具,達成環境標準化與版本彈性。然而,當應用架構走向多服務協作時,單一容器的管理模式便顯不足。因此,文章將焦點轉向 Docker Compose,深入探討其作為多容器應用協調工具的核心概念,解釋如何透過宣告式 YAML 配置文件,定義服務、網路與儲存卷之間的依賴關係。透過具體部署案例,呈現 Docker Compose 在簡化服務通訊與生命週期管理方面的實踐價值。
Docker 運行 Terraform 與 Docker Compose 基礎
本節將延續 Docker 運行命令行工具的討論,完成 Terraform 的執行流程,並介紹 Docker Compose 的基本概念與用途,為後續的多容器應用部署奠定基礎。
完成 Terraform 執行流程
在 Docker 容器內運行 Terraform 的過程中,繼 init 和 plan 命令之後,我們需要執行 apply 命令來實際創建或修改基礎設施。
- 執行
terraform apply:這個命令使用之前docker run -i -t -v ${PWD}:/usr/tf -w /usr/tf \ --env ARM_CLIENT_ID="<azure_client_id>" \ --env ARM_CLIENT_SECRET="<azure_client_secret>" \ --env ARM_SUBSCRIPTION_ID="<azure_subscription_id>" \ --env ARM_TENANT_ID="<azure_tenant_id>" \ hashicorp/terraform:latest apply plan.tfplanplan命令生成的plan.tfplan文件來執行變更。這確保了 Terraform 將應用先前預覽過的確切變更。
使用 Docker 運行命令行工具的優勢
將命令行工具(如 Terraform)運行在 Docker 容器內,提供了顯著的優勢:
- 簡化本地環境配置: 無需在本地機器上安裝和配置這些工具及其複雜的依賴項。Docker 映像已經包含了所有必需的組件,實現了環境的隔離和標準化。
- 版本管理靈活性: 可以輕鬆地在本地運行同一工具的不同版本,而不會產生衝突。只需拉取並運行對應版本的 Docker 映像即可,這對於測試新版本或維護與特定版本兼容的項目至關重要。
Docker Compose 介紹
在之前的章節中,我們學習了如何單獨構建和運行 Docker 映像。然而,現代應用程式通常不是獨立運行的,它們需要與其他服務(如數據庫、API 服務)協同工作。這就引入了多容器部署的需求。
Docker Compose 是一個用於定義和運行多容器 Docker 應用程式的工具。它允許您使用一個 YAML 文件來配置應用程式的所有服務、網絡和卷。通過一個簡單的命令,您可以啟動、停止和管理應用程式的所有組件。
Docker Compose 的核心概念:
- 服務 (Services): 在 Docker Compose 文件中,每個服務代表一個容器。您可以定義多個服務,例如一個 Web 應用服務、一個數據庫服務等。
- 映像 (Images): 每個服務都基於一個 Docker 映像構建。
- 卷 (Volumes): 用於持久化容器數據,確保數據不會隨著容器的銷毀而丟失。
- 網絡 (Networks): 允許容器之間相互通信,並與外部環境進行交互。
使用 Docker Compose,您可以將一個複雜的應用程式(例如,一個 Web 應用程式與一個 MySQL 數據庫)定義為一個單一的部署單元,極大地簡化了多容器應用的管理和部署流程。
Docker Compose 安裝
- Windows 和 macOS: Docker Compose 通常已預裝在 Docker Desktop 中。
- Linux: 在 Linux 上,您可能需要按照官方文檔進行單獨安裝。
基本 Docker Compose 配置示例
我們將以一個常見的場景為例:運行一個 Nginx Web 服務器,並將其連接到一個 MySQL 數據庫。
-
創建
docker-compose.yml文件: 在項目目錄中創建一個名為docker-compose.yml的文件,並使用 YAML 語法定義服務。version: '3.8' # 指定 Docker Compose 文件格式版本 services: # Nginx Web 服務 web: image: nginx:latest # 使用官方 Nginx 映像 ports: - "80:80" # 將主機的 80 端口映射到容器的 80 端口 volumes: - ./html:/usr/share/nginx/html # 掛載本地 html 目錄到 Nginx 的 Web 根目錄 depends_on: - db # 確保數據庫服務先啟動 # MySQL 數據庫服務 db: image: mysql:5.7 # 使用官方 MySQL 5.7 映像 environment: MYSQL_ROOT_PASSWORD: your_strong_password # 設定 MySQL root 用戶密碼 MYSQL_DATABASE: myappdb # 設定數據庫名稱 volumes: - db_data:/var/lib/mysql # 使用命名卷持久化數據庫數據 # 定義命名卷 volumes: db_data:services: 定義了應用程式的各個組件(服務)。web服務: 使用 Nginx 映像,暴露端口 80,並將本地的html文件夾掛載到 Nginx 的 Web 根目錄。depends_on指示 Nginx 服務依賴於db服務。db服務: 使用 MySQL 5.7 映像,並通過environment變量設置了數據庫名稱和 root 密碼。volumes指示使用一個名為db_data的命名卷來持久化數據。volumes: 在頂層定義了命名卷db_data。
執行 Docker Compose 配置
在保存 docker-compose.yml 文件後,您可以在終端中執行以下命令來啟動應用程式:
docker-compose up -d
up: 啟動並運行服務。-d: 在後台模式(detached mode)下運行容器。
執行此命令後,Docker Compose 將會自動拉取所需的映像(Nginx 和 MySQL),創建網絡,創建卷,然後啟動所有定義的服務。您可以在瀏覽器中訪問 http://localhost 來查看 Nginx 服務的運行情況(如果您的本地 html 目錄中有相應的 index.html 文件)。
Docker Compose 實戰:Nginx 與 MySQL 部署
本節將深入探討如何利用 Docker Compose 編寫配置文件,並實際運行一個包含 Nginx Web 服務器和 MySQL 數據庫的多容器應用程式。
Docker Compose 配置文件編寫
在開始之前,首先確認 Docker Compose 已正確安裝。可以通過運行 docker-compose version 命令來驗證。
接下來,我們將創建一個名為 docker-compose.yml 的文件,其中定義了我們應用程式的服務。
-
Nginx 服務配置:
version: '3' # 指定 Docker Compose 文件格式版本 services: nginx: image: nginx:latest # 使用最新的官方 Nginx 映像 container_name: nginx-container # 為容器指定一個易於識別的名稱 ports: - "8080:80" # 將主機的 8080 端口映射到容器的 80 端口services: 這是 Docker Compose 文件的主鍵,用於定義應用程式中的各個服務。nginx: 這是一個服務名稱,代表我們的 Nginx 服務。image: nginx:latest: 指定使用最新的官方 Nginx Docker 映像。container_name: nginx-container: 為此 Nginx 容器指定一個固定的名稱,方便管理和識別。ports: - "8080:80": 這是端口映射。它將主機(您的電腦)的 8080 端口映射到 Nginx 容器內部的 80 端口。這意味著您可以通過訪問主機的localhost:8080來訪問 Nginx 服務。
-
MySQL 服務配置: 在同一個
docker-compose.yml文件中,我們添加 MySQL 服務的配置:mysql: image: mysql:5.7 # 使用 MySQL 5.7 版本映像 container_name: mysql-container # 為 MySQL 容器指定名稱 environment: MYSQL_ROOT_PASSWORD: secret # 設定 MySQL root 用戶的密碼 MYSQL_DATABASE: mydb # 設定要創建的數據庫名稱 MYSQL_USER: myuser # 設定一個新的數據庫用戶名 MYSQL_PASSWORD: password # 設定新用戶的密碼mysql: 這是 MySQL 服務的名稱。image: mysql:5.7: 指定使用 MySQL 5.7 版本映像。選擇特定版本有助於確保環境的一致性。container_name: mysql-container: 為 MySQL 容器指定一個名稱。environment: 這是一個關鍵部分,用於設置 MySQL 容器啟動時所需的環境變量。MYSQL_ROOT_PASSWORD: 設定了root用戶的密碼。MYSQL_DATABASE: 在啟動時自動創建一個名為mydb的數據庫。MYSQL_USER和MYSQL_PASSWORD: 設定了一個新的數據庫用戶myuser及其密碼,用於訪問mydb數據庫。
執行 Docker Compose
編寫好 docker-compose.yml 文件後,我們就可以使用 Docker Compose 命令來啟動這些容器了。
-
啟動容器: 在終端中,導航到包含
docker-compose.yml文件的目錄,然後執行以下命令:docker-compose up -ddocker-compose up: 這個命令會讀取當前目錄下的docker-compose.yml文件,並根據其中的定義創建和啟動所有服務的容器。-d(detached mode): 這個選項讓容器在後台運行,不會阻塞終端。
執行此命令後,Docker Compose 會自動完成以下操作:
- 拉取
nginx:latest和mysql:5.7映像(如果本地不存在)。 - 創建一個 Docker 網絡,讓
nginx和mysql服務能夠相互通信。 - 創建並啟動
nginx-container和mysql-container這兩個容器。 - 為 MySQL 容器配置數據庫、用戶和密碼。
視覺化 Docker Compose 服務架構
以下圖示展示了通過 docker-compose.yml 文件定義的 Nginx 和 MySQL 服務之間的關係。
@startuml
!define DISABLE_LINK
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100
title Docker Compose Multi-Container Setup
component "Docker Host Machine" {
artifact "docker-compose.yml" as COMPOSE_FILE
artifact "Nginx Container\n(nginx-container)" as NGINX_CONT
artifact "MySQL Container\n(mysql-container)" as MYSQL_CONT
artifact "Docker Network\n(e.g., projectname_default)" as DOCKER_NET
artifact "Volume\n(e.g., db_data)" as DB_VOLUME
}
component "External Services" {
artifact "Nginx Image" as NGINX_IMG
artifact "MySQL Image" as MYSQL_IMG
}
COMPOSE_FILE --> NGINX_CONT : Defines Nginx Service
COMPOSE_FILE --> MYSQL_CONT : Defines MySQL Service
COMPOSE_FILE --> DOCKER_NET : Defines Network
COMPOSE_FILE --> DB_VOLUME : Defines Volume
NGINX_CONT --> NGINX_IMG : Uses Image
MYSQL_CONT --> MYSQL_IMG : Uses Image
MYSQL_CONT --> DB_VOLUME : Persists Data
NGINX_CONT -- DOCKER_NET : Connects to Network
MYSQL_CONT -- DOCKER_NET : Connects to Network
NGINX_CONT --> MYSQL_CONT : Communicates via Network\n(using service name 'mysql')
NGINX_CONT : Exposes Port 8080 (Host)\n to Port 80 (Container)
stop
@enduml
看圖說話:
此圖示描繪了 Docker Compose 如何協調多個容器構成一個應用程式。核心是「Docker Host Machine」上的 docker-compose.yml 文件,它定義了「Nginx Container (nginx-container)」和「MySQL Container (mysql-container)」兩個服務。
每個容器都基於相應的 Docker 映像(「Nginx Image」和「MySQL Image」)構建。Docker Compose 會自動創建一個「Docker Network」,讓這兩個容器能夠在內部進行通信。Nginx 容器通過主機的 8080 端口暴露服務,而 MySQL 容器則使用一個「Volume (db_data)」來持久化其數據。
關鍵在於,Nginx 容器可以通過服務名稱 mysql(在 docker-compose.yml 文件中定義)直接訪問 MySQL 容器,而無需知道其 IP 地址。這極大地簡化了服務之間的通信配置。
縱觀現代應用程式開發與維運的複雜性演進,從單一工具的容器化到多容器應用的系統性編排,標示了一次關鍵的思維躍遷。將 Terraform 這類命令行工具置於 Docker 中運行,是解決環境依賴與版本衝突的卓越起點,實現了開發環境的標準化與隔離,屬於一種高效的資源最佳化實踐。
然而,Docker Compose 的引入,則將我們的視角從單一「元件效能」提升至「系統架構」的層次。其核心價值不僅在於簡化多容器啟動的指令,更在於提供了一種宣告式的語言來定義服務間的依賴關係、網絡通訊與數據持久化策略。此舉將原本隱晦、需要透過指令式腳本維護的系統拓撲,轉化為清晰、可版本控制的組態文件。真正的挑戰與瓶頸,並非學習 YAML 語法,而是促使開發與維運團隊從關注獨立服務,轉向建立系統性思考的心智模式。
展望未來,這種以 Docker Compose 為代表的宣告式編排方法,將進一步模糊本地開發、持續整合與生產環境的界線,形成一個高度一致的開發維運生態系。服務間的互動關係在開發初期即被明確定義,大幅降低了後期整合的風險與溝通成本。
對於追求高效能交付的技術領導者而言,引導團隊掌握從單一工具容器化到多容器應用編排的思維躍遷,不僅是技術能力的升級,更是提升團隊整體協作效率與交付品質的關鍵槓桿。