Files
ewoooc/docs/CI_CD_EVALUATION.md
ogt 1b4f3a7bbe
Some checks failed
CD Pipeline / deploy (push) Failing after 59s
feat: EwoooC 初始化 — 完整專案推版至 Gitea
- 建立 Gitea Actions CD pipeline (.gitea/workflows/cd.yaml)
- 部署模式: rsync Python 檔案至 188 → docker restart (volume mount)
- Dockerfile/requirements 變動時自動重建 Docker image
- 部署通知: Telegram (開始/成功/失敗)
- 健康檢查: https://mo.wooo.work/health (最多 5 次重試)
- 同步最新 CLAUDE.md / ADR-008 / memory (2026-04-19)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 01:21:13 +08:00

661 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MOMO Pro System - CI/CD 機制評估報告
## 執行摘要
本文件評估 MOMO Pro System 導入 CI/CD持續整合/持續部署)機制的建議方案。
**現況分析**
- 部署方式:手動執行 `deploy.sh` 腳本(使用 gcloud 命令)
- 版本控制:本地 Git 倉庫,尚未設定遠端倉庫
- 測試覆蓋:無自動化測試套件
- 部署環境GCP VM (asia-east1-a), e2-standard-2
**建議方案**GitHub Actions推薦或 GitLab CI
---
## 1. 平台選擇評估
### 1.1 GitHub Actions推薦
**優點**
- 與 GitHub 原生整合,無需額外設定
- 每月 2,000 分鐘免費額度(私有倉庫)
- 公有倉庫完全免費
- 豐富的 Marketplace Actions 可重用
- 文件齊全,社群活躍
- 支援 Self-hosted Runners可在 GCP VM 上運行,節省成本)
**缺點**
- 需要將程式碼推送到 GitHub
- 超過免費額度後需付費($0.008/分鐘)
- 相對 GitLab CI功能較精簡
**適用場景**
- 開源或小型團隊專案
- 需要快速上手的 CI/CD 解決方案
- 預算有限,希望最大化利用免費額度
**成本估算**
- 免費額度2,000 分鐘/月(私有倉庫)
- 每次 CI/CD 執行約 5-10 分鐘
- 預計每月約 100-200 次部署 → **完全免費**(使用 Self-hosted Runner
---
### 1.2 GitLab CI
**優點**
- 可以 Self-hosted完全控制
- 內建 Container Registry
- 更強大的 Pipeline 配置功能
- 免費版功能豐富
- 每月 400 分鐘免費額度私有倉庫GitLab.com
**缺點**
- Self-hosted 需要額外維護
- GitLab.com 免費額度較少400 分鐘)
- 學習曲線較陡峭
- 如果使用 GitLab.com需要遷移程式碼
**適用場景**
- 大型企業專案
- 需要更複雜的 Pipeline 流程
- 已有 GitLab 基礎設施
**成本估算**
- GitLab.com 免費額度400 分鐘/月
- Self-hosted需額外 VM 資源(約 $20-50/月)
---
### 1.3 建議結論
**推薦 GitHub Actions**,理由:
1. 免費額度充足2,000 分鐘 + Self-hosted Runner 無限制)
2. 與 GitHub 生態系統整合度高
3. 學習成本低,快速上手
4. 可在現有 GCP VM 上運行 Self-hosted Runner完全免費
---
## 2. CI/CD Pipeline 設計
### 2.1 Pipeline 階段規劃
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Trigger │ -> │ Build │ -> │ Test │ -> │ Deploy │
│ (Git Push) │ │ (安裝依賴) │ │ (自動測試) │ │ (部署到GCP) │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
```
### 2.2 建議的 Workflow
#### 階段 1程式碼檢查Linting & Security
- **觸發條件**Pull Request 或 Push 到 main/develop
- **執行內容**
- Python 語法檢查flake8 / pylint
- 安全漏洞掃描bandit
- 程式碼格式檢查black
- **目標**:確保程式碼品質和安全性
- **執行時間**~1-2 分鐘
#### 階段 2自動化測試Testing
- **觸發條件**:通過階段 1
- **執行內容**
- 單元測試pytest
- 整合測試(測試資料庫操作)
- API 端點測試(測試 Flask routes
- **目標**:確保功能正確性
- **執行時間**~2-3 分鐘
#### 階段 3建置與打包Build
- **觸發條件**:通過階段 2
- **執行內容**
- 安裝 Python 依賴pip install -r requirements.txt
- 檢查依賴版本衝突
- 建置文件版本號
- **目標**:確保可部署性
- **執行時間**~1-2 分鐘
#### 階段 4部署Deployment
- **觸發條件**
- **自動觸發**Push 到 main 分支
- **手動觸發**:透過 GitHub Actions UI 手動執行
- **執行內容**
- 備份遠端資料庫
- 上傳程式碼到 GCP VM
- 重啟服務systemctl restart momo
- 健康檢查(確認服務正常運行)
- 失敗時自動回滾
- **目標**:零停機部署
- **執行時間**~3-5 分鐘
---
## 3. 具體實作方案
### 3.1 GitHub Actions 實作
#### 目錄結構
```
.github/
└── workflows/
├── ci.yml # 持續整合(測試、檢查)
├── deploy.yml # 持續部署(部署到 GCP
└── backup.yml # 定期備份任務(每日)
```
#### 範例:`.github/workflows/ci.yml`
```yaml
name: CI - Continuous Integration
on:
pull_request:
branches: [main, develop]
push:
branches: [develop]
jobs:
lint:
name: 程式碼檢查
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 設定 Python 環境
uses: actions/setup-python@v5
with:
python-version: '3.13'
- name: 安裝檢查工具
run: |
pip install flake8 bandit black
- name: Python 語法檢查
run: flake8 app.py scheduler.py --max-line-length=120
- name: 安全漏洞掃描
run: bandit -r . -x ./venv,./lib
- name: 程式碼格式檢查
run: black --check app.py scheduler.py
test:
name: 自動化測試
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v4
- name: 設定 Python 環境
uses: actions/setup-python@v5
with:
python-version: '3.13'
- name: 安裝依賴
run: |
pip install -r requirements.txt
pip install pytest pytest-cov
- name: 執行測試
run: |
pytest tests/ -v --cov=. --cov-report=html
- name: 上傳測試覆蓋率報告
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: htmlcov/
```
#### 範例:`.github/workflows/deploy.yml`
```yaml
name: CD - Deploy to GCP
on:
push:
branches: [main]
workflow_dispatch: # 允許手動觸發
jobs:
deploy:
name: 部署到 GCP Production
runs-on: ubuntu-latest
environment:
name: production
url: http://35.194.172.48
steps:
- uses: actions/checkout@v4
- name: 設定 GCP 認證
uses: google-github-actions/auth@v2
with:
credentials_json: ${{ secrets.GCP_SA_KEY }}
- name: 設定 gcloud CLI
uses: google-github-actions/setup-gcloud@v2
- name: 備份遠端資料庫
run: |
gcloud compute ssh momo-server \
--zone=asia-east1-a \
--command="bash ~/momo_pro_system/backup_system.py"
- name: 上傳程式碼
run: |
gcloud compute scp --recurse \
--exclude='.git' --exclude='venv' --exclude='logs' \
./*.py ./*.html \
momo-server:~/momo_pro_system/ \
--zone=asia-east1-a
- name: 重啟服務
run: |
gcloud compute ssh momo-server \
--zone=asia-east1-a \
--command="sudo systemctl restart momo"
- name: 健康檢查
run: |
sleep 10
gcloud compute ssh momo-server \
--zone=asia-east1-a \
--command="
if sudo systemctl is-active --quiet momo; then
echo '✓ 服務運行正常'
exit 0
else
echo '✗ 服務啟動失敗'
sudo journalctl -u momo -n 50 --no-pager
exit 1
fi
"
- name: 部署失敗時回滾
if: failure()
run: |
echo "部署失敗,執行回滾..."
gcloud compute ssh momo-server \
--zone=asia-east1-a \
--command="bash ~/momo_pro_system/rollback_latest.sh"
```
---
### 3.2 Self-hosted Runner 設定(節省成本)
在 GCP VM 上安裝 GitHub Actions Runner讓 CI/CD 在自己的伺服器上執行(完全免費)。
#### 安裝步驟(在 GCP VM 上執行)
```bash
# 1. 建立 Runner 目錄
mkdir -p ~/actions-runner && cd ~/actions-runner
# 2. 下載 Runner
curl -o actions-runner-linux-x64-2.313.0.tar.gz \
-L https://github.com/actions/runner/releases/download/v2.313.0/actions-runner-linux-x64-2.313.0.tar.gz
# 3. 解壓縮
tar xzf ./actions-runner-linux-x64-2.313.0.tar.gz
# 4. 配置 Runner需要 GitHub Token
./config.sh --url https://github.com/YOUR_USERNAME/momo_pro_system \
--token YOUR_TOKEN
# 5. 安裝為系統服務
sudo ./svc.sh install
sudo ./svc.sh start
```
使用 Self-hosted Runner 後,所有 CI/CD 任務都在您的 GCP VM 上執行,**完全免費**。
---
## 4. 自動化測試策略
### 4.1 測試框架選擇pytest
建議使用 `pytest` 作為主要測試框架,理由:
- Python 最流行的測試框架
- 語法簡潔,易於編寫和維護
- 豐富的插件生態系統
- 支援測試覆蓋率報告
### 4.2 測試架構規劃
```
tests/
├── __init__.py
├── conftest.py # pytest 配置和 fixtures
├── test_app.py # Flask 路由測試
├── test_database.py # 資料庫操作測試
├── test_scheduler.py # 排程器測試
├── test_crawler.py # 爬蟲測試
└── test_email.py # 郵件發送測試
```
### 4.3 測試範例
#### `tests/conftest.py`(測試配置)
```python
import pytest
from app import app, db
@pytest.fixture
def client():
"""Flask 測試客戶端"""
app.config['TESTING'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
with app.test_client() as client:
with app.app_context():
db.create_all()
yield client
@pytest.fixture
def auth_client(client):
"""已登入的測試客戶端"""
client.post('/login', data={
'username': 'admin',
'password': 'test_password'
})
return client
```
#### `tests/test_app.py`(路由測試)
```python
def test_index_redirect(client):
"""測試首頁重定向到登入頁面"""
response = client.get('/')
assert response.status_code == 302
assert '/login' in response.location
def test_login_success(client):
"""測試登入成功"""
response = client.post('/login', data={
'username': 'admin',
'password': 'correct_password'
})
assert response.status_code == 302
assert '/' in response.location
def test_dashboard_access(auth_client):
"""測試已登入用戶可訪問儀表板"""
response = auth_client.get('/dashboard')
assert response.status_code == 200
assert b'dashboard' in response.data.lower()
```
#### `tests/test_database.py`(資料庫測試)
```python
from datetime import date
def test_sales_query(auth_client):
"""測試銷售數據查詢"""
# 插入測試數據
from database.models import RealtimeSalesMonthly
test_data = RealtimeSalesMonthly(
日期=date.today(),
商品ID='TEST001',
商品名稱='測試商品',
銷售數量=100,
銷售金額=5000
)
db.session.add(test_data)
db.session.commit()
# 查詢測試
result = RealtimeSalesMonthly.query.filter_by(商品ID='TEST001').first()
assert result is not None
assert result.銷售數量 == 100
```
### 4.4 測試執行
```bash
# 執行所有測試
pytest tests/ -v
# 執行測試並生成覆蓋率報告
pytest tests/ --cov=. --cov-report=html
# 執行特定測試檔案
pytest tests/test_app.py -v
# 執行特定測試函數
pytest tests/test_app.py::test_login_success -v
```
---
## 5. 零停機部署策略
### 5.1 Blue-Green 部署(推薦)
**概念**維護兩個相同的生產環境Blue 和 Green部署時切換流量。
**實作方式**
```bash
# 1. 部署到 Green 環境(新版本)
gcloud compute ssh momo-server --command="
# 複製當前版本到 blue 目錄
cp -r ~/momo_pro_system ~/momo_pro_system_blue
# 部署新版本到 green 目錄
cd ~/momo_pro_system_green
git pull origin main
# 啟動 Green 服務Port 5001
sudo systemctl restart momo-green
"
# 2. 健康檢查 Green 環境
curl http://localhost:5001/health
# 3. 切換 Nginx 流量到 Green
# 修改 /etc/nginx/sites-available/momo
# proxy_pass http://127.0.0.1:5001; # 從 5000 切換到 5001
# 4. 重新載入 Nginx無停機
sudo nginx -s reload
# 5. 停止 Blue 環境
sudo systemctl stop momo-blue
```
**優點**
- 完全零停機
- 可快速回滾(切換回 Blue
- 可進行 A/B 測試
**缺點**
- 需要雙倍資源(兩個服務同時運行)
- 配置較複雜
---
### 5.2 Rolling 更新(簡化版,推薦用於小型專案)
**概念**:先更新程式碼,然後快速重啟服務。
**實作方式**(現有 deploy.sh 已實現):
```bash
# 1. 備份資料庫
bash ~/momo_pro_system/backup_system.py
# 2. 上傳新程式碼
gcloud compute scp *.py *.html momo-server:~/momo_pro_system/
# 3. 重啟服務Gunicorn graceful reload
sudo systemctl reload momo # 使用 reload 而非 restart
# 4. 健康檢查
sleep 5
curl http://localhost:5000/health || {
echo "部署失敗,回滾..."
# 從備份還原
bash ~/momo_pro_system/rollback_latest.sh
}
```
**優點**
- 簡單易實作
- 資源消耗少
- 適合小型專案
**缺點**
- 有短暫停機(約 2-5 秒)
- 回滾較慢
---
### 5.3 建議實作
**階段 1立即可行**:使用 Rolling 更新 + Gunicorn Graceful Reload
- 修改 `momo.service`,使用 `ExecReload=/bin/kill -HUP $MAINPID`
- 部署時執行 `systemctl reload momo` 而非 `restart`
**階段 2長期目標**Blue-Green 部署
- 當業務量增長後,再實作完整的 Blue-Green 部署
---
## 6. 密鑰管理
### 6.1 GitHub Secrets 配置
需要在 GitHub Repository Settings > Secrets 中新增:
| Secret 名稱 | 說明 | 取得方式 |
|------------|------|----------|
| `GCP_SA_KEY` | GCP Service Account JSON 金鑰 | 在 GCP Console 建立 Service Account 並下載 JSON |
| `GCP_PROJECT_ID` | GCP 專案 ID | GCP Console 查看 |
| `GCP_ZONE` | GCP VM 區域 | `asia-east1-a` |
| `GCP_INSTANCE` | GCP VM 實例名稱 | `momo-server` |
| `ADMIN_PASSWORD_HASH` | 管理員密碼雜湊 | 現有 `generate_password_hash.py` 生成 |
### 6.2 GCP Service Account 權限
需要賦予 Service Account 以下權限:
- `Compute Instance Admin (v1)` - 管理 VM
- `Service Account User` - 使用 Service Account
- `Storage Object Viewer` - 讀取 Cloud Storage如果使用
---
## 7. 實作階段規劃
### 階段 1基礎設施準備1-2 天)
- [ ] 將專案推送到 GitHub 私有倉庫
- [ ] 建立 GCP Service Account 並配置權限
- [ ] 在 GitHub 設定 Secrets
- [ ] 安裝 Self-hosted Runner可選節省成本
### 階段 2建立測試框架3-5 天)
- [ ] 安裝 pytest 和相關插件
- [ ] 撰寫基本測試(路由測試、資料庫測試)
- [ ] 建立測試數據 fixtures
- [ ] 達到 >60% 測試覆蓋率
### 階段 3設定 CI Pipeline1-2 天)
- [ ] 建立 `.github/workflows/ci.yml`
- [ ] 配置程式碼檢查flake8, bandit
- [ ] 配置自動化測試
- [ ] 測試 PR 觸發 CI
### 階段 4設定 CD Pipeline2-3 天)
- [ ] 建立 `.github/workflows/deploy.yml`
- [ ] 整合現有 `deploy.sh` 腳本
- [ ] 實作自動備份機制
- [ ] 實作健康檢查和回滾
- [ ] 測試自動部署流程
### 階段 5優化與監控持續進行
- [ ] 整合 Prometheus 監控到 CI/CD
- [ ] 設定部署失敗通知Slack / Email
- [ ] 優化部署速度
- [ ] 建立部署文件和 Runbook
**總計時間**:約 1-2 週(根據團隊經驗調整)
---
## 8. 成本分析
### 8.1 GitHub Actions使用 Self-hosted Runner
- **費用**$0/月(完全免費)
- **說明**:所有 CI/CD 任務在 GCP VM 上執行,不消耗 GitHub 提供的分鐘數
### 8.2 GitHub Actions使用 GitHub-hosted Runner
- **免費額度**2,000 分鐘/月(私有倉庫)
- **預估使用**
- 每次 CI: 5 分鐘
- 每次 CD: 5 分鐘
- 每月約 100 次部署 = 1,000 分鐘
- **費用**$0/月(在免費額度內)
### 8.3 GitLab CISelf-hosted
- **額外 VM 成本**$20-50/月(需要額外的 Runner VM
- **維護成本**:需要額外的系統維護時間
### 8.4 總結
**建議使用 GitHub Actions + Self-hosted Runner**,完全免費且功能完整。
---
## 9. 風險評估
| 風險 | 影響 | 機率 | 緩解措施 |
|-----|------|------|----------|
| 部署失敗導致服務中斷 | 高 | 中 | 實作自動回滾機制 + 健康檢查 |
| 測試覆蓋不足,未發現 Bug | 中 | 高 | 逐步提升測試覆蓋率至 >80% |
| GCP Service Account 金鑰洩漏 | 高 | 低 | 使用 GitHub Secrets + 定期輪換金鑰 |
| CI/CD Pipeline 執行時間過長 | 低 | 中 | 使用 Self-hosted Runner + 快取依賴 |
| 資料庫遷移失敗 | 高 | 低 | 部署前自動備份 + 測試環境驗證 |
---
## 10. 建議與結論
### 10.1 核心建議
1. **採用 GitHub Actions** 作為 CI/CD 平台
2. **使用 Self-hosted Runner** 節省成本(完全免費)
3. **分階段實作**,先建立 CI再建立 CD
4. **優先建立測試框架**,確保程式碼品質
5. **實作自動回滾機制**,降低部署風險
### 10.2 立即可執行的行動
1. 將專案推送到 GitHub私有倉庫
2. 建立 `tests/` 目錄並撰寫基本測試
3. 建立 `.github/workflows/ci.yml`(先實作 CI
4. 驗證 CI 正常運作後,再建立 `deploy.yml`(實作 CD
### 10.3 長期目標
- 測試覆蓋率 >80%
- 平均部署時間 <5 分鐘
- 自動化部署成功率 >95%
- 零停機部署Blue-Green
---
## 附錄
### A. 相關文件
- [GitHub Actions 官方文件](https://docs.github.com/en/actions)
- [pytest 官方文件](https://docs.pytest.org/)
- [Gunicorn Graceful Reload](https://docs.gunicorn.org/en/stable/signals.html)
- [GCP Service Account 設定](https://cloud.google.com/iam/docs/service-accounts)
### B. 參考專案
- [Flask CI/CD 範例](https://github.com/actions/starter-workflows/blob/main/deployments/azure-webapps-python.yml)
- [Python 測試最佳實踐](https://realpython.com/pytest-python-testing/)
---
**文件版本**1.0
**撰寫日期**2026-01-14
**下次更新**:實作完成後更新實際成果和經驗