별책부록 9편
별책부록 9편
GitHub Actions 자동 배포
git push 한 번으로 서버 자동 배포 · pm2 reload · 롤백
📑 이 챕터에서 다룰 내용

코드를 수정할 때마다 SSH 접속 → git pullnpm buildpm2 restart를 매번 반복하면 금방 지칩니다. GitHub Actions를 설정해두면 git push 한 번으로 이 모든 과정이 자동으로 완료됩니다. 1탄 v2 메타 원칙 "R4 자동 회복"의 봇 적용이에요.

📘 9편 핵심 목표
  • 예상 시간: 1시간
  • GitHub repository 초기화 + .env 보호
  • SSH deploy 키 설정 (read-only + push 분리)
  • GitHub Actions workflow — Node.js·Python 봇
  • pm2 reload 무중단 배포
  • 5분 롤백 시나리오
8-1 GitHub Repository 준비 🔗

먼저 봇 코드를 GitHub에 올립니다. private repository 권장이에요. .env가 절대 push되지 않도록 반드시 확인하세요.

💻 코드 푸시
cd ~/tsv-bot
git init
git add .
git commit -m "Initial commit"

# GitHub 새 repo 생성 (private 권장)
git remote add origin git@github.com:junho/tsv-bot.git
git branch -M main
git push -u origin main
⚠️ Secret 노출 금지 — 절대 지켜야 할 규칙
  • .env 절대 push 금지 — .gitignore에 반드시 포함
  • 만약 실수로 push했다면 즉시:
  1. Discord 토큰 reset
  2. Anthropic API 키 revoke + 재발급
  3. git history 정리 (BFG 또는 git filter-repo 사용)
8-2 SSH deploy 키 설정 🔗

GitHub Actions가 서버에 SSH 접속해서 배포하려면 전용 키가 필요해요. deploy 용 키와 GitHub Actions용 키를 분리해서 권한을 최소화합니다.

💻 서버에서 deploy 전용 SSH 키 생성
# 서버에서 deploy 전용 ssh 키 생성
ssh-keygen -t ed25519 -C "github-deploy@tsv-bot" -f ~/.ssh/deploy_key -N ""

# 공개키 GitHub에 등록
cat ~/.ssh/deploy_key.pub
# → GitHub Repo Settings → Deploy keys → Add deploy key
# → Title: "TSV Bot Server", Allow write access X (read-only)

# 서버 ~/.ssh/config 설정
cat >> ~/.ssh/config << 'EOF'

Host github.com-tsv-bot
  HostName github.com
  User git
  IdentityFile ~/.ssh/deploy_key
EOF

# 테스트
ssh -T github.com-tsv-bot
# Hi junho/tsv-bot! You've successfully authenticated.

# clone path 변경
cd ~
mv tsv-bot tsv-bot-old
git clone git@github.com-tsv-bot:junho/tsv-bot.git
cd tsv-bot

# .env 복사 (push X)
cp ../tsv-bot-old/.env .
chmod 600 .env

# logs 복사 (선택)
cp -r ../tsv-bot-old/logs .

# 빌드 + 재시작
npm install
npm run build
pm2 restart tsv-discord-bot
8-3 GitHub Actions secret + workflow 🔗

Repository Secret 등록

📘 GitHub Repo Settings → Secrets and variables → Actions
  • SSH_HOST: 144.24.123.45 (서버 Public IP)
  • SSH_USER: ubuntu
  • SSH_PRIVATE_KEY: GitHub Actions용 별도 개인키 내용
  • SSH_PORT: 22

deploy 키 재생성 (push 권한 분리)

GitHub Actions runner가 서버에 SSH 접속할 때 사용할 별도 키를 만들어요. deploy 키(read-only)와 분리해서 권한을 최소화합니다.

💻 GitHub Actions용 SSH 키 생성 + authorized_keys 등록
# 로컬 (또는 GitHub Actions runner)용 별도 키
# 서버에서 생성 → 공개키 ~/.ssh/authorized_keys에 추가 → 개인키 GitHub Secret
ssh-keygen -t ed25519 -C "github-actions" -f ~/.ssh/gha_key -N ""
cat ~/.ssh/gha_key.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

# 개인키 보기 → GitHub Secret 등록
cat ~/.ssh/gha_key
# 전체 내용을 GitHub Secret SSH_PRIVATE_KEY로 등록

.github/workflows/deploy.yml

💻 .github/workflows/deploy.yml — Node.js 봇 배포 workflow
# .github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '22'

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build

      - name: Setup SSH
        uses: webfactory/ssh-agent@v0.9.0
        with:
          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

      - name: Add server to known_hosts
        run: |
          mkdir -p ~/.ssh
          ssh-keyscan -p ${{ secrets.SSH_PORT }} \
            ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts

      - name: Deploy to server
        run: |
          ssh -p ${{ secrets.SSH_PORT }} \
            ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} \
            'cd ~/tsv-bot && \
             git pull origin main && \
             npm ci && \
             npm run build && \
             pm2 reload tsv-discord-bot && \
             echo "✅ Deploy completed"'

      - name: Notify Discord
        if: success()
        run: |
          curl -H "Content-Type: application/json" \
            -d '{"content":"✅ TSV 디스코드 봇 배포 완료 — '"$(date +%Y-%m-%d_%H:%M)"'"}' \
            ${{ secrets.DISCORD_DEPLOY_WEBHOOK }}
💡 workflow_dispatch 를 꼭 추가하세요

workflow_dispatch를 추가하면 GitHub Actions 탭에서 수동으로 배포를 트리거할 수 있어요. 긴급 배포나 테스트할 때 유용합니다.

8-4 Python 봇 deploy workflow 🔗

Telegram 봇(Python)도 별도 workflow 파일을 만들어요. src/** 또는 requirements.txt가 변경될 때만 배포합니다.

💻 .github/workflows/deploy-tg.yml — Python 봇 배포 workflow
# .github/workflows/deploy-tg.yml
name: Deploy Telegram Bot

on:
  push:
    branches: [main]
    paths:
      - 'src/**'
      - 'requirements.txt'
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup SSH
        uses: webfactory/ssh-agent@v0.9.0
        with:
          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

      - name: Add server to known_hosts
        run: |
          mkdir -p ~/.ssh
          ssh-keyscan ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts

      - name: Deploy
        run: |
          ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} \
            'cd ~/tsv-tg-bot && \
             git pull origin main && \
             source .venv/bin/activate && \
             uv pip install -r requirements.txt && \
             sudo systemctl restart tsv-tg-bot && \
             echo "✅ Telegram bot deployed"'
8-5 무중단 배포 — pm2 reload 🔗
💻 pm2 restart vs pm2 reload 차이
# pm2 restart vs pm2 reload
# - restart: 봇 종료 후 재시작 (몇 초간 중단)
# - reload: 새 프로세스 시작 후 기존 종료 (무중단)

# pm2 reload tsv-discord-bot
# → cluster mode에서만 진정한 무중단
# → fork mode는 reload ≈ restart

# 봇은 connection 유지가 핵심 → reload가 최소 영향

systemd reload (Python)

💻 systemd — 무중단 재시작
# systemd reload — 자동 재시작 + Restart=always 효과
sudo systemctl reload-or-restart tsv-tg-bot

# 또는 graceful restart 봇 코드 안에서:
# - SIGTERM 받으면 현재 요청 끝낸 후 종료
# - python-telegram-bot 자체가 graceful shutdown 지원
💡 pm2 cluster mode로 진정한 무중단 배포

pm2를 cluster mode로 실행하면 pm2 reload가 진정한 무중단으로 동작해요. 기존 연결을 처리하는 동안 새 프로세스가 올라오고, 완료 후 기존 프로세스가 종료됩니다.

Discord 봇 특성상 WebSocket 재연결이 발생하지만, 사용자 입장에서는 거의 알아채지 못하는 수준이에요.

8-6 롤백 시나리오 🔗

배포 후 봇이 작동하지 않으면 5분 안에 이전 상태로 복구할 수 있어야 합니다.

💻 빠른 롤백 — 이전 커밋으로 복구
# 배포 후 봇 작동 X 시 빠른 롤백

# 1. 이전 커밋으로 되돌리기
ssh ubuntu@your-ip
cd ~/tsv-bot
git log --oneline -5  # 이전 커밋 확인
git checkout <prev-commit-hash>

# 2. 빌드 + 재시작
npm ci
npm run build
pm2 reload tsv-discord-bot

# 3. 작동 확인 후 origin에 force push (긴급 시만)
# 또는 새 정정 commit 푸시 (권장)
⚠️ force push는 긴급 상황에만 사용하세요

git push --force는 팀원이 있거나 이미 배포된 이력이 있을 때 문제를 일으킬 수 있어요.

가능하면 새 정정 commit을 만들어서 정상적으로 push하는 방식을 권장합니다. LogOnTable에 배포 시점과 문제를 트레이스해두세요.

8-7 배포 흐름 — 시리즈 메타 일관 🔗

배포는 단순한 명령어 실행이 아니에요. 시리즈 메타 원칙 R4 안전 의식을 배포 흐름에도 적용합니다.

📘 배포 흐름 — R4 안전 의식 5단계
1
로컬 검증
npm run build 오류 없음 확인 → npm test (있으면) → 봇 로컬 작동 검증
2
git push
의식적 commit message 작성 → 단일 책임 commit
3
GitHub Actions 자동
빌드 + ssh deploy + reload → 디스코드 webhook 알림 수신
4
배포 후 검증
봇 응답 테스트 (!ask 안녕) → Sentry 에러 없음 확인 → 매일 리포트 cron 작동 확인
5
문제 시 롤백
5분 안에 이전 commit으로 복구 → LogOnTable 트레이스 (배포 시점 + 문제 기록)
📌 9편 정리
  • 1️⃣ GitHub repo: private repo + .env 절대 push 금지 + .gitignore 일관
  • 2️⃣ SSH 키 분리: deploy 키 (read-only) + GitHub Actions 키 (authorized_keys) 권한 분리
  • 3️⃣ Node.js workflow: push → checkout → build → ssh deploy → pm2 reload → Discord 알림
  • 4️⃣ Python workflow: src·requirements.txt 변경 시만 배포 → systemctl restart
  • 5️⃣ pm2 reload: restart보다 최소 중단 — cluster mode에서 진정한 무중단
  • 6️⃣ 롤백: git checkout + rebuild + reload — 5분 안에 복구 가능
  • 7️⃣ 메타 일관: R4 자동 회복 → 자동 배포 + 자동 재시작 / E1 다층 보호 → secret + deploy 키 분리
🎉 별책부록 완주 — 운영 상태 총정리

이 별책부록 9편을 마친 여러분께 축하드립니다. 아래가 지금 여러분의 운영 상태입니다.

[인프라]

  • Oracle Cloud Singapore Always Free (월 $0)
  • Ampere A1: 4 OCPU + 24GB RAM
  • Ubuntu 24.04 + 보안 6단계 (ssh·ufw·fail2ban·자동 업데이트·swap·idle 보호)

[봇]

  • Node.js 디스코드 봇: pm2 + Position C 5차원
  • Python Telegram 봇: systemd + Position C 5차원
  • 두 봇 동시 운영 + SSH 종료해도 봇이 계속 살아있는 환경

[모니터링]

  • Sentry (에러 자동 추적)
  • Anthropic API 사용량 추적 (LogOnTable)
  • 매일 운영 리포트 (cron 09:30 KST)
  • 사용자 cooldown 5초

[배포]

  • GitHub Actions 자동 deploy
  • pm2 reload + systemctl restart 무중단
  • 5분 롤백 가능

[비용]

  • Oracle Cloud: $0/월
  • Anthropic API: 사용량만큼 (~$5~30/월 추정)
  • Sentry: $0/월 (무료 5K events)
  • 도메인 (선택): $10/년
  • 합계: ~$5~30/월 (사용량에 따라)

[시리즈 메타 원칙 일관 달성]

  • Position C 5차원 (footer + system prompt + 자동 검출 user + 자동 검출 response + /about·/terms·/privacy)
  • E4 LogOnTable 4요소 (timestamp·user·question·status)
  • E5 환각 방지 + 자동 검출
  • E2 Day 0 시스템 (자동 재시작 + 부팅 자동 시작 + SSH 종료 영향 없음)
  • R4 자동 회복 → 봇 자동 배포 + 자동 재시작

이 별책부록도 "끝점"이 아니라 "시작점"입니다. 디스코드·Telegram 봇 인프라가 갖춰진 지금부터 TSV·AlbaFlow·viewLab 등 모든 1인 운영 프로젝트에 봇을 적용할 수 있어요. Phase 3 (다국어·6 페르소나·모바일 앱) 진입 시 봇도 함께 진화합니다.

페이지를 넘기시지요. 이제는 운영자가 아닌 봇이 함께 작동하는 환경에서 만나뵙겠습니다.

📘
별책부록 도우미
질문하기 OK
안녕하세요! GitHub Actions 자동 배포 설정에 대해 무엇이든 물어보세요. 본문에서 찾아 답변해드릴게요. 👇