功能介紹

什麼是Docker Compose?

Docker Compose是Docker官方提供的工具,用於定義和運行多容器Docker應用程序。通過使用YAML文件來配置應用程序的服務,可以使用單個命令創建和啓動所有服務。

Docker Compose的作用

  1. 簡化多容器應用管理:通過一個配置文件管理多個容器
  2. 環境一致性:確保開發、測試和生產環境的一致性
  3. 快速部署:一鍵啓動整個應用棧
  4. 服務編排:定義服務之間的依賴關係和啓動順序

Docker Compose的核心概念

  1. 服務(Service):應用的一個組件,如數據庫、Web服務器等
  2. 項目(Project):由多個服務組成的完整應用
  3. Compose文件:定義服務配置的YAML文件

使用教程

安裝Docker Compose

# Docker Desktop已包含Compose,Linux需要單獨安裝
# 下載Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 添加執行權限
sudo chmod +x /usr/local/bin/docker-compose

# 驗證安裝
docker-compose --version

Compose文件基本結構

# docker-compose.yml
version: '3.8'

services:
  # 服務定義
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html

  database:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
    volumes:
      - db-data:/var/lib/mysql

volumes:
  # 卷定義
  db-data:

常用Compose命令

# 啓動所有服務
docker-compose up

# 後台啓動所有服務
docker-compose up -d

# 查看服務狀態
docker-compose ps

# 查看服務日誌
docker-compose logs

# 實時查看服務日誌
docker-compose logs -f

# 停止服務
docker-compose stop

# 啓動已停止的服務
docker-compose start

# 重啓服務
docker-compose restart

# 停止並刪除容器、網絡
docker-compose down

# 刪除卷和鏡像
docker-compose down -v --rmi all

# 執行單個服務命令
docker-compose exec web ls /

Compose文件詳細配置

version: '3.8'

services:
  web:
    # 鏡像
    image: nginx:alpine
    
    # 構建配置
    build:
      context: .
      dockerfile: Dockerfile
      args:
        - BUILD_ARG=value
    
    # 端口映射
    ports:
      - "8080:80"
      - "8443:443"
    
    # 環境變量
    environment:
      - ENV_VAR=value
      - DATABASE_URL=mysql://user:pass@db:3306/mydb
    
    # 卷掛載
    volumes:
      - ./html:/usr/share/nginx/html
      - web-data:/data
    
    # 依賴服務
    depends_on:
      - database
    
    # 網絡配置
    networks:
      - frontend
    
    # 健康檢查
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 30s
      timeout: 10s
      retries: 3
    
    # 資源限制
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M

  database:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: myapp
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - backend

volumes:
  web-data:
  db-data:

networks:
  frontend:
  backend:

案例講解

案例一:LAMP應用棧

# 創建項目目錄
mkdir lamp-stack && cd lamp-stack

# 創建docker-compose.yml
cat > docker-compose.yml << EOF
version: '3.8'

services:
  # Apache + PHP服務
  web:
    image: php:8.0-apache
    ports:
      - "8080:80"
    volumes:
      - ./www:/var/www/html
    depends_on:
      - database
    networks:
      - frontend
      - backend

  # MySQL數據庫服務
  database:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: myapp
      MYSQL_USER: myuser
      MYSQL_PASSWORD: mypass
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - backend
    ports:
      - "3306:3306"

  # PHPMyAdmin服務
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    ports:
      - "8081:80"
    environment:
      PMA_HOST: database
      MYSQL_ROOT_PASSWORD: rootpass
    depends_on:
      - database
    networks:
      - backend

volumes:
  db-data:

networks:
  frontend:
  backend:
EOF

# 創建Web目錄和簡單PHP文件
mkdir www
cat > www/index.php << EOF
<?php
\$servername = "database";
\$username = "myuser";
\$password = "mypass";
\$dbname = "myapp";

try {
    \$pdo = new PDO("mysql:host=\$servername;dbname=\$dbname", \$username, \$password);
    echo "Connected successfully<br>";
    echo "Hello LAMP Stack!";
} catch(PDOException \$e) {
    echo "Connection failed: " . \$e->getMessage();
}
?>
EOF

# 啓動應用
docker-compose up -d

# 查看服務狀態
docker-compose ps

# 測試應用
curl http://localhost:8080

# 訪問PHPMyAdmin
# 在瀏覽器中打開 http://localhost:8081

案例二:微服務應用

# 創建項目目錄
mkdir microservices && cd microservices

# 創建API服務
mkdir api-service
cat > api-service/app.py << EOF
from flask import Flask, jsonify
import os

app = Flask(__name__)

@app.route('/')
def home():
    return jsonify({
        'service': 'API Service',
        'message': 'Hello from API service!'
    })

@app.route('/health')
def health():
    return jsonify({'status': 'healthy'})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
EOF

cat > api-service/requirements.txt << EOF
Flask==2.0.1
EOF

cat > api-service/Dockerfile << EOF
FROM python:3.9-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

EXPOSE 5000

CMD ["python", "app.py"]
EOF

# 創建前端服務
mkdir frontend-service
cat > frontend-service/index.html << EOF
<!DOCTYPE html>
<html>
<head>
    <title>Microservices Demo</title>
</head>
<body>
    Microservices Demo
    <div id="api-response"></div>
    <script>
        fetch('http://api:5000/')
            .then(response => response.json())
            .then(data => {
                document.getElementById('api-response').innerHTML = '<p>' + JSON.stringify(data) + '</p>';
            });
    </script>
</body>
</html>
EOF

cat > frontend-service/Dockerfile << EOF
FROM nginx:alpine

COPY index.html /usr/share/nginx/html/

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]
EOF

# 創建docker-compose.yml
cat > docker-compose.yml << EOF
version: '3.8'

services:
  # 負載均衡器
  nginx:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - frontend
      - api
    networks:
      - frontend-net

  # 前端服務
  frontend:
    build: ./frontend-service
    networks:
      - frontend-net

  # API服務
  api:
    build: ./api-service
    networks:
      - frontend-net
      - backend-net

  # Redis緩存
  redis:
    image: redis:alpine
    networks:
      - backend-net

  # 數據庫
  database:
    image: postgres:13
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mypass
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - backend-net

volumes:
  db-data:

networks:
  frontend-net:
  backend-net:
EOF

# 創建Nginx配置
cat > nginx.conf << EOF
events {
    worker_connections 1024;
}

http {
    upstream frontend {
        server frontend:80;
    }

    upstream api {
        server api:5000;
    }

    server {
        listen 80;

        location / {
            proxy_pass http://frontend;
        }

        location /api/ {
            proxy_pass http://api/;
        }
    }
}
EOF

# 啓動微服務應用
docker-compose up -d

# 查看服務狀態
docker-compose ps

# 測試應用
curl http://localhost:8080
curl http://localhost:8080/api/

常見問題解答

Q1: 如何處理服務啓動順序問題?

A: Docker Compose提供了depends_on選項,但它只等待容器啓動,不等待應用就緒。可以使用以下方法解決:

version: '3.8'

services:
  web:
    image: my-web-app
    depends_on:
      database:
        condition: service_healthy
    # 或者使用自定義健康檢查
    # depends_on:
    #   - database

  database:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      timeout: 20s
      retries: 10

或者在應用中實現重試機制:

# 在啓動腳本中添加重試邏輯
#!/bin/bash
until mysql -h database -u root -prootpass -e "SELECT 1"; do
  echo "Waiting for database..."
  sleep 5
done

# 啓動應用
exec your-app-command

Q2: 如何在不同環境中使用不同的配置?

A: 可以使用多個Compose文件或環境變量:

# 方法1:使用多個Compose文件
# docker-compose.yml (基礎配置)
# docker-compose.override.yml (開發環境)
# docker-compose.prod.yml (生產環境)

# 開發環境
docker-compose up -d

# 生產環境
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

# 方法2:使用環境變量
# docker-compose.yml
version: '3.8'
services:
  web:
    image: my-app:${TAG:-latest}
    environment:
      - ENV=${ENV:-development}

# 設置環境變量
export TAG=v1.0
export ENV=production
docker-compose up -d

Q3: 如何調試Compose應用?

A: 可以通過以下方式調試Compose應用:

# 1. 查看服務日誌
docker-compose logs service-name

# 2. 實時查看日誌
docker-compose logs -f service-name

# 3. 進入容器調試
docker-compose exec service-name /bin/bash

# 4. 查看網絡配置
docker-compose exec service-name ip addr show

# 5. 使用docker-compose config驗證配置
docker-compose config

# 6. 構建時不使用緩存
docker-compose build --no-cache

# 7. 強制重新創建容器
docker-compose up -d --force-recreate

最佳實踐

1. Compose文件組織最佳實踐

  • 使用版本控制管理Compose文件
  • 為不同環境創建不同的Compose文件
  • 使用.env文件管理環境變量
  • 合理命名服務和資源
  • 添加註釋説明覆雜配置

2. 服務設計最佳實踐

  • 一個服務一個進程原則
  • 明確定義服務間的依賴關係
  • 合理設置資源限制
  • 配置健康檢查確保服務可用性
  • 使用命名卷而非綁定掛載

3. 安全最佳實踐

  • 不在Compose文件中硬編碼敏感信息
  • 使用Docker secrets管理敏感數據
  • 限制服務間的網絡訪問
  • 定期更新基礎鏡像
  • 使用非root用户運行容器

4. 性能優化實踐

  • 合理規劃網絡結構
  • 使用多階段構建減小鏡像大小
  • 配置適當的資源限制
  • 使用緩存卷提高構建速度
  • 監控服務性能指標

命令速查表

命令 描述
docker-compose up 啓動所有服務
docker-compose up -d 後台啓動所有服務
docker-compose ps 查看服務狀態
docker-compose logs 查看服務日誌
docker-compose logs -f 實時查看服務日誌
docker-compose exec <service> <command> 在服務中執行命令
docker-compose stop 停止服務
docker-compose start 啓動已停止的服務
docker-compose restart 重啓服務
docker-compose down 停止並刪除容器、網絡
docker-compose down -v 同時刪除卷
docker-compose build 構建服務鏡像
docker-compose pull 拉取服務鏡像
docker-compose config 驗證並查看最終配置