GitHub Actions로 첫 변경 배포

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

학습 목표

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

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

사전 준비사항

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

1-1. 서비스 토큰 생성

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

  1. Alpacon 워크스페이스에 로그인
  2. IAM → Applications에서 이 파이프라인이 속한 Application 열기 또는 새로 생성
  3. 토큰 탭에서 새로 만들기 클릭

네 단계를 차례로 진행합니다.

yaml
용도: 이름 github-actions-deploy, 만료 30일
권한: 배포 파이프라인 템플릿에서 시작해 조정
접근 규칙: prod-server와 1-2의 업로드 경로
검토: 이 파이프라인에 토큰이 필요한 이유 작성

만료 기본값은 30일이며 90일, 365일을 고르거나 시각을 직접 지정할 수 있습니다. 서비스 토큰에는 만료일이 필요하지만 워크스페이스의 토큰 최대 사용 기간은 적용되지 않습니다.

토큰 만들기를 누르면 키가 가려진 채로 한 번만 표시됩니다. 키는 alpst-로 시작합니다. 복사하거나 내려받은 뒤 키를 안전한 곳에 보관했어요에 체크해야 창을 닫을 수 있습니다.

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

1-2. ACL 규칙 추가

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

접근 규칙 단계에서 고른 규칙은 토큰이 승인될 때까지 대기합니다. 승인 후 토큰의 접근 규칙 탭을 열고 준비된 접근 규칙에서 적용을 선택하거나, 서버와 파일 규칙을 직접 추가하세요. Alpacon Cloud에서는 명령 ACL 관리자에 등록된 관리자가 같은 탭의 사전 승인된 명령에 아래 명령어를 추가합니다. 이 권한은 워크스페이스 역할과 별개입니다. 자체 호스팅에서는 접근 규칙 탭의 허용된 명령에 각 명령어를 패턴으로 추가하세요. 다음 접근 범위를 설정합니다.

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

각 명령어 항목은 제출하는 한 줄 전체와 일치해야 합니다. 아래 워크플로에서 각 토큰에 필요한 명령어를 한 항목씩 추가하세요.

pm2 restart app
pm2 status
curl -f http://localhost:3000/health || exit 1
cd /app && git pull && npm ci && npm run build && pm2 restart app
cd /app && if [ "$ROLLBACK_VERSION" = "previous" ]; then git reset --hard HEAD~1; else git reset --hard "$ROLLBACK_VERSION"; fi && npm ci && npm run build && pm2 restart app

파일 전송은 서버 규칙을 먼저 확인한 다음 파일 규칙을 확인합니다. 따라서 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:

yaml
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. 코드 푸시

bash
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. 명령 탭에서 실행된 명령어와 결과 확인. 토큰을 소유한 Application 이름으로 기록됨
  3. 토큰의 개요 탭에서 사용 내역 확인

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

환경별 배포

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

yaml
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:

yaml
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
      env:
        ROLLBACK_VERSION: ${{ github.event.inputs.version }}
      with:
        workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
        api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
        target: 'prod-server'
        env: |
          ROLLBACK_VERSION
        script: |
          cd /app && if [ "$ROLLBACK_VERSION" = "previous" ]; then git reset --hard HEAD~1; else git reset --hard "$ROLLBACK_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 항목 없음. 항목이 하나도 없으면 모든 명령이 거부됨토큰의 접근 규칙 탭에서 항목 추가
업로드 단계 거부대상 경로에 대한 Server ACL 또는 File ACL 누락둘 다 추가. 전송은 Server ACL을 먼저 확인한 뒤 File ACL을 확인
토큰 생성 직후 인증 실패토큰이 아직 대기중이고 활성화되지 않음승인 권한이 있는 사람에게 활성화 요청
Server not found잘못된 서버 이름워크스페이스에서 서버 이름 확인
Token expired토큰 만료새 토큰 발급 및 GitHub Secret 업데이트

다음 단계

요약

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

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

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

최종 수정: