#!/bin/bash # ============================================================ # MOMO Pro System - UAT 一鍵部署腳本 # ============================================================ # 用法: ./deploy_to_uat.sh [選項] # -f, --full 完整同步 (包含所有檔案) # -q, --quick 快速更新 (僅 Python/HTML) # -r, --restart 僅重啟容器 # -h, --help 顯示說明 # # 預設行為: 快速更新 + 重啟容器 # ============================================================ set -e # 發生錯誤時停止執行 # === 配置 === UAT_HOST="wooo@192.168.0.110" UAT_PATH="/home/wooo/momo_pro_system" LOCAL_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" CONTAINER_NAME="momo-pro-system" # === 顏色輸出 === RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # === 函數定義 === print_header() { echo "" echo -e "${BLUE}============================================================${NC}" echo -e "${BLUE} MOMO Pro System - UAT 部署工具${NC}" echo -e "${BLUE}============================================================${NC}" echo -e " 目標主機: ${GREEN}${UAT_HOST}${NC}" echo -e " 目標路徑: ${GREEN}${UAT_PATH}${NC}" echo "" } print_step() { echo -e "${YELLOW}[步驟]${NC} $1" } print_success() { echo -e "${GREEN}[成功]${NC} $1" } print_error() { echo -e "${RED}[錯誤]${NC} $1" } show_help() { echo "用法: $0 [選項]" echo "" echo "選項:" echo " -f, --full 完整同步 (rsync 整個專案,排除 data/logs/venv)" echo " -q, --quick 快速更新 (僅同步 Python 和 HTML 檔案)" echo " -r, --restart 僅重啟容器 (不同步檔案)" echo " -m, --monitor 啟動監控服務 (Grafana/Prometheus/Loki)" echo " -v, --verify 驗證部署狀態" echo " -h, --help 顯示此說明" echo "" echo "範例:" echo " $0 # 預設: 快速更新 + 重啟" echo " $0 -f # 完整同步 + 重啟" echo " $0 -r # 僅重啟容器" echo " $0 -v # 驗證部署狀態" } # 檢查 SSH 連線 check_ssh() { print_step "檢查 SSH 連線..." if ssh -o ConnectTimeout=5 ${UAT_HOST} "echo 'SSH OK'" > /dev/null 2>&1; then print_success "SSH 連線正常" return 0 else print_error "無法連線到 ${UAT_HOST}" exit 1 fi } # 快速更新 (僅 Python/HTML) quick_sync() { print_step "快速同步 Python 和 HTML 檔案..." # 同步 routes 目錄 echo " - 同步 routes/*.py" scp -q ${LOCAL_PATH}/routes/*.py ${UAT_HOST}:${UAT_PATH}/routes/ # 同步根目錄的 Python 檔案 echo " - 同步根目錄 Python 檔案" scp -q ${LOCAL_PATH}/app.py ${UAT_HOST}:${UAT_PATH}/ scp -q ${LOCAL_PATH}/auth.py ${UAT_HOST}:${UAT_PATH}/ scp -q ${LOCAL_PATH}/config.py ${UAT_HOST}:${UAT_PATH}/ scp -q ${LOCAL_PATH}/auto_import_routes.py ${UAT_HOST}:${UAT_PATH}/ 2>/dev/null || true scp -q ${LOCAL_PATH}/vendor_routes.py ${UAT_HOST}:${UAT_PATH}/ 2>/dev/null || true scp -q ${LOCAL_PATH}/crawler_management_routes.py ${UAT_HOST}:${UAT_PATH}/ 2>/dev/null || true # 同步 services 目錄 echo " - 同步 services/*.py" scp -q ${LOCAL_PATH}/services/*.py ${UAT_HOST}:${UAT_PATH}/services/ # 同步 database 目錄 echo " - 同步 database/*.py" scp -q ${LOCAL_PATH}/database/*.py ${UAT_HOST}:${UAT_PATH}/database/ # 同步 templates 目錄 echo " - 同步 templates/" rsync -az --delete -e ssh \ ${LOCAL_PATH}/templates/ \ ${UAT_HOST}:${UAT_PATH}/templates/ # 同步根目錄的 HTML 檔案 echo " - 同步根目錄 HTML 檔案" scp -q ${LOCAL_PATH}/*.html ${UAT_HOST}:${UAT_PATH}/ 2>/dev/null || true print_success "快速同步完成" } # 完整同步 (rsync) full_sync() { print_step "完整同步專案檔案..." rsync -avz --progress -e ssh \ --exclude='venv' \ --exclude='__pycache__' \ --exclude='*.pyc' \ --exclude='.git' \ --exclude='backups' \ --exclude='logs/*.log' \ --exclude='data/*.db' \ --exclude='data/*.db-*' \ --exclude='.env' \ --exclude='*.tar.gz' \ ${LOCAL_PATH}/ \ ${UAT_HOST}:${UAT_PATH}/ print_success "完整同步完成" } # 重啟容器 restart_container() { print_step "重啟 Docker 容器 (${CONTAINER_NAME})..." ssh ${UAT_HOST} "docker restart ${CONTAINER_NAME}" # 等待容器啟動 echo " - 等待容器啟動..." sleep 5 # 檢查容器狀態 local status=$(ssh ${UAT_HOST} "docker ps --filter name=${CONTAINER_NAME} --format '{{.Status}}' | head -1") if [[ $status == *"healthy"* ]] || [[ $status == *"Up"* ]]; then print_success "容器已啟動: ${status}" else print_error "容器狀態異常: ${status}" echo " 查看日誌: ssh ${UAT_HOST} 'docker logs ${CONTAINER_NAME} --tail 50'" fi } # 重建容器 (當 docker-compose.yml 有變更時) recreate_container() { print_step "重建 Docker 容器..." ssh ${UAT_HOST} "cd ${UAT_PATH} && \ docker rm -f ${CONTAINER_NAME} 2>/dev/null || true && \ docker-compose up -d momo-app" # 等待容器啟動 echo " - 等待容器啟動..." sleep 8 local status=$(ssh ${UAT_HOST} "docker ps --filter name=${CONTAINER_NAME} --format '{{.Status}}' | head -1") print_success "容器已重建: ${status}" } # 啟動監控服務 start_monitoring() { print_step "啟動監控服務..." ssh ${UAT_HOST} "cd ${UAT_PATH} && docker-compose --profile monitoring up -d" print_success "監控服務已啟動" echo " - Grafana: http://192.168.0.110:3000" echo " - Prometheus: http://192.168.0.110:9090" } # 驗證部署 verify_deployment() { print_step "驗證部署狀態..." echo "" echo " [容器狀態]" ssh ${UAT_HOST} "docker ps --filter name=momo --format 'table {{.Names}}\t{{.Status}}' | head -10" echo "" echo " [健康檢查]" local health=$(curl -s -o /dev/null -w "%{http_code}" "https://mo.wooo.work/health" 2>/dev/null || echo "000") if [ "$health" = "200" ]; then echo -e " /health: ${GREEN}200 OK${NC}" else echo -e " /health: ${RED}${health}${NC}" fi echo "" echo " [登入保護驗證] (應為 302)" for path in "/" "/auto_import" "/daily_sales" "/sales_analysis"; do local code=$(curl -s -o /dev/null -w "%{http_code}" "https://mo.wooo.work${path}" 2>/dev/null || echo "000") if [ "$code" = "302" ]; then echo -e " ${path}: ${GREEN}${code}${NC}" else echo -e " ${path}: ${RED}${code}${NC}" fi done echo "" echo " [公開端點] (應為 200)" for path in "/health" "/metrics"; do local code=$(curl -s -o /dev/null -w "%{http_code}" "https://mo.wooo.work${path}" 2>/dev/null || echo "000") if [ "$code" = "200" ]; then echo -e " ${path}: ${GREEN}${code}${NC}" else echo -e " ${path}: ${RED}${code}${NC}" fi done echo "" print_success "驗證完成" } # === 主程式 === print_header # 解析參數 MODE="quick" # 預設模式 RESTART=true VERIFY=false while [[ $# -gt 0 ]]; do case $1 in -f|--full) MODE="full" shift ;; -q|--quick) MODE="quick" shift ;; -r|--restart) MODE="restart_only" shift ;; -m|--monitor) MODE="monitor" shift ;; -v|--verify) VERIFY=true shift ;; -h|--help) show_help exit 0 ;; *) echo "未知選項: $1" show_help exit 1 ;; esac done # 執行 check_ssh case $MODE in "quick") quick_sync restart_container ;; "full") full_sync recreate_container ;; "restart_only") restart_container ;; "monitor") start_monitoring ;; esac if [ "$VERIFY" = true ] || [ "$MODE" != "monitor" ]; then verify_deployment fi echo "" echo -e "${GREEN}============================================================${NC}" echo -e "${GREEN} 部署完成!${NC}" echo -e "${GREEN}============================================================${NC}" echo ""