a2acaa70d8
Add deploy-production.sh (new): - Automated deployment to hz-prod-01 (178.104.200.7) - Service lifecycle management: systemctl stop/start quantengine - Automatic backup to /home/kjh2064/quantengine_backup - File transfer via rsync to /home/kjh2064/quantengine_active - Health checks against public URL and service status - Rollback instructions with backup restoration Update deploy-manual.sh: - Interactive deployment with user confirmation - Updated for quantengine service (not nginx) - Deployment path: /home/kjh2064/quantengine_active - Backup path: /home/kjh2064/quantengine_backup - Nginx reverse proxy structure documentation - Comprehensive rollback procedures Both scripts: - SSH connection validation (178.104.200.7) - Environment diagnostics - Comprehensive logging and error handling - Support for internal and public IP access - Pre/post deployment validation Deployment Architecture: Public: http://178.104.200.7/quant/ → Nginx (reverse proxy) → localhost:5000 (quantengine service) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
226 lines
9.1 KiB
Bash
226 lines
9.1 KiB
Bash
#!/bin/bash
|
|
# Quant Engine Production Deployment Script (v9)
|
|
# 환경: hz-prod-01, 공인IP 178.104.200.7, 내부 172.17.0.1
|
|
# 배포 경로: /home/kjh2064/quantengine_active
|
|
# Nginx 설정: /etc/nginx/sites-available/gitea-ip.conf (reverse proxy → localhost:5000)
|
|
|
|
set -e
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# 설정
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
DEPLOY_HOST="178.104.200.7"
|
|
DEPLOY_INTERNAL_IP="172.17.0.1"
|
|
DEPLOY_USER="kjh2064"
|
|
DEPLOY_PATH="/home/kjh2064/quantengine_active"
|
|
SERVICE_NAME="quantengine"
|
|
BACKUP_PATH="/home/kjh2064/quantengine_backup"
|
|
LOCAL_PUBLISH_DIR="$(pwd)/src/dotnet/QuantEngine.Web/publish"
|
|
|
|
echo "🚀 Quant Engine v9 Production Deployment"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo "Public URL: http://$DEPLOY_HOST/quant/"
|
|
echo "Internal IP: $DEPLOY_INTERNAL_IP"
|
|
echo "Deploy Path: $DEPLOY_PATH"
|
|
echo "Service: $SERVICE_NAME"
|
|
echo "Backup Path: $BACKUP_PATH"
|
|
echo "Hostname: hz-prod-01"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# Step 1: 배포 파일 준비
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
echo "📦 Step 1: 배포 파일 확인..."
|
|
|
|
if [ ! -d "$LOCAL_PUBLISH_DIR" ]; then
|
|
echo "❌ 오류: $LOCAL_PUBLISH_DIR 없음"
|
|
echo "먼저 'dotnet publish -c Release'를 실행하세요"
|
|
exit 1
|
|
fi
|
|
|
|
PACKAGE_SIZE=$(du -sh "$LOCAL_PUBLISH_DIR" | cut -f1)
|
|
FILE_COUNT=$(find "$LOCAL_PUBLISH_DIR" -type f | wc -l)
|
|
|
|
echo "✓ 배포 패키지:"
|
|
echo " 크기: $PACKAGE_SIZE"
|
|
echo " 파일 수: $FILE_COUNT"
|
|
echo ""
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# Step 2: SSH 연결 확인
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
echo "🔐 Step 2: SSH 연결 확인..."
|
|
|
|
if ! ssh -o ConnectTimeout=10 "$DEPLOY_USER@$DEPLOY_HOST" "echo '✅ SSH 연결 성공'" &>/dev/null; then
|
|
echo "❌ SSH 연결 실패"
|
|
exit 1
|
|
fi
|
|
|
|
echo "✓ SSH 연결 확인됨"
|
|
echo ""
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# Step 3: 배포 전 확인
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
echo "✅ 배포 전 확인:"
|
|
echo " [ ] Release 빌드 완료됨 ($PACKAGE_SIZE)"
|
|
echo " [ ] SSH 연결 가능"
|
|
echo ""
|
|
|
|
read -p "배포를 진행하시겠습니까? (y/n) " -n 1 -r
|
|
echo ""
|
|
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
echo "❌ 배포 취소됨"
|
|
exit 1
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# Step 4: 서비스 중지 및 백업 생성
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
echo "🛑 Step 3: 서비스 중지 및 백업 생성..."
|
|
|
|
ssh "$DEPLOY_USER@$DEPLOY_HOST" << 'EOF'
|
|
set -e
|
|
|
|
SERVICE_NAME="quantengine"
|
|
DEPLOY_PATH="/home/kjh2064/quantengine_active"
|
|
BACKUP_PATH="/home/kjh2064/quantengine_backup"
|
|
BACKUP_NAME="quantengine_$(date +%Y%m%d_%H%M%S)"
|
|
|
|
echo " 서비스 중지 중..."
|
|
sudo systemctl stop "$SERVICE_NAME" 2>/dev/null || true
|
|
sleep 2
|
|
echo " ✓ 서비스 중지 완료"
|
|
|
|
echo " 백업 생성 중..."
|
|
mkdir -p "$BACKUP_PATH"
|
|
if [ -d "$DEPLOY_PATH" ]; then
|
|
cp -r "$DEPLOY_PATH" "$BACKUP_PATH/$BACKUP_NAME"
|
|
echo " ✓ 백업 생성: $BACKUP_PATH/$BACKUP_NAME"
|
|
|
|
# 최근 5개만 유지
|
|
BACKUP_COUNT=$(ls -1 "$BACKUP_PATH" | wc -l)
|
|
if [ "$BACKUP_COUNT" -gt 5 ]; then
|
|
OLD_BACKUPS=$(ls -1t "$BACKUP_PATH" | tail -n +6)
|
|
for backup in $OLD_BACKUPS; do
|
|
rm -rf "$BACKUP_PATH/$backup"
|
|
echo " 🧹 오래된 백업 삭제: $backup"
|
|
done
|
|
fi
|
|
else
|
|
echo " ⚠️ 기존 배포 없음 (첫 배포)"
|
|
mkdir -p "$DEPLOY_PATH"
|
|
fi
|
|
EOF
|
|
|
|
echo ""
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# Step 5: 파일 전송
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
echo "📤 Step 4: 파일 전송 (rsync)..."
|
|
|
|
rsync -avz --delete \
|
|
--rsh="ssh" \
|
|
"$LOCAL_PUBLISH_DIR/" \
|
|
"$DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_PATH/"
|
|
|
|
echo "✓ 파일 전송 완료"
|
|
echo ""
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# Step 6: 서비스 시작
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
echo "🚀 Step 5: 서비스 시작..."
|
|
|
|
ssh "$DEPLOY_USER@$DEPLOY_HOST" << 'EOF'
|
|
set -e
|
|
|
|
SERVICE_NAME="quantengine"
|
|
DEPLOY_PATH="/home/kjh2064/quantengine_active"
|
|
|
|
echo " 파일 검증 중..."
|
|
if [ -f "$DEPLOY_PATH/QuantEngine.Web.dll" ]; then
|
|
echo " ✓ QuantEngine.Web.dll 확인됨"
|
|
else
|
|
echo " ❌ QuantEngine.Web.dll 없음 (배포 실패)"
|
|
exit 1
|
|
fi
|
|
|
|
echo " 서비스 시작 중..."
|
|
sudo systemctl start "$SERVICE_NAME"
|
|
sleep 3
|
|
|
|
if sudo systemctl is-active --quiet "$SERVICE_NAME"; then
|
|
echo " ✓ $SERVICE_NAME 시작 완료"
|
|
else
|
|
echo " ❌ $SERVICE_NAME 시작 실패"
|
|
sudo systemctl status "$SERVICE_NAME" || true
|
|
exit 1
|
|
fi
|
|
EOF
|
|
|
|
echo ""
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# Step 7: 헬스 체크
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
echo "🧪 Step 6: 헬스 체크..."
|
|
|
|
for i in {1..30}; do
|
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
|
|
"http://$DEPLOY_HOST/quant/" 2>/dev/null || echo "000")
|
|
|
|
if [ "$HTTP_CODE" = "200" ]; then
|
|
echo "✓ Health check PASS (HTTP 200)"
|
|
break
|
|
fi
|
|
|
|
echo " 시도 $i/30: HTTP $HTTP_CODE (대기 중...)"
|
|
sleep 2
|
|
done
|
|
|
|
echo ""
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# 배포 완료
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo "✅ 배포 완료!"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
echo "📊 배포 정보:"
|
|
echo " 공인 URL: http://$DEPLOY_HOST/quant/"
|
|
echo " 내부 IP: $DEPLOY_INTERNAL_IP"
|
|
echo " 배포 경로: $DEPLOY_PATH"
|
|
echo " 서비스: $SERVICE_NAME"
|
|
echo " 백업: $BACKUP_PATH"
|
|
echo ""
|
|
echo "🔍 로그 확인:"
|
|
echo " ssh $DEPLOY_USER@$DEPLOY_HOST 'sudo journalctl -u $SERVICE_NAME -f'"
|
|
echo ""
|
|
echo "🔄 롤백 (필요시):"
|
|
echo " ssh $DEPLOY_USER@$DEPLOY_HOST << 'ROLLBACK'"
|
|
echo " LATEST=\$(ls -t $BACKUP_PATH | head -1)"
|
|
echo " cp -r $BACKUP_PATH/\$LATEST/* $DEPLOY_PATH/"
|
|
echo " sudo systemctl restart $SERVICE_NAME"
|
|
echo " ROLLBACK"
|
|
echo ""
|
|
echo "🌐 Nginx 역방향 프록시 구조:"
|
|
echo " 공인 IP:178.104.200.7/quant/ → localhost:5000 (Nginx reverse proxy)"
|
|
echo " Nginx 설정: /etc/nginx/sites-available/gitea-ip.conf"
|
|
echo ""
|