name: Deploy KCG on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # ═══ Frontend ═══ - name: Configure npm registry run: | echo "registry=https://nexus.gc-si.dev/repository/npm-public/" > frontend/.npmrc echo "//nexus.gc-si.dev/repository/npm-public/:_auth=${{ secrets.NEXUS_NPM_AUTH }}" >> frontend/.npmrc - name: Build frontend working-directory: frontend env: VITE_GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }} run: | npm ci npx vite build - name: Deploy frontend run: | rm -rf /deploy/kcg/* cp -r frontend/dist/* /deploy/kcg/ echo "Frontend deployed at $(date '+%Y-%m-%d %H:%M:%S')" # ═══ Backend ═══ - name: Install JDK 21 + Maven run: | apt-get update -qq apt-get install -y -qq wget apt-transport-https gpg maven openssh-client > /dev/null 2>&1 wget -qO - https://packages.adoptium.net/artifactory/api/gpg/key/public | gpg --dearmor -o /usr/share/keyrings/adoptium.gpg echo "deb [signed-by=/usr/share/keyrings/adoptium.gpg] https://packages.adoptium.net/artifactory/deb bookworm main" > /etc/apt/sources.list.d/adoptium.list apt-get update -qq apt-get install -y -qq temurin-21-jdk > /dev/null 2>&1 echo "JAVA_HOME=/usr/lib/jvm/temurin-21-jdk-amd64" >> $GITHUB_ENV echo "/usr/lib/jvm/temurin-21-jdk-amd64/bin" >> $GITHUB_PATH /usr/lib/jvm/temurin-21-jdk-amd64/bin/java -version mvn --version - name: Build backend working-directory: backend run: mvn -B clean package -DskipTests - name: Deploy backend files env: GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }} JWT_SECRET: ${{ secrets.JWT_SECRET }} DB_PASSWORD: ${{ secrets.DB_PASSWORD }} OPENSKY_CLIENT_ID: ${{ secrets.OPENSKY_CLIENT_ID }} OPENSKY_CLIENT_SECRET: ${{ secrets.OPENSKY_CLIENT_SECRET }} run: | DEPLOY_DIR=/deploy/kcg-backend mkdir -p $DEPLOY_DIR/backup # JAR 백업 (최근 5개 유지) if [ -f $DEPLOY_DIR/kcg.jar ]; then cp $DEPLOY_DIR/kcg.jar $DEPLOY_DIR/backup/kcg-$(date +%Y%m%d%H%M%S).jar ls -t $DEPLOY_DIR/backup/*.jar | tail -n +6 | xargs -r rm fi # Secrets → 환경변수 파일 : > $DEPLOY_DIR/.env [ -n "$GOOGLE_CLIENT_ID" ] && echo "GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}" >> $DEPLOY_DIR/.env [ -n "$JWT_SECRET" ] && echo "JWT_SECRET=${JWT_SECRET}" >> $DEPLOY_DIR/.env [ -n "$DB_PASSWORD" ] && echo "DB_PASSWORD=${DB_PASSWORD}" >> $DEPLOY_DIR/.env [ -n "$OPENSKY_CLIENT_ID" ] && echo "OPENSKY_CLIENT_ID=${OPENSKY_CLIENT_ID}" >> $DEPLOY_DIR/.env [ -n "$OPENSKY_CLIENT_SECRET" ] && echo "OPENSKY_CLIENT_SECRET=${OPENSKY_CLIENT_SECRET}" >> $DEPLOY_DIR/.env echo "PREDICTION_BASE_URL=http://192.168.1.18:8001" >> $DEPLOY_DIR/.env # JAR 내부에 application-prod.yml이 있으면 외부 파일 제거 if unzip -l backend/target/kcg.jar | grep -q 'application-prod.yml$'; then rm -f $DEPLOY_DIR/application-prod.yml echo "JAR 내부 application-prod.yml 감지 → 외부 파일 제거" fi # systemd 서비스 파일 배포 cp deploy/kcg-backend.service $DEPLOY_DIR/kcg-backend.service # JAR 교체 cp backend/target/kcg.jar $DEPLOY_DIR/kcg.jar echo "Backend files deployed at $(date '+%Y-%m-%d %H:%M:%S')" - name: Restart backend via SSH env: DEPLOY_KEY: ${{ secrets.DEPLOY_SSH_KEY }} DEPLOY_HOST: 192.168.1.20 run: | mkdir -p ~/.ssh printf '%s\n' "$DEPLOY_KEY" > ~/.ssh/id_deploy chmod 600 ~/.ssh/id_deploy ssh-keyscan -T 5 $DEPLOY_HOST >> ~/.ssh/known_hosts 2>/dev/null || true SSH_OPTS="-i ~/.ssh/id_deploy -o StrictHostKeyChecking=no -o ConnectTimeout=10 -o ServerAliveInterval=15" # 재시작 스크립트를 SCP로 업로드 후 SSH로 실행 (각각 재시도) cat > /tmp/restart-kcg.sh << 'SCRIPT' #!/bin/bash DEPLOY_DIR=/devdata/services/kcg/backend SYSTEMD_DIR=/etc/systemd/system if [ -f "$DEPLOY_DIR/kcg-backend.service" ] && ! diff -q "$DEPLOY_DIR/kcg-backend.service" "$SYSTEMD_DIR/kcg-backend.service" >/dev/null 2>&1; then cp "$DEPLOY_DIR/kcg-backend.service" "$SYSTEMD_DIR/kcg-backend.service" systemctl daemon-reload fi echo "--- Restarting kcg-backend ---" systemctl restart kcg-backend for i in $(seq 1 60); do HTTP=$(curl -s -o /dev/null -w '%{http_code}' http://localhost:8080/api/aircraft 2>/dev/null || echo "000") if [ "$HTTP" = "200" ] || [ "$HTTP" = "401" ] || [ "$HTTP" = "403" ]; then echo "Backend started successfully (${i}s, HTTP $HTTP)" exit 0 fi sleep 1 done echo "WARNING: Startup timeout" journalctl -u kcg-backend --no-pager -n 10 exit 1 SCRIPT # SCP 업로드 (최대 3회 재시도) for attempt in 1 2 3; do echo "SCP upload attempt $attempt/3..." if scp $SSH_OPTS /tmp/restart-kcg.sh root@$DEPLOY_HOST:/tmp/restart-kcg.sh; then break fi [ "$attempt" -eq 3 ] && { echo "ERROR: SCP failed after 3 attempts"; exit 1; } sleep 10 done # SSH 실행 (최대 3회 재시도) for attempt in 1 2 3; do echo "SSH execute attempt $attempt/3..." if ssh $SSH_OPTS root@$DEPLOY_HOST "bash /tmp/restart-kcg.sh && rm -f /tmp/restart-kcg.sh"; then exit 0 fi SSH_EXIT=$? [ "$attempt" -eq 3 ] && { echo "ERROR: SSH failed after 3 attempts (exit $SSH_EXIT)"; exit 1; } echo "SSH failed (exit $SSH_EXIT), retrying in 10s..." sleep 10 done # ═══ Prediction (FastAPI) — CI/CD 제외, 수동 배포 ═══ # ssh redis-211 에서 수동 배포: # scp prediction/*.py redis-211:/home/apps/kcg-prediction/ # ssh redis-211 "sudo systemctl restart kcg-prediction" - name: Cleanup if: always() run: rm -f ~/.ssh/id_deploy