#!/bin/bash # ============================================================================= # WOOO TECH - Momo Pro System # UAT Docker 一鍵部署腳本 # ============================================================================= set -e # 顏色定義 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' NC='\033[0m' # No Color # 配置 UAT_HOST="192.168.0.110" UAT_USER="wooo" UAT_PATH="/home/wooo/momo_pro_system" LOCAL_PATH="/Users/ogt/momo_pro_system" IMAGE_NAME="wooo/momo-pro-system" CONTAINER_NAME="momo-pro-system" # 函數:打印帶顏色的訊息 print_header() { echo "" echo -e "${PURPLE}=============================================================================${NC}" echo -e "${PURPLE} $1${NC}" echo -e "${PURPLE}=============================================================================${NC}" } print_step() { echo -e "${CYAN}▶ $1${NC}" } print_success() { echo -e "${GREEN}✅ $1${NC}" } print_warning() { echo -e "${YELLOW}⚠️ $1${NC}" } print_error() { echo -e "${RED}❌ $1${NC}" } print_info() { echo -e "${BLUE}ℹ️ $1${NC}" } # 檢查 SSH 連線 check_ssh() { print_step "檢查 SSH 連線..." if ssh -o ConnectTimeout=5 -o BatchMode=yes ${UAT_USER}@${UAT_HOST} "echo ok" 2>/dev/null; then print_success "SSH 連線正常(免密碼)" return 0 else print_warning "需要 SSH 密碼驗證" return 1 fi } # 主要部署流程 deploy() { print_header "WOOO TECH - UAT Docker 部署" echo -e "${CYAN}目標主機: ${UAT_USER}@${UAT_HOST}${NC}" echo -e "${CYAN}部署時間: $(date '+%Y-%m-%d %H:%M:%S')${NC}" echo "" # 步驟 1: 同步配置檔案 print_header "步驟 1/6: 同步 Docker 配置檔案到 UAT" print_step "上傳 Dockerfile..." scp "${LOCAL_PATH}/Dockerfile" ${UAT_USER}@${UAT_HOST}:${UAT_PATH}/ print_step "上傳 docker-compose.yml..." scp "${LOCAL_PATH}/docker-compose.yml" ${UAT_USER}@${UAT_HOST}:${UAT_PATH}/ print_step "上傳 .dockerignore..." scp "${LOCAL_PATH}/.dockerignore" ${UAT_USER}@${UAT_HOST}:${UAT_PATH}/ print_step "上傳 docker/ 目錄..." scp -r "${LOCAL_PATH}/docker" ${UAT_USER}@${UAT_HOST}:${UAT_PATH}/ print_step "上傳 requirements.txt..." scp "${LOCAL_PATH}/requirements.txt" ${UAT_USER}@${UAT_HOST}:${UAT_PATH}/ print_step "上傳核心 Python 檔案..." scp "${LOCAL_PATH}/app.py" ${UAT_USER}@${UAT_HOST}:${UAT_PATH}/ scp "${LOCAL_PATH}/auth.py" ${UAT_USER}@${UAT_HOST}:${UAT_PATH}/ scp "${LOCAL_PATH}/config.py" ${UAT_USER}@${UAT_HOST}:${UAT_PATH}/ scp "${LOCAL_PATH}/scheduler.py" ${UAT_USER}@${UAT_HOST}:${UAT_PATH}/ print_step "上傳 HTML 模板..." scp "${LOCAL_PATH}"/*.html ${UAT_USER}@${UAT_HOST}:${UAT_PATH}/ 2>/dev/null || true print_step "上傳 services/ 目錄..." scp -r "${LOCAL_PATH}/services" ${UAT_USER}@${UAT_HOST}:${UAT_PATH}/ print_step "上傳 database/ 目錄..." scp -r "${LOCAL_PATH}/database" ${UAT_USER}@${UAT_HOST}:${UAT_PATH}/ print_step "上傳 utils/ 目錄..." scp -r "${LOCAL_PATH}/utils" ${UAT_USER}@${UAT_HOST}:${UAT_PATH}/ print_step "上傳 static/ 目錄..." scp -r "${LOCAL_PATH}/static" ${UAT_USER}@${UAT_HOST}:${UAT_PATH}/ print_step "上傳 web/ 目錄..." scp -r "${LOCAL_PATH}/web" ${UAT_USER}@${UAT_HOST}:${UAT_PATH}/ print_success "檔案同步完成" # 步驟 2: 停止現有服務 print_header "步驟 2/6: 停止現有服務" print_step "停止 systemd momo 服務..." ssh ${UAT_USER}@${UAT_HOST} "sudo systemctl stop momo 2>/dev/null || echo '服務未運行'" print_step "停止並刪除舊的 Docker 容器..." ssh ${UAT_USER}@${UAT_HOST} "docker stop ${CONTAINER_NAME} 2>/dev/null || true" ssh ${UAT_USER}@${UAT_HOST} "docker rm ${CONTAINER_NAME} 2>/dev/null || true" print_success "服務已停止" # 步驟 3: 建置 Docker Image print_header "步驟 3/6: 建置 Docker Image" print_info "這可能需要幾分鐘,請耐心等候..." ssh ${UAT_USER}@${UAT_HOST} "cd ${UAT_PATH} && docker build -t ${IMAGE_NAME}:latest ." print_success "Docker Image 建置完成" # 步驟 4: 啟動 Docker 容器 print_header "步驟 4/6: 啟動 Docker 容器" ssh ${UAT_USER}@${UAT_HOST} "cd ${UAT_PATH} && docker run -d \ --name ${CONTAINER_NAME} \ -p 5000:5000 \ -v ./data:/app/data \ -v ./logs:/app/logs \ -v ./config:/app/config \ -v ./backups:/app/backups \ --env-file .env \ --restart unless-stopped \ ${IMAGE_NAME}:latest" print_success "Docker 容器已啟動" # 步驟 5: 等待服務啟動 print_header "步驟 5/6: 等待服務啟動" print_info "等待 30 秒讓服務完全啟動..." for i in {1..30}; do echo -ne "\r${CYAN}等待中... ${i}/30 秒${NC}" sleep 1 done echo "" print_success "等待完成" # 步驟 6: 驗證部署 print_header "步驟 6/6: 驗證部署" print_step "檢查容器狀態..." ssh ${UAT_USER}@${UAT_HOST} "docker ps --filter name=${CONTAINER_NAME} --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'" print_step "測試健康檢查端點..." HEALTH_STATUS=$(ssh ${UAT_USER}@${UAT_HOST} "curl -s -o /dev/null -w '%{http_code}' http://localhost:5000/health" || echo "000") if [ "$HEALTH_STATUS" = "200" ]; then print_success "健康檢查通過 (HTTP 200)" else print_warning "健康檢查回傳 HTTP ${HEALTH_STATUS}" fi print_step "測試首頁..." HOME_STATUS=$(ssh ${UAT_USER}@${UAT_HOST} "curl -s -o /dev/null -w '%{http_code}' http://localhost:5000/" || echo "000") if [ "$HOME_STATUS" = "200" ] || [ "$HOME_STATUS" = "302" ]; then print_success "首頁正常 (HTTP ${HOME_STATUS})" else print_warning "首頁回傳 HTTP ${HOME_STATUS}" fi # 完成 print_header "部署完成!" echo "" echo -e "${GREEN}┌─────────────────────────────────────────────────────────────┐${NC}" echo -e "${GREEN}│ 🎉 UAT Docker 部署成功! │${NC}" echo -e "${GREEN}├─────────────────────────────────────────────────────────────┤${NC}" echo -e "${GREEN}│ 存取網址: http://${UAT_HOST}:5000 │${NC}" echo -e "${GREEN}│ 容器名稱: ${CONTAINER_NAME} │${NC}" echo -e "${GREEN}│ 映像名稱: ${IMAGE_NAME}:latest │${NC}" echo -e "${GREEN}└─────────────────────────────────────────────────────────────┘${NC}" echo "" echo -e "${CYAN}常用指令:${NC}" echo -e " 查看日誌: ssh ${UAT_USER}@${UAT_HOST} 'docker logs -f ${CONTAINER_NAME}'" echo -e " 重啟容器: ssh ${UAT_USER}@${UAT_HOST} 'docker restart ${CONTAINER_NAME}'" echo -e " 停止容器: ssh ${UAT_USER}@${UAT_HOST} 'docker stop ${CONTAINER_NAME}'" echo "" } # 顯示使用說明 usage() { echo "使用方式: $0 [選項]" echo "" echo "選項:" echo " deploy 執行完整部署 (預設)" echo " status 檢查 UAT 容器狀態" echo " logs 查看容器日誌" echo " restart 重啟容器" echo " stop 停止容器" echo " help 顯示此說明" echo "" } # 檢查狀態 check_status() { print_header "UAT Docker 容器狀態" ssh ${UAT_USER}@${UAT_HOST} "docker ps -a --filter name=${CONTAINER_NAME} --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'" echo "" print_step "磁碟空間:" ssh ${UAT_USER}@${UAT_HOST} "df -h | head -3" } # 查看日誌 view_logs() { print_header "UAT Docker 容器日誌 (最近 100 行)" ssh ${UAT_USER}@${UAT_HOST} "docker logs --tail 100 ${CONTAINER_NAME}" } # 重啟容器 restart_container() { print_header "重啟 UAT Docker 容器" ssh ${UAT_USER}@${UAT_HOST} "docker restart ${CONTAINER_NAME}" print_success "容器已重啟" } # 停止容器 stop_container() { print_header "停止 UAT Docker 容器" ssh ${UAT_USER}@${UAT_HOST} "docker stop ${CONTAINER_NAME}" print_success "容器已停止" } # 主程式 case "${1:-deploy}" in deploy) deploy ;; status) check_status ;; logs) view_logs ;; restart) restart_container ;; stop) stop_container ;; help|--help|-h) usage ;; *) print_error "未知選項: $1" usage exit 1 ;; esac