diff --git a/deploy.sh b/deploy.sh index 0b898e7..aa69a28 100755 --- a/deploy.sh +++ b/deploy.sh @@ -2,428 +2,275 @@ set -e -# ============================================================================ -# CloudForge Backend - Build, Deploy & Monitor -# 一個 script 做晒:build → push → deploy → monitor -# ============================================================================ - -# 配置 -# 改用 K3S 內部 registry DNS,避免網絡超時問題 -REGISTRY="registry.kube-system.svc.cluster.local:5000" +# Configuration +REGISTRY_URL="fungtest.duckdns.org/cloudforge-dev/cloudforge-dashboard-backend:latest" +GITEA_DOMAIN="fungtest.duckdns.org" +GITEA_USERNAME="cloudforge-dev" +GITEA_PASSWORD="a7964adcd821be4c6d7c4ca0b05865030a9d0b82" +GITEA_EMAIL="deploy@cloudforge.local" IMAGE_NAME="cloudforge-dashboard-backend" -TAG="latest" -NAMESPACE="cloudforge" -SERVICE_PORT="5001" +NAMESPACE="default" +PORT="5001" +GIT_REMOTE="ssh://gitea-cloudforge-dev/cloudforge-dev/dashboard-backend.git" +REPLICAS=1 +TIMEOUT=120 -# 顏色 +# Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' -BLUE='\033[0;34m' NC='\033[0m' # No Color -# 函數:打印標題 -print_title() { - echo -e "\n${BLUE}════════════════════════════════════════${NC}" - echo -e "${BLUE}$1${NC}" - echo -e "${BLUE}════════════════════════════════════════${NC}\n" +# Functions +log() { + echo -e "${GREEN}✅${NC} $1" } -# 函數:打印成功 -print_success() { - echo -e "${GREEN}✅ $1${NC}" +warn() { + echo -e "${YELLOW}⚠️ ${NC} $1" } -# 函數:打印警告 -print_warning() { - echo -e "${YELLOW}⚠️ $1${NC}" +error() { + echo -e "${RED}❌${NC} $1" + exit 1 } -# 函數:打印錯誤 -print_error() { - echo -e "${RED}❌ $1${NC}" +separator() { + echo "" + echo "════════════════════════════════════════" + echo "$1" + echo "════════════════════════════════════════" + echo "" } -# 函數:打印步驟 -print_step() { - echo -e "\n${BLUE}→ $1${NC}" +# Main deployment logic +deploy_all() { + separator "Step 1: Build Docker Image" + build_image + + separator "Step 2: Login to Gitea Registry" + login_registry + + separator "Step 3: Push Image to Gitea Registry" + push_image + + separator "Step 4: Create K3S Resources" + create_namespace + create_secret + create_deployment + create_service + + separator "Step 5: Commit & Push to Git" + commit_to_git + + separator "Step 6: Wait for Deployment" + wait_for_deployment + + separator "✅ Deployment Complete!" + echo "Image: ${REGISTRY_URL}" + echo "Namespace: ${NAMESPACE}" + echo "" + echo "Verify deployment:" + echo " kubectl get pods -n ${NAMESPACE}" + echo " kubectl describe pod -n ${NAMESPACE} -l app=${IMAGE_NAME}" } -# ============================================================================ -# 主菜單 -# ============================================================================ - -show_menu() { - echo -e "\n${BLUE}CloudForge Backend 部署工具${NC}" - echo "================================" - echo "1. Build & Deploy (完整流程)" - echo "2. 只 Build Image" - echo "3. 只 Push to Registry" - echo "4. 只 Deploy to K3S" - echo "5. 查看狀態" - echo "6. 查看 Logs" - echo "7. 測試 API" - echo "8. 重啟 Deployment" - echo "9. 清理所有資源" - echo "0. 退出" - echo "================================" - read -p "選擇操作 (0-9): " choice -} - -# ============================================================================ -# Step 1: Build Image -# ============================================================================ - build_image() { - print_title "Step 1: Build Docker Image" - - if [ ! -f "Dockerfile" ]; then - print_error "Dockerfile not found!" - print_error "請確認你喺 dashboard-backend 目錄" - return 1 - fi - - print_step "Building $IMAGE_NAME:$TAG" - - if podman build -t $IMAGE_NAME:$TAG . ; then - print_success "Build completed" - return 0 - else - print_error "Build failed" - return 1 - fi + echo "→ Building ${IMAGE_NAME}:latest" + + if [ ! -f "Dockerfile" ]; then + error "Dockerfile not found in current directory" + fi + + podman build -t ${IMAGE_NAME}:latest . || docker build -t ${IMAGE_NAME}:latest . + log "Build completed" } -# ============================================================================ -# Step 2: Push to Registry (via kubectl) -# ============================================================================ +login_registry() { + echo "→ Authenticating with Gitea Registry at ${GITEA_DOMAIN}" + + echo "${GITEA_PASSWORD}" | podman login -u ${GITEA_USERNAME} --password-stdin ${GITEA_DOMAIN} 2>/dev/null || \ + echo "${GITEA_PASSWORD}" | docker login -u ${GITEA_USERNAME} --password-stdin ${GITEA_DOMAIN} 2>/dev/null || \ + error "Failed to authenticate with registry" + + log "Registry authentication successful" +} -push_to_registry() { - print_title "Step 2: Push to K3S Registry (via pod)" - - print_step "Tagging image for registry" - podman tag $IMAGE_NAME:$TAG $IMAGE_NAME:$TAG - - print_step "Saving image to tar" - podman save $IMAGE_NAME:$TAG -o /tmp/$IMAGE_NAME.tar - - print_step "Creating temporary pod to push image" - - # 建立臨時 pod 推送 image - cat </dev/null || true -apiVersion: batch/v1 -kind: Job +push_image() { + echo "→ Tagging image for ${REGISTRY_URL}" + podman tag ${IMAGE_NAME}:latest ${REGISTRY_URL} || docker tag ${IMAGE_NAME}:latest ${REGISTRY_URL} + + echo "→ Pushing to registry (this may take a few minutes...)" + podman push ${REGISTRY_URL} || docker push ${REGISTRY_URL} + log "Image pushed successfully" +} + +create_namespace() { + echo "→ Creating namespace if not exists" + kubectl create namespace ${NAMESPACE} --dry-run=client -o yaml | kubectl apply -f - + log "Namespace ready" +} + +create_secret() { + echo "→ Creating image pull secret" + + kubectl delete secret gitea-registry -n ${NAMESPACE} 2>/dev/null || true + + kubectl create secret docker-registry gitea-registry \ + --docker-server=${GITEA_DOMAIN} \ + --docker-username=${GITEA_USERNAME} \ + --docker-password="${GITEA_PASSWORD}" \ + --docker-email=${GITEA_EMAIL} \ + -n ${NAMESPACE} + + log "Image pull secret created" +} + +create_deployment() { + echo "→ Creating deployment" + + cat < /dev/null - - print_step "Checking if deployment exists" - if kubectl get deployment $IMAGE_NAME -n $NAMESPACE &>/dev/null ; then - print_step "Updating existing deployment" - kubectl set image deployment/$IMAGE_NAME \ - $IMAGE_NAME=$REGISTRY/$IMAGE_NAME:$TAG \ - -n $NAMESPACE \ - --record - else - print_step "Creating new deployment" - kubectl create deployment $IMAGE_NAME \ - --image=$IMAGE_NAME:$TAG \ - --replicas=1 \ - -n $NAMESPACE \ - --dry-run=client -o yaml | kubectl apply -f - - print_step "Creating service" - kubectl expose deployment $IMAGE_NAME \ - --port=$SERVICE_PORT \ - --target-port=$SERVICE_PORT \ - -n $NAMESPACE \ - --dry-run=client -o yaml | kubectl apply -f - 2>/dev/null || true - fi - - print_success "Deployment updated" + log "Deployment created/updated" } -# ============================================================================ -# Step 4: Commit and Push to Gitea -# ============================================================================ - -commit_to_gitea() { - print_title "Step 4: Commit to Gitea" - - print_step "Adding files" - git add . 2>/dev/null || print_warning "No files to add" - - print_step "Committing" - git commit -m "Deploy backend - $(date '+%Y-%m-%d %H:%M:%S')" 2>/dev/null || print_warning "Nothing to commit" - - print_step "Pushing to Gitea" - if git push origin main ; then - print_success "Pushed to Gitea" - return 0 - else - print_warning "Git push failed (network or auth issue)" - return 0 - fi -} - -# ============================================================================ -# Step 5: Wait and Verify -# ============================================================================ - -wait_and_verify() { - print_title "Step 5: Waiting for Deployment" - - print_step "Waiting for pod to be ready (max 120s)" - if kubectl wait --for=condition=ready pod -l app=$IMAGE_NAME -n $NAMESPACE --timeout=120s 2>/dev/null ; then - print_success "Pod is ready" - else - print_warning "Pod not ready yet, proceeding anyway" - fi - - print_step "Checking deployment status" - kubectl get deployment $IMAGE_NAME -n $NAMESPACE - - echo "" - print_step "Checking pod status" - kubectl get pods -n $NAMESPACE -l app=$IMAGE_NAME - - echo "" - print_success "Deployment complete!" -} - -# ============================================================================ -# 監控:查看狀態 -# ============================================================================ - -check_status() { - print_title "CloudForge Backend Status" - - echo -e "${BLUE}Namespace:${NC} $NAMESPACE" - echo -e "${BLUE}Deployment:${NC} $IMAGE_NAME" - - echo -e "\n${BLUE}=== Deployment ===${NC}" - kubectl get deployment -n $NAMESPACE || echo "No deployment found" - - echo -e "\n${BLUE}=== Pods ===${NC}" - kubectl get pods -n $NAMESPACE -l app=$IMAGE_NAME || echo "No pods found" - - echo -e "\n${BLUE}=== Services ===${NC}" - kubectl get svc -n $NAMESPACE || echo "No services found" - - echo -e "\n${BLUE}=== Recent Events ===${NC}" - kubectl get events -n $NAMESPACE --sort-by='.lastTimestamp' | tail -5 || echo "No events" - - echo -e "\n${BLUE}=== Local Images ===${NC}" - podman images | grep $IMAGE_NAME || echo "No images found" -} - -# ============================================================================ -# 監控:查看 Logs -# ============================================================================ - -view_logs() { - print_title "View Logs" - - echo -e "${BLUE}Last 50 lines:${NC}" - kubectl logs deployment/$IMAGE_NAME -n $NAMESPACE --tail=50 || echo "No logs found" - - echo "" - read -p "實時看 logs?(y/n): " -n 1 -r - echo - if [[ $REPLY =~ ^[Yy]$ ]]; then - echo "按 Ctrl+C 停止" - kubectl logs -f deployment/$IMAGE_NAME -n $NAMESPACE - fi -} - -# ============================================================================ -# 測試:API Test -# ============================================================================ - -test_api() { - print_title "Testing API" - - print_step "Setting up port-forward" - kubectl port-forward -n $NAMESPACE svc/$IMAGE_NAME $SERVICE_PORT:$SERVICE_PORT > /dev/null 2>&1 & - PF_PID=$! - - sleep 2 - - print_step "Testing health endpoint" - if curl -s http://localhost:$SERVICE_PORT/health 2>/dev/null ; then - echo "" - print_success "API is responding" - else - print_error "API not responding" - fi - - kill $PF_PID 2>/dev/null || true -} - -# ============================================================================ -# 操作:重啟 Deployment -# ============================================================================ - -restart_deployment() { - print_title "Restarting Deployment" - - print_step "Restarting deployment" - if kubectl rollout restart deployment/$IMAGE_NAME -n $NAMESPACE ; then - print_success "Restart triggered" +create_service() { + echo "→ Creating service" - print_step "Waiting for new pod" - kubectl wait --for=condition=ready pod -l app=$IMAGE_NAME -n $NAMESPACE --timeout=120s 2>/dev/null || print_warning "Timeout waiting for pod" + cat </dev/null || true - - print_step "Deleting service" - kubectl delete svc $IMAGE_NAME -n $NAMESPACE 2>/dev/null || true - - print_step "Deleting namespace" - kubectl delete namespace $NAMESPACE 2>/dev/null || true - - print_success "Cleanup complete" +wait_for_deployment() { + echo "→ Waiting for deployment to be ready (max ${TIMEOUT}s)" + + if kubectl wait --for=condition=available --timeout=${TIMEOUT}s \ + deployment/${IMAGE_NAME} -n ${NAMESPACE} 2>/dev/null; then + log "Deployment is ready!" + else + warn "Deployment not ready within ${TIMEOUT}s, checking status..." + + echo "" + echo "Deployment status:" + kubectl get deployment -n ${NAMESPACE} ${IMAGE_NAME} + + echo "" + echo "Pod status:" + kubectl get pods -n ${NAMESPACE} -l app=${IMAGE_NAME} + + echo "" + echo "Pod details:" + kubectl describe pod -n ${NAMESPACE} -l app=${IMAGE_NAME} | tail -20 + fi } -# ============================================================================ -# Main Loop -# ============================================================================ - -main() { - while true; do - show_menu +commit_to_git() { + echo "→ Committing changes to Git" - case $choice in - 1) - # 完整流程 - build_image && push_to_registry && deploy_to_k3s && commit_to_gitea && wait_and_verify + git config user.email "deploy@cloudforge.local" + git config user.name "CloudForge Deploy" + + git add -A + git commit -m "Deploy ${IMAGE_NAME} - $(date '+%Y-%m-%d %H:%M:%S')" || warn "Nothing to commit" + + echo "→ Pushing to Gitea" + git push origin main || git push origin master || error "Failed to push to Git" + + log "Committed and pushed to Git" +} + +# Main logic +case "${1:-all}" in + all) + deploy_all ;; - 2) + build) build_image ;; - 3) - push_to_registry + login) + login_registry ;; - 4) - deploy_to_k3s && wait_and_verify - ;; - 5) - check_status - ;; - 6) - view_logs - ;; - 7) - test_api - ;; - 8) - restart_deployment - ;; - 9) - cleanup_all - ;; - 0) - echo -e "\n${GREEN}Goodbye!${NC}" - exit 0 - ;; - *) - print_error "無效的選擇" - ;; - esac - - echo "" - read -p "按 Enter 繼續..." - done -} - -# 檢查參數(支持直接執行步驟) -if [ $# -gt 0 ]; then - case $1 in - build) - build_image - ;; push) - push_to_registry - ;; + build_image + login_registry + push_image + ;; deploy) - deploy_to_k3s && wait_and_verify - ;; - all) - build_image && push_to_registry && deploy_to_k3s && commit_to_gitea && wait_and_verify - ;; - status) - check_status - ;; - logs) - view_logs - ;; - test) - test_api - ;; - restart) - restart_deployment - ;; - cleanup) - cleanup_all - ;; + create_namespace + create_secret + create_deployment + create_service + wait_for_deployment + ;; *) - echo "Usage: $0 [build|push|deploy|all|status|logs|test|restart|cleanup]" - echo " $0 (interactive menu)" - ;; - esac -else - main -fi + echo "Usage: ./deploy.sh [all|build|login|push|deploy]" + exit 1 + ;; +esac