# 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 Pipeline(1-2 天) - [ ] 建立 `.github/workflows/ci.yml` - [ ] 配置程式碼檢查(flake8, bandit) - [ ] 配置自動化測試 - [ ] 測試 PR 觸發 CI ### 階段 4:設定 CD Pipeline(2-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 CI(Self-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 **下次更新**:實作完成後更新實際成果和經驗