GitHub Actions로 CI/CD 파이프라인 구축하기
Alpacon GitHub Actions를 이용한 단계별 CI/CD 파이프라인 구축 튜토리얼입니다.
학습 목표
이 튜토리얼을 완료하면 다음을 할 수 있습니다:
- SSH 키 없이 안전한 배포 파이프라인 구축
- 명령어 수준의 세밀한 권한 제어
- 자동화된 빌드 및 배포 프로세스 구현
사전 준비사항
- Alpacon 워크스페이스 생성 완료
- 서버 등록 및 에이전트 설치 완료
- 이 파이프라인이 사용할 Application, 또는 Application을 만들 수 있는 관리자 권한
- GitHub 저장소 접근 권한
Step 1: 서비스 토큰 생성 (5분 + 승인 대기)
1-1. 서비스 토큰 생성
CI와 자동화는 서비스 토큰으로 동작합니다. 서비스 토큰은 사람이 아니라 Application에 속하기 때문에 담당자가 바뀌어도 그대로 유지되며, 파이프라인이 무엇까지 할 수 있는지는 ACL이 정확히 정합니다.
- Alpacon 워크스페이스에 로그인
- IAM → Applications에서 이 파이프라인이 속한 Application 열기 또는 새로 생성
- 자격 증명 탭에서 추가 클릭
양식에서 다음을 설정합니다:
Token name: github-actions-deploy
Expiration: 3 months (권장)
Scopes: 배포에 필요한 범위 선택
Reason: 이 파이프라인에 토큰이 필요한 이유
표시된 키를 복사하세요. alpst-로 시작하며 한 번만 표시됩니다.
CI 범위로 만든 토큰은 검토를 거쳐야 동작합니다. 요청은 대기중(pending) 상태로 생성되고 승인 권한이 있는 사람이 활성화하기 전까지는 어디에도 인증되지 않습니다. 파이프라인 도중에 발견하지 않도록 이 단계를 미리 감안하세요.
1-2. ACL 규칙 추가
새 서비스 토큰은 ACL 규칙을 추가하기 전까지 아무 곳에도 닿지 못합니다. 서버, 명령, 파일 경로가 각각 기본 거부이므로 규칙이 하나도 없는 토큰은 어디서든 거부됩니다.
토큰을 열고 ACL 탭에서 다음을 추가하세요.
| 규칙 | 이 파이프라인에 필요한 항목 |
|---|---|
| Server ACL | prod-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 저장소에서:
- Settings > Secrets and variables > Actions 이동
- New repository secret 클릭
- 다음 시크릿 추가:
| Name | Value |
|---|---|
ALPACON_WORKSPACE_URL | https://your-workspace.ap1.alpacon.io |
ALPACON_SERVICE_TOKEN | Step 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. 배포 모니터링
- GitHub 저장소의 Actions 탭 이동
- 실행 중인 워크플로우 클릭
- 각 단계별 로그 확인
3-3. Alpacon에서 확인
- Alpacon 워크스페이스의 Audit > Events 열기
- Commands 탭에서 실행된 명령어와 결과 확인. 토큰을 소유한 Application 이름으로 기록됨
- 토큰의 개요 탭에서 사용 내역 확인
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
문제 해결
배포 실패 시
-
GitHub Actions 로그 확인
- Actions 탭에서 실패한 단계 확인
- 에러 메시지 확인
-
Alpacon 감사 이벤트 확인
- Audit > Events에서 명령어 실행 로그 확인
- 서버 연결 상태 확인
-
토큰의 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 키 대신 범위가 제한된 서비스 토큰을 사용하여 더 안전하고 관리하기 쉬운 배포 파이프라인을 구축했습니다.