之前用Docker部署一個Spring Boot+MySQL的應用時,每次啓動都要手動創建網絡、啓動數據庫容器、再啓動應用容器,還得記一堆命令參數。換成Docker Compose後,一個docker-compose up命令就能搞定所有容器的啓動,網絡配置也自動完成,省去了不少麻煩。

Docker Compose是多容器應用編排的利器,尤其適合開發和測試環境。它通過一個YAML文件定義所有服務,實現容器的統一啓停、網絡配置和依賴管理。本文結合實際場景,講解Compose的進階用法,包括網絡隔離、依賴控制、環境變量管理和容器擴展,幫你搞定複雜應用的部署。

一、多容器編排基礎:一個完整的Web應用示例

先看一個典型的多容器應用場景:Spring Boot後端 + MySQL數據庫 + Nginx前端。用Compose編排的docker-compose.yml文件如下:

version: '3.8'  # Compose文件版本

services:
  # MySQL數據庫服務
  mysql:
    image: mysql:8.0
    container_name: app-mysql
    environment:
      MYSQL_ROOT_PASSWORD: root123
      MYSQL_DATABASE: appdb
      MYSQL_USER: appuser
      MYSQL_PASSWORD: apppass
    volumes:
      - mysql-data:/var/lib/mysql  # 數據持久化
    ports:
      - "3306:3306"
    restart: unless-stopped  # 容器退出時自動重啓(除非手動停止)

  # Spring Boot後端服務
  backend:
    build: ./backend  # 從當前目錄的backend文件夾構建鏡像
    container_name: app-backend
    depends_on:
      - mysql  # 依賴mysql服務,確保mysql先啓動
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/appdb
      SPRING_DATASOURCE_USERNAME: appuser
      SPRING_DATASOURCE_PASSWORD: apppass
    ports:
      - "8080:8080"
    restart: unless-stopped

  # Nginx前端服務
  frontend:
    image: nginx:alpine
    container_name: app-frontend
    volumes:
      - ./frontend:/usr/share/nginx/html  # 掛載前端靜態文件
      - ./nginx.conf:/etc/nginx/conf.d/default.conf  # 掛載Nginx配置
    ports:
      - "80:80"
    depends_on:
      - backend  # 依賴後端服務
    restart: unless-stopped

volumes:
  mysql-data:  # 聲明數據卷,用於持久化MySQL數據

這個配置實現了三個服務的協同工作:

  • mysql服務提供數據庫,數據保存在命名卷mysql-data中,避免容器刪除後數據丟失;
  • backend服務依賴mysql,確保數據庫就緒後再啓動;
  • frontend服務通過Nginx提供靜態頁面,反向代理後端接口。

啓動命令:

docker-compose up -d  # -d表示後台運行

停止並刪除容器:

docker-compose down  # 僅停止容器
docker-compose down -v  # 停止容器並刪除數據卷(謹慎使用,會丟失數據)

二、網絡配置:容器間通信與隔離

默認情況下,Compose會為應用創建一個默認網絡,所有服務都在這個網絡中,可通過服務名互相訪問(如backend服務能通過mysql:3306訪問數據庫)。但實際開發中,可能需要更精細的網絡控制。

1. 自定義網絡實現隔離

比如將數據庫網絡和前端網絡隔離,只允許後端訪問數據庫:

version: '3.8'

services:
  mysql:
    image: mysql:8.0
    # 只加入backend-net網絡
    networks:
      - backend-net
    # ...其他配置省略

  backend:
    build: ./backend
    # 同時加入backend-net和frontend-net
    networks:
      - backend-net
      - frontend-net
    # ...其他配置省略

  frontend:
    image: nginx:alpine
    # 只加入frontend-net網絡
    networks:
      - frontend-net
    # ...其他配置省略

# 定義兩個自定義網絡
networks:
  backend-net:  # 後端與數據庫的網絡
    driver: bridge
  frontend-net:  # 前端與後端的網絡
    driver: bridge

這樣配置後:

  • mysql只能被backend訪問(同處backend-net);
  • frontend只能訪問backend(同處frontend-net),無法直接訪問mysql,增強了安全性。

2. 訪問宿主機服務

容器需要訪問宿主機上的服務(如本地開發的API)時,可通過特殊域名host.docker.internal(Windows和Mac)或宿主機IP:

services:
  backend:
    environment:
      # 訪問宿主機的9000端口服務
      EXTERNAL_API_URL: http://host.docker.internal:9000

Linux系統需手動指定宿主機IP(如192.168.1.100),或在啓動時添加--add-host=host.docker.internal:host-gateway參數。

三、環境變量與配置管理

硬編碼配置到docker-compose.yml中不利於多環境部署,可通過環境變量文件和動態注入解決。

1. 使用.env文件管理環境變量

創建.env文件存儲環境變量:

# .env文件
MYSQL_ROOT_PASSWORD=root123
MYSQL_DATABASE=appdb
SPRING_PROFILES_ACTIVE=dev

docker-compose.yml中引用:

services:
  mysql:
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}  # 引用.env中的變量
      MYSQL_DATABASE: ${MYSQL_DATABASE}

  backend:
    environment:
      SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE}

2. 不同環境使用不同配置文件

為開發、測試、生產環境創建不同的配置文件:

  • docker-compose.dev.yml(開發環境)
  • docker-compose.prod.yml(生產環境)

啓動時指定配置文件:

# 開發環境:默認配置 + 開發環境配置
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d

# 生產環境:默認配置 + 生產環境配置
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

生產環境配置示例(docker-compose.prod.yml):

version: '3.8'

services:
  backend:
    environment:
      SPRING_PROFILES_ACTIVE: prod  # 覆蓋默認的dev環境
    restart: always  # 總是自動重啓(生產環境更嚴格)

  mysql:
    ports:
      - "3307:3306"  # 生產環境使用不同端口避免衝突

四、依賴控制與健康檢查

depends_on只能保證容器啓動順序,不能確保服務就緒(如數據庫啓動但未完成初始化)。需結合健康檢查實現真正的依賴就緒。

1. 配置健康檢查

為MySQL添加健康檢查,確保數據庫就緒後再啓動後端:

services:
  mysql:
    image: mysql:8.0
    # 健康檢查:每10秒執行一次,超時5秒,3次成功視為健康
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 30s  # 啓動後30秒再開始健康檢查(給初始化留時間)

  backend:
    depends_on:
      mysql:
        condition: service_healthy  # 僅當mysql健康時才啓動

這樣backend會等待MySQL完全就緒(能ping通)後再啓動,避免連接失敗。

五、容器擴展與負載均衡

開發環境可能需要多個後端實例模擬負載均衡,Compose的--scale參數可快速擴展服務:

# 啓動3個backend實例
docker-compose up -d --scale backend=3

配合Nginx的負載均衡配置(nginx.conf):

http {
    upstream backend {
        # 引用backend服務的3個實例(Compose會自動解析為容器IP)
        server backend:8080;
    }

    server {
        listen 80;
        location /api/ {
            proxy_pass http://backend/;  # 反向代理到backend集羣
        }
    }
}

訪問http://localhost/api/時,Nginx會將請求分發到3個backend實例,實現簡單的負載均衡。

六、最佳實踐與避坑指南

  1. 不要依賴默認網絡:生產環境建議自定義網絡,通過網絡隔離增強安全性。
  2. 數據卷命名規範:使用項目名+服務名命名數據卷(如myapp_mysql-data),避免不同項目的數據卷衝突。
  3. 避免在Compose中存儲敏感信息:密碼、密鑰等敏感信息應通過環境變量文件或外部密鑰管理服務注入,且.env文件不要提交到代碼倉庫。
  4. 控制容器資源:為避免單個容器耗盡宿主機資源,可限制CPU和內存:
services:
  backend:
    deploy:
      resources:
        limits:
          cpus: '0.5'  # 最多使用0.5個CPU核心
          memory: 512M  # 最多使用512MB內存
  1. 定期清理無用資源:使用docker-compose down --rmi local清理本地構建的鏡像,避免磁盤佔用過大。

總結

Docker Compose通過簡潔的YAML配置實現了多容器應用的編排,解決了手動管理容器的繁瑣問題。進階用法中,自定義網絡實現服務隔離、健康檢查確保依賴就緒、環境變量文件適配多環境,這些技巧能讓你的部署配置更靈活、更可靠。

雖然Compose主要用於開發和測試環境,但其編排思想也適用於生產環境的容器管理(如Kubernetes)。掌握Compose的進階用法,不僅能提升日常開發效率,也能為理解更復雜的容器編排平台打下基礎。