Jenkins 통합

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

사전 요구사항

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

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

빠른 시작

1. 서비스 토큰 생성

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

  1. IAM → Applications에서 이 파이프라인이 속한 Application을 열거나 새로 생성
  2. 자격 증명 탭에서 추가 클릭
  3. 토큰 이름과 접근 범위 지정, 필요한 사유 작성
  4. 표시된 키 복사(alpst-로 시작하며 한 번만 표시)

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

2. ACL 규칙 추가

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

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

규칙제한 대상
Server ACL파이프라인이 접근할 수 있는 서버
Command ACL실행할 수 있는 명령. 예: git pull, npm ci, pm2 restart myapp
File ACL업로드하거나 내려받을 수 있는 경로

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

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 websh prod-server "cd /opt/myapp && git pull && pm2 restart app"'
            }
        }
    }
}

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

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

사용 예시

애플리케이션 배포

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 websh $TARGET_SERVER "cd /opt/myapp && git pull origin main"'
                sh 'alpacon websh $TARGET_SERVER "cd /opt/myapp && npm ci --omit=dev"'
                sh 'alpacon websh $TARGET_SERVER "pm2 restart myapp"'
            }
        }
    }
}

Root 권한으로 서비스 재시작

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 websh root@prod-server "systemctl restart nginx"'
                sh 'alpacon websh root@prod-server "systemctl status nginx"'
            }
        }
    }
}

Docker Compose로 배포

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 prod-server:/opt/myapp/docker-compose.yml'
                sh 'alpacon cp .env prod-server:/opt/myapp/.env'
                sh 'alpacon websh root@prod-server "docker compose -f /opt/myapp/docker-compose.yml pull"'
                sh 'alpacon websh root@prod-server "docker compose -f /opt/myapp/docker-compose.yml up -d"'
                sh 'alpacon websh root@prod-server "docker compose -f /opt/myapp/docker-compose.yml ps"'
            }
        }
    }
}

alpacon cp 두 줄에는 Server ACL 항목에 더해 /opt/myapp/ 경로를 여는 File ACL 항목이 필요하고, docker compose 줄에는 Command 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이 그 작업을 포함하지 않습니다. 토큰의 ACL 탭에서 빠진 Server ACL, Command ACL, File ACL 항목을 추가하세요. 세 가지가 각각 기본 거부라서 추가하지 않은 종류는 전부 막힙니다.

다음 단계

최종 수정: