Docker 容器化進階:自動化部署與 CI/CD 實戰指南

本文承接從零開始的 Docker 容器化指南,主要討論如何實現全自動化的 Docker 部署流程。透過整合 GitHub Actions、Docker Hub 和自動化工具,我們可以實現程式碼推送後自動更新生產環境的目標。

目錄

自動化部署概述

完整的自動化部署流程包含以下步驟:

  1. 開發者推送程式碼到 GitHub
  2. GitHub Actions 自動執行測試和建置
  3. 建立新的 Docker 映像檔並推送至 Docker Hub
  4. 生產環境自動偵測並更新容器
  5. 健康檢查確認部署狀態

部署流程圖

graph TD
    A[開發者推送程式碼] --> B[GitHub Actions 觸發]
    B --> C[執行測試]
    C --> D[建立 Docker 映像檔]
    D --> E[推送至 Docker Hub]
    E --> F[生產環境更新]
    F --> G[健康檢查]
    G -->|成功| H[部署完成]
    G -->|失敗| I[自動回滾]

GitHub Actions 設定

1. 基礎設定

建立 .github/workflows/deploy.yml 檔案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
name: Deploy to Production

on:
push:
branches: [ main ]
workflow_dispatch: # 允許手動觸發

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1

- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-

- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}

- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: |
user/myapp:latest
user/myapp:${{ github.sha }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new

# 更新快取
- name: Move cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache

2. 部署到伺服器

添加遠端部署步驟:

1
2
3
4
5
6
7
8
9
- name: Deploy to Production
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
cd /path/to/project
./deploy.sh ${{ github.sha }}

自動更新容器設定

1. Watchtower 設定

Watchtower 可以自動監測和更新 Docker 容器:

1
2
3
4
5
6
7
8
9
10
11
12
13
# docker-compose.yml
services:
watchtower:
image: containrrr/watchtower
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- WATCHTOWER_CLEANUP=true
- WATCHTOWER_LABEL_ENABLE=true
- WATCHTOWER_NOTIFICATION_URL=slack://hook-url
labels:
- "com.centurylinklabs.watchtower.enable=true"
command: --interval 300 # 每5分鐘檢查一次

2. 容器標籤設定

為需要自動更新的服務加上標籤:

1
2
3
4
services:
api:
labels:
- "com.centurylinklabs.watchtower.enable=true"

零停機部署策略

1. 藍綠部署

建立部署腳本 deploy.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/bin/bash

# 設定變數
APP_NAME="myapp"
BLUE_PORT="8080"
GREEN_PORT="8081"
PROXY_PORT="80"
VERSION=$1

# 獲取當前活動的部署顏色
ACTIVE_COLOR=$(docker ps --filter "name=${APP_NAME}-" --format "{{.Names}}" | grep -o 'blue\|green')
if [ "$ACTIVE_COLOR" == "blue" ]; then
NEW_COLOR="green"
NEW_PORT=$GREEN_PORT
else
NEW_COLOR="blue"
NEW_PORT=$BLUE_PORT
fi

echo "Starting $NEW_COLOR deployment..."

# 部署新版本
docker-compose -f docker-compose.$NEW_COLOR.yml up -d --build

# 等待服務啟動
sleep 10

# 健康檢查
if curl -f "http://localhost:$NEW_PORT/health"; then
# 切換流量
echo "Switching traffic to $NEW_COLOR deployment"
docker-compose -f docker-compose.proxy.yml up -d --force-recreate

# 移除舊版本
if [ -n "$ACTIVE_COLOR" ]; then
docker-compose -f docker-compose.$ACTIVE_COLOR.yml down
fi

echo "Deployment successful!"
else
echo "Health check failed! Rolling back..."
docker-compose -f docker-compose.$NEW_COLOR.yml down
exit 1
fi

2. 健康檢查設定

在服務中設定健康檢查:

1
2
3
4
5
6
7
8
services:
api:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s

備份與還原機制

1. 自動備份設定

建立備份腳本 backup.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash

# 設定變數
BACKUP_DIR="/backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

# 建立備份目錄
mkdir -p $BACKUP_DIR

# 備份 Docker Compose 設定
docker-compose config > $BACKUP_DIR/docker-compose-$TIMESTAMP.yml

# 備份容器資料
docker-compose exec -T db sh -c 'mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" --all-databases' > $BACKUP_DIR/db-$TIMESTAMP.sql

# 保留最近 7 天的備份
find $BACKUP_DIR -type f -mtime +7 -delete

2. 還原流程

建立還原腳本 restore.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/bin/bash

if [ -z "$1" ]; then
echo "Please provide backup timestamp"
exit 1
fi

TIMESTAMP=$1
BACKUP_DIR="/backups"

# 檢查備份檔案是否存在
if [ ! -f "$BACKUP_DIR/docker-compose-$TIMESTAMP.yml" ] ||
[ ! -f "$BACKUP_DIR/db-$TIMESTAMP.sql" ]; then
echo "Backup files not found"
exit 1
fi

# 停止現有服務
docker-compose down

# 還原設定檔
cp $BACKUP_DIR/docker-compose-$TIMESTAMP.yml docker-compose.yml

# 啟動服務
docker-compose up -d

# 還原資料庫
docker-compose exec -T db sh -c "mysql -u root -p\"$MYSQL_ROOT_PASSWORD\"" < $BACKUP_DIR/db-$TIMESTAMP.sql

監控與告警設定

1. Prometheus 設定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# docker-compose.yml
services:
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"

grafana:
image: grafana/grafana
ports:
- "3000:3000"
depends_on:
- prometheus

2. 告警設定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# prometheus.yml
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093

rule_files:
- alert.rules.yml

scrape_configs:
- job_name: 'docker'
static_configs:
- targets: ['localhost:9323']

故障排除與回滾流程

1. 常見問題處理

  • 映像檔拉取失敗
  • 容器啟動失敗
  • 健康檢查失敗
  • 資料庫連線問題

2. 回滾流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash
# rollback.sh

VERSION=$1

if [ -z "$VERSION" ]; then
echo "Please specify version to rollback"
exit 1
fi

# 拉取指定版本映像檔
docker-compose pull

# 設定版本
export APP_VERSION=$VERSION

# 停止並重新啟動服務
docker-compose down
docker-compose up -d

最佳實踐建議

  1. 版本管理

    • 使用語意化版本號
    • 保留歷史版本映像檔
    • 定期清理舊版本
  2. 監控策略

    • 設定關鍵指標監控
    • 建立適當的告警閾值
    • 保留足夠的日誌資訊
  3. 部署安全

    • 使用加密的環境變數
    • 實施適當的存取控制
    • 定期更新基礎映像檔
  4. 效能優化

    • 最佳化映像檔大小
    • 使用多階段建置
    • 實施快取策略

結論

透過本文介紹的自動化部署流程,我們可以大幅減少人工操作,提高部署效率和可靠性。記得根據實際需求調整配置,並持續優化部署流程。

參考資源