[refactor] 버튼 추가 #42
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy Discord Bot to Oracle Cloud | |
| on: | |
| push: | |
| branches: | |
| - main # main 브랜치에 푸시하면 자동 배포 | |
| workflow_dispatch: # GitHub에서 수동 실행도 가능 | |
| jobs: | |
| deploy: | |
| name: Deploy to Oracle Cloud | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup SSH | |
| run: | | |
| mkdir -p ~/.ssh | |
| echo "${{ secrets.ORACLE_SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa | |
| chmod 600 ~/.ssh/id_rsa | |
| ssh-keyscan -H ${{ secrets.ORACLE_HOST }} >> ~/.ssh/known_hosts | |
| - name: Deploy to Oracle Cloud | |
| run: | | |
| ssh -o StrictHostKeyChecking=no ${{ secrets.ORACLE_USER }}@${{ secrets.ORACLE_HOST }} << 'ENDSSH' | |
| set -e # 에러 발생 시 중단 | |
| echo "🚀 배포 시작..." | |
| # 프로젝트 디렉토리 확인 및 이동 | |
| PROJECT_DIR="$HOME/discord-bot" | |
| if [ ! -d "$PROJECT_DIR" ]; then | |
| echo "❌ 디렉토리가 없습니다: $PROJECT_DIR" | |
| echo "초기 설정이 필요합니다. 다음 명령어를 실행하세요:" | |
| echo " mkdir -p $PROJECT_DIR" | |
| echo " cd $PROJECT_DIR" | |
| echo " git clone <your-repo-url> ." | |
| exit 1 | |
| fi | |
| cd "$PROJECT_DIR" | |
| # 데이터베이스 파일 백업 (덮어쓰기 방지) - Git reset 전에 필수! | |
| DB_BACKUP_DIR="$PROJECT_DIR/db_backups" | |
| mkdir -p "$DB_BACKUP_DIR" | |
| if [ -f "bot_data.db" ]; then | |
| BACKUP_FILE="$DB_BACKUP_DIR/bot_data.db.backup.$(date +%Y%m%d_%H%M%S)" | |
| echo "💾 기존 데이터베이스 백업 중: $BACKUP_FILE" | |
| cp bot_data.db "$BACKUP_FILE" || { | |
| echo "⚠️ 데이터베이스 백업 실패, 배포 중단" | |
| exit 1 | |
| } | |
| echo "✅ 백업 완료: $(du -h "$BACKUP_FILE" | cut -f1)" | |
| else | |
| echo "ℹ️ 기존 데이터베이스 파일이 없습니다 (신규 설치)" | |
| fi | |
| # Git pull (stash를 사용하여 추적되지 않는 파일 보호) | |
| echo "📥 코드 업데이트 중..." | |
| git fetch origin main | |
| # 추적되지 않는 파일들을 임시로 stash (bot_data.db 보호) | |
| # git stash는 추적되지 않는 파일도 포함할 수 있지만, --include-untracked는 신중하게 사용 | |
| # 대신 bot_data.db를 임시 위치로 이동 | |
| TEMP_DB="/tmp/bot_data.db.$$" | |
| if [ -f "bot_data.db" ]; then | |
| echo "🛡️ 데이터베이스 파일 임시 보호 중..." | |
| mv bot_data.db "$TEMP_DB" || { | |
| echo "⚠️ 데이터베이스 파일 이동 실패, 배포 중단" | |
| exit 1 | |
| } | |
| fi | |
| # Git reset 실행 | |
| git reset --hard origin/main || { | |
| echo "⚠️ Git reset 실패, 데이터베이스 복원 시도..." | |
| if [ -f "$TEMP_DB" ]; then | |
| mv "$TEMP_DB" bot_data.db | |
| fi | |
| exit 1 | |
| } | |
| # 데이터베이스 파일 복원 | |
| if [ -f "$TEMP_DB" ]; then | |
| echo "🔄 데이터베이스 파일 복원 중..." | |
| mv "$TEMP_DB" bot_data.db || { | |
| echo "⚠️ 데이터베이스 복원 실패!" | |
| echo "💾 백업에서 복원 시도..." | |
| LATEST_BACKUP=$(ls -t "$DB_BACKUP_DIR"/bot_data.db.backup.* 2>/dev/null | head -1) | |
| if [ -n "$LATEST_BACKUP" ]; then | |
| cp "$LATEST_BACKUP" bot_data.db | |
| echo "✅ 백업에서 복원 완료" | |
| else | |
| echo "❌ 백업 파일도 없습니다!" | |
| exit 1 | |
| fi | |
| } | |
| echo "✅ 데이터베이스 파일 복원 완료" | |
| fi | |
| # 오래된 백업 파일 정리 (30일 이상 된 백업 삭제) | |
| echo "🧹 오래된 백업 파일 정리 중..." | |
| find "$DB_BACKUP_DIR" -name "bot_data.db.backup.*" -mtime +30 -delete 2>/dev/null || true | |
| # 가상환경 확인 및 생성 | |
| if [ ! -d "venv" ]; then | |
| echo "📦 가상환경 생성 중..." | |
| python3 -m venv venv | |
| fi | |
| # 가상환경 활성화 및 의존성 설치 | |
| echo "📦 의존성 설치 중..." | |
| source venv/bin/activate | |
| pip install --upgrade pip --quiet | |
| pip install -r requirements.txt --quiet | |
| # 봇 재시작 | |
| echo "🔄 봇 재시작 중..." | |
| # 기존 프로세스 모두 종료 (systemd든 직접 실행이든 상관없이) | |
| echo "🛑 기존 봇 프로세스 종료 중..." | |
| # systemd 서비스가 있으면 중지 | |
| if systemctl list-units --type=service --all | grep -q discord-bot; then | |
| sudo systemctl stop discord-bot 2>/dev/null || true | |
| echo " systemd 서비스 중지 완료" | |
| fi | |
| # 직접 실행된 프로세스 종료 | |
| PIDS=$(pgrep -f "python.*main.py" 2>/dev/null || true) | |
| if [ -n "$PIDS" ]; then | |
| echo " 직접 실행 프로세스 발견: $PIDS" | |
| echo "$PIDS" | xargs kill -TERM 2>/dev/null || true | |
| sleep 2 | |
| # 강제 종료가 필요한 경우 | |
| REMAINING=$(pgrep -f "python.*main.py" 2>/dev/null || true) | |
| if [ -n "$REMAINING" ]; then | |
| echo " 강제 종료 중..." | |
| echo "$REMAINING" | xargs kill -9 2>/dev/null || true | |
| sleep 1 | |
| fi | |
| fi | |
| # 프로세스가 완전히 종료되었는지 확인 | |
| sleep 2 | |
| REMAINING_PIDS=$(pgrep -f "python.*main.py" 2>/dev/null || true) | |
| if [ -n "$REMAINING_PIDS" ]; then | |
| echo "⚠️ 경고: 일부 프로세스가 여전히 실행 중입니다: $REMAINING_PIDS" | |
| echo " 강제 종료 시도..." | |
| echo "$REMAINING_PIDS" | xargs kill -9 2>/dev/null || true | |
| sleep 1 | |
| fi | |
| # systemd 사용하는 경우 (권장) | |
| if systemctl list-units --type=service --all | grep -q discord-bot; then | |
| echo "📦 systemd 서비스로 시작 중..." | |
| sudo systemctl start discord-bot | |
| sleep 3 | |
| if systemctl is-active --quiet discord-bot; then | |
| echo "✅ systemd로 봇 재시작 완료" | |
| # 프로세스 확인 | |
| PROC_COUNT=$(pgrep -f "python.*main.py" | wc -l) | |
| if [ "$PROC_COUNT" -eq 1 ]; then | |
| echo "✅ 단일 프로세스 실행 확인됨" | |
| else | |
| echo "⚠️ 경고: 프로세스가 $PROC_COUNT개 실행 중입니다" | |
| fi | |
| else | |
| echo "❌ 봇 재시작 실패. 로그 확인: sudo journalctl -u discord-bot -n 50" | |
| exit 1 | |
| fi | |
| else | |
| # 직접 실행하는 경우 (fallback) | |
| echo "⚠️ systemd 서비스가 없습니다. 직접 실행 모드로 전환..." | |
| # 프로세스가 완전히 종료되었는지 최종 확인 | |
| FINAL_CHECK=$(pgrep -f "python.*main.py" 2>/dev/null || true) | |
| if [ -n "$FINAL_CHECK" ]; then | |
| echo "❌ 오류: 기존 프로세스를 종료할 수 없습니다: $FINAL_CHECK" | |
| echo " 수동으로 종료 후 다시 시도하세요: kill -9 $FINAL_CHECK" | |
| exit 1 | |
| fi | |
| # 새 프로세스 시작 | |
| cd "$PROJECT_DIR" | |
| source venv/bin/activate | |
| nohup python main.py > bot.log 2>&1 & | |
| sleep 3 | |
| # 프로세스 확인 | |
| NEW_PIDS=$(pgrep -f "python.*main.py" 2>/dev/null || true) | |
| if [ -z "$NEW_PIDS" ]; then | |
| echo "❌ 봇 프로세스를 찾을 수 없습니다. 로그 확인: tail -f bot.log" | |
| exit 1 | |
| fi | |
| PROC_COUNT=$(echo "$NEW_PIDS" | wc -l) | |
| if [ "$PROC_COUNT" -eq 1 ]; then | |
| echo "✅ 봇 재시작 완료 (직접 실행, PID: $NEW_PIDS)" | |
| else | |
| echo "⚠️ 경고: 프로세스가 $PROC_COUNT개 실행 중입니다: $NEW_PIDS" | |
| echo " 로그 확인: tail -f bot.log" | |
| fi | |
| fi | |
| echo "✅ 배포 완료!" | |
| ENDSSH | |
| - name: Deployment Status | |
| run: | | |
| echo "✅ 배포가 완료되었습니다!" | |
| echo "📋 로그 확인:" | |
| echo " - systemd: ssh ${{ secrets.ORACLE_USER }}@${{ secrets.ORACLE_HOST }} 'sudo journalctl -u discord-bot -f'" | |
| echo " - 직접 실행: ssh ${{ secrets.ORACLE_USER }}@${{ secrets.ORACLE_HOST }} 'tail -f ~/discord-bot/bot.log'" | |