본문 바로가기

React

React 프로젝트에서 GitHub Actions를 이용한 자동 배포와 버전 관리 워크플로우 설계

React 애플리케이션을 운영하면서 가장 많이 겪는 고민은 배포 과정의 일관성과 버전 관리입니다. 수동으로 빌드하고 서버에 업로드하면 실수 위험이 크고, 배포 로그가 흩어져 추적이 어려워집니다. 이번 글에서는 GitHub Actions를 활용해 CI/CD 파이프라인을 구축하고, 자동 버전 태깅까지 포함한 워크플로우를 설계하는 방법을 실무 중심으로 살펴보겠습니다.

1. 프로젝트 구조와 사전 준비

먼저, 기본적인 React 프로젝트 구조를 가정합니다. create-react-app 혹은 Vite로 생성된 프로젝트라면 별다른 설정 없이도 CI/CD를 적용할 수 있습니다.

my-react-app/
├─ .github/
│  └─ workflows/
│     └─ deploy.yml
├─ src/
├─ public/
├─ package.json
└─ README.md

필요한 사전 작업은 다음과 같습니다.

  • GitHub 레포지토리 생성 및 main 브랜치 보호 설정
  • 배포 대상 서버에 SSH 키를 생성하고, ~/.ssh/authorized_keys에 공개키를 등록
  • GitHub Secrets에 아래 항목 추가
SSH_PRIVATE_KEY   # 배포 서버 접근용 개인키
SERVER_HOST       # 예: example.com
SERVER_USER       # 배포 사용자, 보통 ubuntu 혹은 ec2-user
DEPLOY_PATH       # /var/www/my-react-app

2. GitHub Actions 워크플로우 기본 틀

다음은 가장 기본적인 배포 워크플로우 예시입니다. push 이벤트가 main 브랜치에 발생하면 자동으로 빌드하고, SSH를 통해 서버에 복사합니다.

name: Deploy React to Server

on:
  push:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

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

      - name: Install dependencies
        run: npm ci

      - name: Build project
        run: npm run build

      - name: Prepare SSH
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          ssh-keyscan -H ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts

      - name: Deploy via rsync
        run: |
          rsync -avz --delete ./build/ ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }}:${{ secrets.DEPLOY_PATH }}

위 워크플로우는 npm ci 로 의존성을 설치하고, npm run build 로 정적 파일을 생성한 뒤 rsync 로 서버에 동기화합니다.

3. 자동 버전 태깅 전략

배포와 동시에 Git 태그를 자동 생성하면 릴리즈 히스토스를 관리하기 쉬워집니다. 여기서는 semantic-release 대신 간단히 git tag 를 활용하는 방법을 소개합니다.

      - name: Determine next version
        id: version
        run: |
          # 현재 가장 최근 태그 가져오기
          git fetch --tags
          LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1` 2>/dev/null || echo "v0.0.0")
          echo "Latest tag: $LATEST_TAG"
          # npm version 명령어를 이용해 패치 버전 증가
          NEW_TAG=$(npm version patch --no-git-tag-version)
          echo "New tag: $NEW_TAG"
          echo "::set-output name=tag::$NEW_TAG"

      - name: Push new tag
        run: |
          git config user.name "github-actions"
          git config user.email "actions@github.com"
          git tag ${{ steps.version.outputs.tag }}
          git push origin ${{ steps.version.outputs.tag }}

위 단계는 현재 태그를 조회한 뒤 npm version patch 로 vX.Y.Z 형식의 새 버전을 생성하고, 이를 원격에 푸시합니다. 필요에 따라 major, minor 로 바꿀 수 있습니다.

4. 배포 전후 검증 (Optional)

자동 배포가 성공했는지 확인하려면 간단한 curl 검증을 추가합니다.

      - name: Verify deployment
        run: |
          URL="https://${{ secrets.SERVER_HOST }}"
          for i in {1..5}; do
            STATUS=$(curl -o /dev/null -s -w "%{http_code}" $URL)
            if [ "$STATUS" -eq 200 ]; then
              echo "✅ Deployment verified"
              exit 0
            fi
            echo "⏳ Waiting for app... ($i)"
            sleep 10
          done
          echo "❌ Deployment verification failed"
          exit 1

위 검증은 배포 후 5번 시도하며 200 응답을 받으면 성공으로 간주합니다.

5. 전체 워크플로우 파일

앞서 소개한 모든 파트를 하나로 합치면 아래와 같습니다.

name: CI/CD for React

on:
  push:
    branches: [main]

jobs:
  build-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm run build
      - name: Prepare SSH
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          ssh-keyscan -H ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts
      - name: Deploy via rsync
        run: |
          rsync -avz --delete ./build/ ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }}:${{ secrets.DEPLOY_PATH }}
      - name: Verify deployment
        run: |
          URL="https://${{ secrets.SERVER_HOST }}"
          for i in {1..5}; do
            STATUS=$(curl -o /dev/null -s -w "%{http_code}" $URL)
            if [ "$STATUS" -eq 200 ]; then
              echo "✅ Deployment verified"
              exit 0
            fi
            sleep 10
          done
          echo "❌ Verification failed" && exit 1
      - name: Determine next version
        id: version
        run: |
          git fetch --tags
          LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1` 2>/dev/null || echo "v0.0.0")
          echo "Latest tag: $LATEST_TAG"
          NEW_TAG=$(npm version patch --no-git-tag-version)
          echo "::set-output name=tag::$NEW_TAG"
      - name: Push new tag
        run: |
          git config user.name "github-actions"
          git config user.email "actions@github.com"
          git tag ${{ steps.version.outputs.tag }}
          git push origin ${{ steps.version.outputs.tag }}

위 파일을 .github/workflows/deploy.yml 로 저장하면, main 브랜치에 푸시될 때마다 자동으로 빌드 → 배포 → 검증 → 버전 태깅이 순차적으로 실행됩니다.

6. 마무리 팁

  • 분기별 배포: staging 브랜치를 별도 워크플로우에 연결해 사전 검증 환경을 운영합니다.
  • 환경 변수 관리: dotenv 파일은 서버에만 존재하도록 하고, GitHub Secrets 로 API 키 등을 관리합니다.
  • 배포 롤백: 이전 태그를 체크아웃하고 동일한 워크플로우를 재실행하면 손쉽게 롤백할 수 있습니다.

자동화된 CI/CD 파이프라인을 구축하면 배포 실수를 크게 줄이고, 버전 관리가 투명해집니다. 오늘 소개한 워크플로우를 기반으로 프로젝트에 맞게 커스터마이징해 보세요.