GitHub Actions로 CI/CD 파이프라인 구축하기

Alpacon GitHub Actions를 이용한 단계별 CI/CD 파이프라인 구축 튜토리얼입니다.

학습 목표

이 튜토리얼을 완료하면 다음을 할 수 있습니다:

  • SSH 키 없이 안전한 배포 파이프라인 구축
  • 명령어 수준의 세밀한 권한 제어
  • 자동화된 빌드 및 배포 프로세스 구현

사전 준비사항

Step 1: 서비스 토큰 생성 (5분 + 승인 대기)

1-1. 서비스 토큰 생성

CI와 자동화는 서비스 토큰으로 동작합니다. 서비스 토큰은 사람이 아니라 Application에 속하기 때문에 담당자가 바뀌어도 그대로 유지되며, 파이프라인이 무엇까지 할 수 있는지는 ACL이 정확히 정합니다.

  1. Alpacon 워크스페이스에 로그인
  2. IAM → Applications에서 이 파이프라인이 속한 Application 열기 또는 새로 생성
  3. 자격 증명 탭에서 추가 클릭

양식에서 다음을 설정합니다:

Token name: github-actions-deploy
Expiration: 3 months (권장)
Scopes: 배포에 필요한 범위 선택
Reason: 이 파이프라인에 토큰이 필요한 이유

표시된 키를 복사하세요. alpst-로 시작하며 한 번만 표시됩니다.

CI 범위로 만든 토큰은 검토를 거쳐야 동작합니다. 요청은 대기중(pending) 상태로 생성되고 승인 권한이 있는 사람이 활성화하기 전까지는 어디에도 인증되지 않습니다. 파이프라인 도중에 발견하지 않도록 이 단계를 미리 감안하세요.

1-2. ACL 규칙 추가

새 서비스 토큰은 ACL 규칙을 추가하기 전까지 아무 곳에도 닿지 못합니다. 서버, 명령, 파일 경로가 각각 기본 거부이므로 규칙이 하나도 없는 토큰은 어디서든 거부됩니다.

토큰을 열고 ACL 탭에서 다음을 추가하세요.

규칙이 파이프라인에 필요한 항목
Server ACLprod-server
Command ACL아래 명령 패턴
File ACL빌드 결과물을 올릴 /var/www/app/dist/

Command ACL 항목은 각각 하나의 명령 패턴이며(와일드카드 * 지원), 한 항목에 하나씩 입력합니다:

git *
npm *
pm2 *
curl *
systemctl status nginx

파일 전송은 서버 규칙을 먼저 확인한 다음 파일 규칙을 확인합니다. 따라서 Upload to server 단계에는 둘 중 하나가 아니라 Server ACL 항목과 File ACL 항목이 모두 필요합니다.

💡 팁: 개발과 프로덕션용 토큰을 분리하여 관리하세요.

1-3. 토큰 활성화 확인

토큰의 개요 탭에서 상태가 더 이상 대기중이 아닌지 확인하세요. 대기중인 토큰은 어디에도 인증되지 않으므로 그 상태로 만든 파이프라인은 첫 Alpacon 단계에서 실패합니다.

Step 2: GitHub 저장소 설정 (3분)

2-1. GitHub Secrets 추가

GitHub 저장소에서:

  1. Settings > Secrets and variables > Actions 이동
  2. New repository secret 클릭
  3. 다음 시크릿 추가:
NameValue
ALPACON_WORKSPACE_URLhttps://your-workspace.ap1.alpacon.io
ALPACON_SERVICE_TOKENStep 1에서 복사한 alpst- 키

아래 액션의 입력값 이름은 api-token이며 서비스 토큰을 그대로 받습니다. 이미 배포된 워크플로우와의 호환을 위해 이름은 그대로 둡니다.

2-2. 워크플로우 파일 생성

저장소 루트에 .github/workflows 디렉터리 생성 후:

.github/workflows/deploy.yml:

name: Deploy to Production
 
on:
  push:
    branches: [main]
 
env:
  NODE_VERSION: '18'
 
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
 
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ env.NODE_VERSION }}
        cache: 'npm'
 
    - name: Install dependencies
      run: npm ci
 
    - name: Run tests
      run: npm test
 
    - name: Build application
      run: npm run build
 
    # 빌드 결과물을 아티팩트로 저장
    - name: Upload build artifacts
      uses: actions/upload-artifact@v4
      with:
        name: build-artifacts
        path: dist/
 
  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
 
    steps:
    # 빌드 아티팩트 다운로드
    - name: Download artifacts
      uses: actions/download-artifact@v4
      with:
        name: build-artifacts
        path: dist/
 
    # Alpacon CLI 설치
    - name: Setup Alpacon CLI
      uses: alpacax/alpacon-setup-action@v1
 
    # 빌드 결과물을 서버로 전송
    - name: Upload to server
      uses: alpacax/alpacon-cp-action@v1
      with:
        workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
        api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
        source: './dist/'
        target-server: 'prod-server'
        target-path: '/var/www/app/dist/'
        recursive: true
 
    # 애플리케이션 재시작
    - name: Restart application
      uses: alpacax/alpacon-websh-action@v1
      with:
        workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
        api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
        target: 'prod-server'
        script: |
          pm2 restart app
          pm2 status
 
    # 헬스 체크
    - name: Health check
      uses: alpacax/alpacon-websh-action@v1
      with:
        workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
        api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
        target: 'prod-server'
        script: |
          curl -f http://localhost:3000/health || exit 1

Step 3: 첫 배포 실행 (2분)

3-1. 코드 푸시

git add .github/workflows/deploy.yml
git commit -m "Add CI/CD pipeline with Alpacon"
git push origin main

3-2. 배포 모니터링

  1. GitHub 저장소의 Actions 탭 이동
  2. 실행 중인 워크플로우 클릭
  3. 각 단계별 로그 확인

3-3. Alpacon에서 확인

  1. Alpacon 워크스페이스의 Audit > Events 열기
  2. Commands 탭에서 실행된 명령어와 결과 확인. 토큰을 소유한 Application 이름으로 기록됨
  3. 토큰의 개요 탭에서 사용 내역 확인

Step 4: 고급 설정 (선택사항)

환경별 배포

.github/workflows/deploy-multi-env.yml:

name: Multi-Environment Deploy
 
on:
  push:
    branches: [main, develop]
 
jobs:
  deploy:
    runs-on: ubuntu-latest
 
    steps:
    - uses: actions/checkout@v4
 
    - name: Setup Alpacon CLI
      uses: alpacax/alpacon-setup-action@v1
 
    # 브랜치별 환경 설정
    - name: Set environment
      id: env
      run: |
        if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
          echo "target=prod-server" >> $GITHUB_OUTPUT
          echo "token=${{ secrets.ALPACON_PROD_TOKEN }}" >> $GITHUB_OUTPUT
        else
          echo "target=dev-server" >> $GITHUB_OUTPUT
          echo "token=${{ secrets.ALPACON_DEV_TOKEN }}" >> $GITHUB_OUTPUT
        fi
 
    - name: Deploy to ${{ steps.env.outputs.target }}
      uses: alpacax/alpacon-websh-action@v1
      with:
        workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
        api-token: ${{ steps.env.outputs.token }}
        target: ${{ steps.env.outputs.target }}
        script: |
          cd /app
          git pull
          npm ci
          npm run build
          pm2 restart app

두 토큰은 각자의 ACL을 가지므로, 개발용 토큰에는 prod-server에 대한 Server ACL 항목을 넣지 않아도 됩니다.

롤백 워크플로우

.github/workflows/rollback.yml:

name: Rollback Deployment
 
on:
  workflow_dispatch:
    inputs:
      version:
        description: 'Version to rollback to'
        required: true
        default: 'previous'
 
jobs:
  rollback:
    runs-on: ubuntu-latest
 
    steps:
    - name: Setup Alpacon CLI
      uses: alpacax/alpacon-setup-action@v1
 
    - name: Rollback application
      uses: alpacax/alpacon-websh-action@v1
      with:
        workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
        api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
        target: 'prod-server'
        script: |
          cd /app
          if [ "${{ github.event.inputs.version }}" = "previous" ]; then
            git reset --hard HEAD~1
          else
            git reset --hard ${{ github.event.inputs.version }}
          fi
          npm ci
          npm run build
          pm2 restart app

문제 해결

배포 실패 시

  1. GitHub Actions 로그 확인

    • Actions 탭에서 실패한 단계 확인
    • 에러 메시지 확인
  2. Alpacon 감사 이벤트 확인

    • Audit > Events에서 명령어 실행 로그 확인
    • 서버 연결 상태 확인
  3. 토큰의 ACL과 상태 확인

    • 실행하려는 명령에 대응하는 Command ACL 항목이 있는지, 파일 전송에는 Server ACL과 File ACL 항목이 모두 있는지 확인
    • 토큰이 대기중이 아니라 활성 상태인지, 만료되지 않았는지 확인

일반적인 문제

문제원인해결 방법
Permission denied대응하는 Command ACL 항목 없음. 항목이 하나도 없으면 모든 명령이 거부됨토큰의 ACL 탭에서 항목 추가
업로드 단계 거부대상 경로에 대한 Server ACL 또는 File ACL 누락둘 다 추가. 전송은 Server ACL을 먼저 확인한 뒤 File ACL을 확인
토큰 생성 직후 인증 실패토큰이 아직 대기중이고 활성화되지 않음승인 권한이 있는 사람에게 활성화 요청
Server not found잘못된 서버 이름워크스페이스에서 서버 이름 확인
Token expired토큰 만료새 토큰 발급 및 GitHub Secret 업데이트

다음 단계

요약

이 튜토리얼에서 다음을 완료했습니다:

✅ 서비스 토큰 생성 및 ACL 구성 ✅ GitHub Secrets 구성 ✅ CI/CD 파이프라인 작성 ✅ 자동 배포 실행 및 모니터링

SSH 키 대신 범위가 제한된 서비스 토큰을 사용하여 더 안전하고 관리하기 쉬운 배포 파이프라인을 구축했습니다.

최종 수정: