---
title: "GitHub Actions"
description: "Alpacon GitHub Actions를 사용하여 CI/CD 배포를 자동화하는 통합 가이드입니다. alpacon-setup, websh, cp, common 4가지 액션 구성, 다중 서버 배포, Docker 환경별 배포 워크플로 및 서비스 토큰 보안 모범 사례를 안내합니다."
---

> Full documentation index: https://docs.alpacax.com/llms.ko.txt

# GitHub Actions 통합

Alpacon의 전용 GitHub Actions로 배포와 서버 관리를 자동화하세요.

## 사용 가능한 액션

Alpacon은 CI/CD 워크플로를 위한 4가지 GitHub Actions를 제공합니다:

| 액션 | 용도 | 사용 사례 |
|------|------|----------|
| [alpacon-setup-action] | Alpacon CLI 설치 | 항상 먼저 실행 |
| [alpacon-websh-action] | 원격 명령 실행 | 앱 배포, 서비스 재시작 |
| [alpacon-cp-action] | 파일 전송 | 빌드 업로드, 로그 다운로드 |
| [alpacon-common-action] | 모든 Alpacon 명령 실행 | 서버 목록 조회, 상태 확인 |

전체 입력값 정보는 [Actions 레퍼런스](/reference/actions/)를 참고하세요.

## 빠른 시작

### 1. 서비스 토큰 생성

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

토큰 발급 전에 애플리케이션에 서버 계정과 필요한 scope를 허용하는 전역 역할을 부여하세요. 예시의 `ci-deploy`는 애플리케이션이 소유한 계정으로 바꿔 사용합니다. 이 계정이 배포 디렉터리와 Docker에 접근할 수 있도록 권한을 설정하세요. 서비스 토큰은 `root`로 실행하거나 대화형 Websh 세션을 열 수 없습니다.

Alpacon Cloud에서는 서비스 토큰의 sudo 위험도가 심각(Critical)보다 낮거나 평가되지 않았으면 허용하고, 심각이면 거부합니다. 단, Advisory 워크스페이스에서는 위험도를 이유로 거부하지 않고 판단을 기록합니다. Advisory가 아니면 워크스페이스의 `token_exec` 규칙으로 위험도 기준을 더 엄격하게 정할 수 있습니다. 워크스페이스의 sudo 설정도 켜져 있어야 하며, 꺼져 있으면 `workspace_sudo_with_mfa_disabled`로 거부됩니다. 기본 설정의 자체 호스팅에서는 모든 서비스 토큰 sudo가 거부됩니다. 명령어 규칙은 `sudo`를 포함한 제출 문자열 전체와 일치해야 합니다. [서비스 토큰](/use/iam/applications/service-tokens/)을 참고하세요.

1. **IAM** → [애플리케이션](/use/iam/applications/)에서 이 파이프라인이 속한 Application을 열거나 새로 생성
2. **토큰** 탭에서 **새로 만들기** 클릭
3. 토큰 이름과 만료 시점 지정, 액세스 템플릿이나 직접 선택으로 권한 지정, 서버·명령어·경로 준비, 검토 단계에서 필요한 사유 작성
4. 표시된 키 복사 또는 다운로드(`alpst-`로 시작하며 한 번만 표시)

명령어와 파일 전송 scope는 항상 웹 콘솔에서 승인을 기다립니다. ACL을 추가하거나 파이프라인을 시작하기 전에 슈퍼유저나 해당 요청의 승인자에게 승인을 받으세요.

### 2. ACL 규칙 추가

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

승인 후 토큰의 **접근 규칙** 탭에서 준비한 규칙을 적용하거나 서버와 파일 규칙을 추가하세요. Alpacon Cloud에서는 **명령 ACL 관리자**에 등록된 관리자가 같은 탭의 **사전 승인된 명령**에 명령어를 추가합니다. 이 권한은 워크스페이스 역할과 별개입니다. 자체 호스팅에서는 명령어 ACL을 사용합니다. 다음 접근 범위를 설정하세요.

| 규칙 | 제한 대상 |
|--------|-----------------|
| Server ACL | 파이프라인이 접근할 수 있는 서버 |
| 명령어 접근 | 워크플로가 제출하는 명령어 전체. 예: `cd /opt/myapp && git pull && npm install && pm2 restart app` |
| File ACL | 업로드하거나 내려받을 수 있는 경로 |

파일 전송은 서버 규칙을 먼저 확인한 다음 파일 규칙을 확인합니다. **접근 규칙** 탭을 건너뛰면 워크플로는 첫 명령에서 실패합니다.

### 3. GitHub에 시크릿 추가

리포지토리에 다음 시크릿을 추가하세요 (Settings → Secrets → Actions):

```
ALPACON_WORKSPACE_URL: https://your-workspace.ap1.alpacon.io
ALPACON_SERVICE_TOKEN: alpst-your-token-here
```

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

### 4. 워크플로에서 사용

```yaml
name: Deploy with Alpacon
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Alpacon CLI
        uses: alpacax/alpacon-setup-action@v1

      - name: Deploy to production
        uses: alpacax/alpacon-websh-action@v1
        with:
          workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
          api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
          target: 'prod-server'
          username: 'ci-deploy'
          script: |
            cd /opt/myapp && git pull && npm install && pm2 restart app
```

## 대안: Alpacon CLI 컨테이너 사용

사전 제작된 액션 대신 Alpacon CLI를 직접 사용하려면 공식 Docker 컨테이너를 사용할 수 있습니다.

이 방식에서는 CLI가 URL이 아니라 워크스페이스 이름과 리전으로 Alpacon Cloud에 로그인하므로 시크릿 두 개를 더 추가합니다:

```
ALPACON_WORKSPACE: your-workspace
ALPACON_REGION: ap1
```

`ALPACON_WORKSPACE_URL`은 네 가지 액션의 `workspace-url` 입력값으로 그대로 쓰이므로 남겨 두고, `ALPACON_SERVICE_TOKEN`은 두 방식이 함께 사용합니다.

```yaml
name: Deploy with Alpacon CLI
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    container:
      image: alpacax/alpacon-cli:latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Login to Alpacon
        run: alpacon login --workspace ${{ secrets.ALPACON_WORKSPACE }} --region ${{ secrets.ALPACON_REGION }} -t ${{ secrets.ALPACON_SERVICE_TOKEN }}

      - name: Deploy to production
        run: |
          alpacon exec ci-deploy@prod-server "cd /opt/myapp && git pull && npm install && pm2 restart app"

      - name: Upload build artifacts
        run: |
          alpacon cp -r ./dist/ ci-deploy@prod-server:/var/www/app/
```

이 방식은 최소한의 설정으로 CLI에 직접 접근할 수 있으며, 여러 CLI 명령이 필요한 복잡한 워크플로에 유용합니다.

## 사용 예제

> 아래 모든 예제는 이전 단계에서 `alpacon-setup-action`이 이미 실행되었다고 가정합니다. 전체 워크플로는 [빠른 시작](#빠른-시작) 섹션을 참고하세요.

### sudo로 서비스 재시작

애플리케이션 계정으로 실행하세요. Cloud에서는 워크스페이스에 더 엄격한 규칙이 없으면 심각 미만의 sudo를 허용하며, Advisory에서는 위험도를 이유로 거부하지 않고 판단을 기록합니다. 워크스페이스 sudo 설정이 켜져 있어야 합니다. 기본 설정의 자체 호스팅에서는 거부됩니다. 명령어 규칙은 `sudo systemctl restart nginx` 전체 문자열과 일치해야 합니다.

```yaml
- name: Restart nginx
  uses: alpacax/alpacon-websh-action@v1
  with:
    workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
    api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
    target: 'web-server'
    username: 'ci-deploy'
    script: sudo systemctl restart nginx
```

### 애플리케이션 계정으로 실행

```yaml
- name: Deploy as the application account
  uses: alpacax/alpacon-websh-action@v1
  with:
    workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
    api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
    target: 'web-server'
    username: 'ci-deploy'
    script: |
      cd /home/ci-deploy/app && git pull && npm install
```

서비스 토큰은 항상 해당 계정의 전용 그룹을 사용합니다.

### 환경 변수 전달

이 계정으로 시스템 서비스를 재시작하려면 sudo가 필요합니다. 워크스페이스 설정과 명령어 규칙은 [sudo로 서비스 재시작](#sudo로-서비스-재시작)을 참고하세요.

```yaml
- name: Deploy with environment variables
  uses: alpacax/alpacon-websh-action@v1
  with:
    workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
    api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
    target: 'prod-server'
    username: 'ci-deploy'
    env: |
      APP_ENV=production
      DB_HOST=localhost
    script: |
      echo "Deploying to $APP_ENV"
      sudo systemctl restart myapp
```

### 빌드 산출물 업로드

```yaml
- name: Build application
  run: npm run build

- name: Upload build 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'
    username: 'ci-deploy'
    target-path: '/var/www/app/'
    recursive: true
```

### 다중 파일 업로드

```yaml
- name: Upload config files
  uses: alpacax/alpacon-cp-action@v1
  with:
    workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
    api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
    source: |
      ./docker-compose.yml
      ./nginx.conf
      ./.env.production
    target-server: 'prod-server'
    username: 'ci-deploy'
    target-path: '/opt/myapp/'
```

### 로그 다운로드

```yaml
- name: Download error logs
  uses: alpacax/alpacon-cp-action@v1
  with:
    workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
    api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
    source: '/var/log/app/error.log'
    target-server: 'prod-server'
    username: 'ci-deploy'
    target-path: './logs/'
    mode: download

- name: Upload logs as artifact
  uses: actions/upload-artifact@v4
  with:
    name: error-logs
    path: ./logs/
```

### 다중 서버 배포

```yaml
jobs:
  deploy:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        server: [web1, web2, web3]
    steps:
      - uses: actions/checkout@v4

      - name: Setup Alpacon CLI
        uses: alpacax/alpacon-setup-action@v1

      - name: Deploy to ${{ matrix.server }}
        uses: alpacax/alpacon-websh-action@v1
        with:
          workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
          api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
          target: ${{ matrix.server }}
          username: 'ci-deploy'
          script: |
            cd /opt/myapp && git pull && npm install && pm2 restart app
```

### 모든 Alpacon 명령 실행

```yaml
- name: List all servers
  uses: alpacax/alpacon-common-action@v1
  with:
    workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
    api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
    command: "server ls"
```

### 환경별 Docker 배포

동적 서버 선택을 통해 다양한 환경에 컨테이너화된 애플리케이션을 배포합니다:

```yaml
name: Deploy Application

on:
  workflow_dispatch:
    inputs:
      env:
        description: "Deployment environment"
        required: true
        type: choice
        options:
          - dev
          - prod

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Select target server
        run: |
          if [ "${{ inputs.env }}" = "prod" ]; then
            echo "TARGET_SERVER=prod-server" >> $GITHUB_ENV
            echo "APP_PORT=8080" >> $GITHUB_ENV
          else
            echo "TARGET_SERVER=dev-server" >> $GITHUB_ENV
            echo "APP_PORT=8081" >> $GITHUB_ENV
          fi

      - name: Prepare environment file
        env:
          APP_SECRETS: ${{ secrets.APP_SECRETS }}
        run: |
          echo "APP_ENV=${{ inputs.env }}" > /tmp/.env
          echo "APP_PORT=${{ env.APP_PORT }}" >> /tmp/.env
          printf '%s' "$APP_SECRETS" >> /tmp/.env

      - name: Setup Alpacon CLI
        uses: alpacax/alpacon-setup-action@v1

      - name: Docker login on target server
        uses: alpacax/alpacon-websh-action@v1
        env:
          DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
          DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
        with:
          workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
          api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
          target: ${{ env.TARGET_SERVER }}
          username: 'ci-deploy'
          env: |
            DOCKER_USERNAME
            DOCKER_PASSWORD
          script: |
            printf '%s\n' "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin

      - name: Copy docker-compose.yml
        uses: alpacax/alpacon-cp-action@v1
        with:
          workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
          api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
          source: ./docker-compose.yml
          target-server: ${{ env.TARGET_SERVER }}
          username: 'ci-deploy'
          target-path: /opt/myapp/docker-compose.yml

      - name: Copy environment file
        uses: alpacax/alpacon-cp-action@v1
        with:
          workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
          api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
          source: /tmp/.env
          target-server: ${{ env.TARGET_SERVER }}
          username: 'ci-deploy'
          target-path: /opt/myapp/.env

      - name: Deploy application
        uses: alpacax/alpacon-websh-action@v1
        with:
          workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
          api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
          target: ${{ env.TARGET_SERVER }}
          username: 'ci-deploy'
          script: |
            docker compose -f /opt/myapp/docker-compose.yml pull
            docker compose -f /opt/myapp/docker-compose.yml --env-file /opt/myapp/.env up -d
            docker compose -f /opt/myapp/docker-compose.yml ps
```

## 모범 사례

- CI/CD 전용 서비스 토큰을 최소 권한으로 발급
- 토큰이 실행할 수 있는 명령어는 Cloud의 사전 승인 명령어나 자체 호스팅의 명령어 ACL로 제한
- 토큰은 시크릿으로 저장하고 리포지토리에는 커밋 금지
- 워크스페이스에서 토큰을 정기적으로 교체한 뒤 GitHub 시크릿 갱신
- 여러 리포지토리가 공유하는 토큰에는 조직 시크릿 사용
- 모든 명령은 워크스페이스 감사 로그에 기록되며 민감한 값은 자동 마스킹

## 리소스

- [Actions 레퍼런스](/reference/actions/)
- [Alpacon CLI 문서](/reference/cli/)
- [서비스 토큰](/use/iam/applications/service-tokens/)
- [GitHub Marketplace - Setup Action](https://github.com/marketplace/actions/setup-alpacon-cli)
- [GitHub Marketplace - Websh Action](https://github.com/marketplace/actions/alpacon-websh-action)
- [GitHub Marketplace - CP Action](https://github.com/marketplace/actions/alpacon-cp-action)
- [GitHub Marketplace - Common Action](https://github.com/marketplace/actions/alpacon-common-action)

[alpacon-setup-action]: /reference/actions/setup/
[alpacon-websh-action]: /reference/actions/websh/
[alpacon-cp-action]: /reference/actions/cp/
[alpacon-common-action]: /reference/actions/common/

## 다음 단계

- [GitLab CI 통합](/integrate/gitlab-ci/)
- [Jenkins 통합](/integrate/jenkins/)
- [CLI 레퍼런스](/reference/cli/)

Source: https://docs.alpacax.com/ko/integrate/github-actions/
