티스토리 뷰

반응형

GitHub Actions로 완전 자동화된 NestJS 배포 파이프라인 구축하기

(Blue-Green, Prisma Migrate, Slack 알림까지 원클릭 배포 완성)


이제 우리가 만든 NestJS + Prisma + Redis + PM2 백엔드
로컬과 서버 모두에서 완벽히 작동한다.

하지만 진짜 서비스 운영에서 더 중요한 건 “배포 자동화”다.
매번 서버에 SSH 접속해서 git pull → docker compose up 하는 건 100% 사고 난다.

이번 편에서는 GitHub Actions를 이용해
코드 푸시 → 빌드 → 마이그레이션 → 배포 → 프록시 전환 → 알림까지
한 번의 push로 자동화하는 방법을 단계별로 정리한다.


🧭 목표

단계 내용

1️⃣ main 브랜치 push 시 Actions 자동 트리거
2️⃣ 서버에 SSH 접속 후 Docker Compose 빌드/교체
3️⃣ Prisma 마이그레이션 자동 실행
4️⃣ Blue-Green 방식으로 무중단 전환
5️⃣ Slack/Discord 알림 발송

1️⃣ 서버 구조 복습

/srv/nest-app/
├── blue/
│   ├── docker-compose.yml  (port 3001)
│   ├── Dockerfile
│   └── ecosystem.config.js
└── green/
    ├── docker-compose.yml  (port 3002)
    ├── Dockerfile
    └── ecosystem.config.js

Nginx는 이전 글에서 본 것처럼 upstream을
현재 포트를 기준으로 Blue ↔ Green 으로 번갈아 연결한다.


2️⃣ GitHub Secrets 설정

이름 설명

SERVER_IP 서버 IP
SERVER_USER ubuntu 또는 ec2-user
SERVER_SSH_KEY 개인 SSH 키 (id_rsa 내용)
SLACK_WEBHOOK 슬랙 알림용 Webhook URL
DEPLOY_PATH 예: /srv/nest-app

3️⃣ GitHub Actions Workflow 작성

반응형

.github/workflows/deploy.yml

name: 🚀 NestJS Blue-Green Deploy

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

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

      - name: 🔑 Connect & Deploy via SSH
        uses: appleboy/ssh-action@v1.1.0
        with:
          host: ${{ secrets.SERVER_IP }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SERVER_SSH_KEY }}
          script: |
            cd ${{ secrets.DEPLOY_PATH }}

            echo "🌀 현재 실행중인 버전 확인..."
            ACTIVE=$(docker ps --format '{{.Ports}}' | grep 3001 || true)

            if [ -n "$ACTIVE" ]; then
              echo "🟩 Blue(3001)가 활성 → Green(3002)로 배포"
              TARGET="green"
              OLD="blue"
              PORT=3002
            else
              echo "🟦 Green(3002)가 활성 → Blue(3001)로 배포"
              TARGET="blue"
              OLD="green"
              PORT=3001
            fi

            cd $TARGET
            echo "📦 이미지 빌드 중..."
            docker compose build

            echo "🗃 Prisma 마이그레이션 실행..."
            docker compose run --rm migrate

            echo "🚀 새 컨테이너 시작..."
            docker compose up -d

            echo "🔁 Nginx 프록시 전환..."
            sudo sed -i "s/3001/3002/g" /etc/nginx/conf.d/app.conf || true
            sudo sed -i "s/3002/3001/g" /etc/nginx/conf.d/app.conf || true
            sudo nginx -t && sudo systemctl reload nginx

            echo "🧹 이전 버전 종료..."
            cd ../$OLD && docker compose down

            echo "✅ 배포 완료!"

4️⃣ Slack 알림 추가

같은 workflow에 추가 👇

      - name: 📨 Slack Notification
        if: always()
        uses: rtCamp/action-slack-notify@v2
        env:
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
          SLACK_COLOR: ${{ job.status }}
          SLACK_TITLE: "NestJS Blue-Green 배포 완료"
          SLACK_MESSAGE: |
            *브랜치:* main  
            *상태:* ${{ job.status }}  
            *서버:* ${{ secrets.SERVER_IP }}
            *시간:* $(date)

결과 👉

✅ NestJS Blue-Green 배포 완료
Branch: main
Server: 13.124.xxx.xxx
Time: 2025-11-17 16:23


5️⃣ Prisma 마이그레이션 자동화 주의점

Prisma는 schema.prisma 변경 시 migrate deploy가 필요하다.
이를 migrate 서비스로 분리하는 게 핵심이다.

docker-compose.yml 예시:

services:
  migrate:
    build: .
    command: ["npx", "prisma", "migrate", "deploy"]
    depends_on:
      mysql:
        condition: service_healthy
    restart: "no"

GitHub Actions 스크립트에서
docker compose run --rm migrate 명령으로 자동 실행되게 했다.


6️⃣ Nginx 프록시 자동 전환 스크립트 (서버 내부)

/etc/nginx/conf.d/app.conf

upstream nest_backend {
    server 127.0.0.1:3001;
    server 127.0.0.1:3002 backup;
}

server {
    listen 80;
    server_name myapp.example.com;

    location / {
        proxy_pass http://nest_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

배포 시 sed 명령어가 3001 ↔ 3002를 교체하고
nginx reload로 트래픽을 새로운 버전으로 넘긴다.


7️⃣ Blue-Green Health Check 로직

배포 후 5초 간격으로 새 버전 헬스체크를 수행하면
완벽한 무중단 전환이 가능하다.

for i in {1..10}; do
  STATUS=$(curl -s http://localhost:$PORT/healthz | jq -r '.status')
  if [ "$STATUS" == "ok" ]; then
    echo "🟢 새 버전 정상 구동"
    break
  fi
  echo "⏳ 서버 기동 중..."
  sleep 5
done

배포 실패 시 Slack에 “❌ 배포 실패” 메시지를 보낼 수도 있다.


8️⃣ 전체 파이프라인 흐름

[ Developer ]
    ↓  push main
[ GitHub Actions ]
    ↓
[ SSH: Server 접속 ]
    ↓
[ Docker Build (blue/green) ]
    ↓
[ Prisma migrate deploy ]
    ↓
[ Nginx proxy switch ]
    ↓
[ Slack 알림 ]

✅ 결과 정리

단계 자동화 여부

코드 푸시 트리거
빌드/배포
DB 마이그레이션
무중단 프록시 전환
알림 전송
이전 버전 정리

🔮 다음 예고

이제 진짜 완성이다.
다음 편에서는 AWS / Cloudflare / Vercel Edge 연결편으로,
프록시 서버 + CDN + HTTPS + 로드밸런서까지 통합하는 실전 운영 레벨로 들어간다.

"로컬 → 테스트 → 운영 → 클라우드 오케스트레이션"
이 모든 과정을 하나의 자동화된 백엔드 배포 체인으로 완성할 것이다.


 

NestJS, GitHubActions, CI/CD, BlueGreen, Prisma, PM2, Docker, Nginx, SlackWebhook, DevOps, 백엔드자동배포


 

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/01   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함
반응형