---
title: "Jenkins"
description: "Docker 컨테이너를 사용하여 Alpacon을 Jenkins 파이프라인에 통합하는 가이드입니다. 서비스 토큰 발급과 ACL 규칙, Jenkins Credential 설정, Declarative Pipeline 구성, entrypoint 오버라이드, 원격 서버 관리 자동화를 안내합니다."
---

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

# Jenkins 통합

공식 Docker 컨테이너를 사용하여 Alpacon을 Jenkins 파이프라인에 통합합니다.

## 사전 요구사항

- Docker Pipeline 플러그인이 설치된 Jenkins
- Alpacon 워크스페이스와 파이프라인의 서비스 토큰이 속할 Application

Free 플랜 워크스페이스는 Application을 하나만 둘 수 있습니다. 파이프라인 전용으로 새로 만들지 말고 이미 있는 Application을 함께 사용하세요.

## 빠른 시작

### 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 && pm2 restart app`, `cd /opt/myapp && git pull origin main`, `cd /opt/myapp && npm ci --omit=dev`, `pm2 restart myapp` |
| File ACL | 업로드하거나 내려받을 수 있는 경로 |

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

### 3. Credentials 추가

**Manage Jenkins → Credentials**에서 다음을 추가하세요:

- **ALPACON_WORKSPACE**: 워크스페이스 이름. 예: `your-workspace` (Secret text)
- **ALPACON_REGION**: 워크스페이스 리전. `us1` 또는 `ap1` (Secret text)
- **ALPACON_SERVICE_TOKEN**: 1단계에서 복사한 `alpst-` 키 (Secret text)

### 4. 파이프라인 생성

```groovy
pipeline {
    agent {
        docker {
            image 'alpacax/alpacon-cli:latest'
            args '--entrypoint=""'
        }
    }

    environment {
        ALPACON_WORKSPACE = credentials('ALPACON_WORKSPACE')
        ALPACON_REGION = credentials('ALPACON_REGION')
        ALPACON_SERVICE_TOKEN = credentials('ALPACON_SERVICE_TOKEN')
    }

    stages {
        stage('Deploy') {
            steps {
                sh 'alpacon login --workspace $ALPACON_WORKSPACE --region $ALPACON_REGION -t $ALPACON_SERVICE_TOKEN'
                sh 'alpacon exec ci-deploy@prod-server "cd /opt/myapp && git pull && pm2 restart app"'
            }
        }
    }
}
```

**중요:** 컨테이너의 기본 entrypoint를 override하기 위해 `args '--entrypoint=""'`가 필요합니다.

CLI는 `alpacon login`으로만 토큰을 읽습니다. 환경 변수로 인증하는 경로는 없으므로 모든 파이프라인은 첫 Alpacon 명령 앞에 이 login 단계를 그대로 두어야 합니다.

## 사용 예시

### 애플리케이션 배포

```groovy
pipeline {
    agent {
        docker {
            image 'alpacax/alpacon-cli:latest'
            args '--entrypoint=""'
        }
    }

    environment {
        ALPACON_WORKSPACE = credentials('ALPACON_WORKSPACE')
        ALPACON_REGION = credentials('ALPACON_REGION')
        ALPACON_SERVICE_TOKEN = credentials('ALPACON_SERVICE_TOKEN')
        TARGET_SERVER = 'prod-server'
    }

    stages {
        stage('Deploy') {
            steps {
                sh 'alpacon login --workspace $ALPACON_WORKSPACE --region $ALPACON_REGION -t $ALPACON_SERVICE_TOKEN'
                sh 'alpacon exec ci-deploy@$TARGET_SERVER "cd /opt/myapp && git pull origin main"'
                sh 'alpacon exec ci-deploy@$TARGET_SERVER "cd /opt/myapp && npm ci --omit=dev"'
                sh 'alpacon exec ci-deploy@$TARGET_SERVER "pm2 restart myapp"'
            }
        }
    }
}
```

### sudo로 서비스 재시작

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

```groovy
pipeline {
    agent {
        docker {
            image 'alpacax/alpacon-cli:latest'
            args '--entrypoint=""'
        }
    }

    environment {
        ALPACON_WORKSPACE = credentials('ALPACON_WORKSPACE')
        ALPACON_REGION = credentials('ALPACON_REGION')
        ALPACON_SERVICE_TOKEN = credentials('ALPACON_SERVICE_TOKEN')
    }

    stages {
        stage('Restart') {
            steps {
                sh 'alpacon login --workspace $ALPACON_WORKSPACE --region $ALPACON_REGION -t $ALPACON_SERVICE_TOKEN'
                sh 'alpacon exec ci-deploy@prod-server "sudo systemctl restart nginx"'
                sh 'alpacon exec ci-deploy@prod-server "systemctl status nginx"'
            }
        }
    }
}
```

### Docker Compose로 배포

```groovy
pipeline {
    agent {
        docker {
            image 'alpacax/alpacon-cli:latest'
            args '--entrypoint=""'
        }
    }

    environment {
        ALPACON_WORKSPACE = credentials('ALPACON_WORKSPACE')
        ALPACON_REGION = credentials('ALPACON_REGION')
        ALPACON_SERVICE_TOKEN = credentials('ALPACON_SERVICE_TOKEN')
    }

    stages {
        stage('Deploy') {
            steps {
                sh 'alpacon login --workspace $ALPACON_WORKSPACE --region $ALPACON_REGION -t $ALPACON_SERVICE_TOKEN'
                sh 'alpacon cp docker-compose.yml ci-deploy@prod-server:/opt/myapp/docker-compose.yml'
                sh 'alpacon cp .env ci-deploy@prod-server:/opt/myapp/.env'
                sh 'alpacon exec ci-deploy@prod-server "docker compose -f /opt/myapp/docker-compose.yml pull"'
                sh 'alpacon exec ci-deploy@prod-server "docker compose -f /opt/myapp/docker-compose.yml up -d"'
                sh 'alpacon exec ci-deploy@prod-server "docker compose -f /opt/myapp/docker-compose.yml ps"'
            }
        }
    }
}
```

`alpacon cp` 두 줄에는 Server ACL 항목에 더해 `/opt/myapp/` 경로를 여는 File ACL 항목이 필요하고, `docker compose` 줄에는 Cloud의 사전 승인 명령어 또는 자체 호스팅의 명령어 ACL 항목이 필요합니다.

## 보안

Alpacon을 통해 실행된 모든 명령은 워크스페이스 감사 로그에 기록되며, 사람이 아니라 토큰을 소유한 Application 이름으로 남습니다. 환경 변수를 통해 전달된 민감한 값(비밀번호, 토큰 등)은 명령 기록에서 자동으로 마스킹됩니다.

## 문제 해결

### Entrypoint 오류

**증상:** 컨테이너가 예상한 명령을 실행하지 않음

**해결 방법:** docker agent 설정에 `args '--entrypoint=""'`를 반드시 포함해야 합니다.

### 정상적인 서비스 토큰으로 로그인 실패

**증상:** `alpst-` 키를 정확히 복사했는데도 `alpacon login`이 `failed to verify user profile`을 출력함

**해결 방법:** 서비스 토큰은 Alpacon CLI v1.7.4 이상이 필요합니다. 그 이전 버전은 `alpst-` 키를 알아보지 못하고 이처럼 오해하기 쉬운 메시지를 대신 출력합니다. 에이전트가 실제로 실행하는 버전을 확인하고 올리세요. 자체 호스팅 에이전트이거나 `alpacax/alpacon-cli` 이미지 태그를 고정한 경우가 대부분입니다.

### 명령이나 파일이 거부됨

**증상:** 내 터미널에서는 되는 명령이나 `alpacon cp`가 파이프라인에서는 거부됨

**해결 방법:** 토큰의 서버·파일 ACL과 실행 계정을 확인하세요. Cloud에서는 Command ACL 관리자에게 토큰의 사전 승인 명령어 검토를 요청하고, 자체 호스팅에서는 명령어 ACL을 확인하세요. [자동화 오류 해결](/integrate/automation-failure-modes/)을 참고하세요.

## 다음 단계

- [GitHub Actions 통합](/integrate/github-actions/)
- [GitLab CI 통합](/integrate/gitlab-ci/)
- [서비스 토큰](/use/iam/applications/service-tokens/)
- [CLI 레퍼런스](/reference/cli/)

Source: https://docs.alpacax.com/ko/integrate/jenkins/
