GitLab CI 통합

공식 Docker 컨테이너를 사용하여 GitLab CI/CD 파이프라인에서 Alpacon으로 배포와 서버 관리를 자동화하세요.

빠른 시작

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를 포함한 제출 문자열 전체와 일치해야 합니다. 서비스 토큰을 참고하세요.

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

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

2. ACL 규칙 추가

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

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

규칙제한 대상
Server ACL파이프라인이 접근할 수 있는 서버
명령어 접근실행할 수 있는 명령. 예: docker compose ... up -d
File ACL업로드하거나 내려받을 수 있는 경로

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

3. CI/CD 변수 추가

GitLab 프로젝트에 다음 변수를 추가하세요 (Settings → CI/CD → Variables):

  • ALPACON_WORKSPACE: 워크스페이스 이름 (예: your-workspace)
  • ALPACON_REGION: 워크스페이스 리전 (us1 또는 ap1)
  • ALPACON_SERVICE_TOKEN: 1단계에서 복사한 alpst- 키 (Masked와 Protected로 표시)
  • DOCKER_USERNAME: Docker 로그인 예제에서 사용할 레지스트리 사용자 이름 (Masked로 표시)
  • DOCKER_PASSWORD: Docker 로그인 예제에서 사용할 레지스트리 비밀번호 (Masked로 표시)

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

4. .gitlab-ci.yml 생성

중요: alpacax/alpacon-cli 이미지는 ENTRYPOINT ["alpacon"]으로 설정되어 있으므로, GitLab CI에서 entrypoint: [""]로 오버라이드해야 합니다.

yaml
stages:
  - deploy
 
deploy:
  stage: deploy
  image:
    name: alpacax/alpacon-cli:latest
    entrypoint: [""]
  script:
    - alpacon login --workspace $ALPACON_WORKSPACE --region $ALPACON_REGION -t $ALPACON_SERVICE_TOKEN
    - alpacon exec ci-deploy@prod-server "docker ps"
  only:
    - main

배포 디렉터리 준비

첫 배포 전에 서버 관리자에게 /opt/myapp을 만들고 애플리케이션 계정(예시에서는 ci-deploy)이 소유하도록 설정해 달라고 요청하세요. 이 계정의 Docker 접근 권한도 준비해야 합니다. 파이프라인은 준비된 디렉터리에 파일을 올리고 배포합니다.

사용 예제

docker-compose.yml로 배포

yaml
deploy-compose:
  stage: deploy
  image:
    name: alpacax/alpacon-cli:latest
    entrypoint: [""]
  script:
    - alpacon login --workspace $ALPACON_WORKSPACE --region $ALPACON_REGION -t $ALPACON_SERVICE_TOKEN
    - alpacon cp docker-compose.yml ci-deploy@prod-server:/opt/myapp/docker-compose.yml
    - alpacon exec ci-deploy@prod-server "docker compose -f /opt/myapp/docker-compose.yml up -d"
    - alpacon exec ci-deploy@prod-server "docker compose -f /opt/myapp/docker-compose.yml ps"
  only:
    - main

환경 변수 파일과 함께 배포

작업 실행 전에 관리자에게 /opt/myapp을 만들고 애플리케이션 계정이 소유하도록 설정해 달라고 요청하세요. 배포 디렉터리 준비를 참고하세요.

yaml
deploy-with-env:
  stage: deploy
  image:
    name: alpacax/alpacon-cli:latest
    entrypoint: [""]
  script:
    - alpacon login --workspace $ALPACON_WORKSPACE --region $ALPACON_REGION -t $ALPACON_SERVICE_TOKEN
    # Upload files
    - alpacon cp docker-compose.yml ci-deploy@prod-server:/opt/myapp/
    - alpacon cp .env ci-deploy@prod-server:/opt/myapp/
    # Deploy
    - alpacon exec ci-deploy@prod-server "docker compose -f /opt/myapp/docker-compose.yml up -d"
    - alpacon exec ci-deploy@prod-server "docker compose -f /opt/myapp/docker-compose.yml ps"
  only:
    - main

이미지 태그와 함께 배포

yaml
deploy-tagged:
  stage: deploy
  image:
    name: alpacax/alpacon-cli:latest
    entrypoint: [""]
  script:
    - alpacon login --workspace $ALPACON_WORKSPACE --region $ALPACON_REGION -t $ALPACON_SERVICE_TOKEN
    - alpacon exec --env="DOCKER_USERNAME" --env="DOCKER_PASSWORD" ci-deploy@prod-server 'printf "%s\n" "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin'
    - alpacon cp docker-compose.yml ci-deploy@prod-server:/opt/myapp/docker-compose.yml
    - alpacon exec --env="DOCKER_USERNAME" --env="IMAGE_TAG=$CI_COMMIT_SHORT_SHA" ci-deploy@prod-server "docker compose -f /opt/myapp/docker-compose.yml pull"
    - alpacon exec --env="DOCKER_USERNAME" --env="IMAGE_TAG=$CI_COMMIT_SHORT_SHA" ci-deploy@prod-server "docker compose -f /opt/myapp/docker-compose.yml up -d"
    - alpacon exec --env="DOCKER_USERNAME" --env="IMAGE_TAG=$CI_COMMIT_SHORT_SHA" ci-deploy@prod-server "docker compose -f /opt/myapp/docker-compose.yml ps"
  only:
    - main

다중 환경 배포

아래 두 job은 같은 토큰을 사용하므로 토큰의 Server ACL에 prod-server뿐 아니라 staging-server도 들어가야 합니다. 환경마다 토큰을 따로 발급해 각자의 서버로만 범위를 좁히면 staging 파이프라인이 프로덕션에 아예 닿지 못합니다.

yaml
deploy-staging:
  stage: deploy
  image:
    name: alpacax/alpacon-cli:latest
    entrypoint: [""]
  script:
    - alpacon login --workspace $ALPACON_WORKSPACE --region $ALPACON_REGION -t $ALPACON_SERVICE_TOKEN
    - alpacon cp docker-compose.yml ci-deploy@staging-server:/opt/myapp/docker-compose.yml
    - alpacon exec ci-deploy@staging-server "docker compose -f /opt/myapp/docker-compose.yml up -d"
  only:
    - develop
  environment:
    name: staging
 
deploy-production:
  stage: deploy
  image:
    name: alpacax/alpacon-cli:latest
    entrypoint: [""]
  script:
    - alpacon login --workspace $ALPACON_WORKSPACE --region $ALPACON_REGION -t $ALPACON_SERVICE_TOKEN
    - alpacon cp docker-compose.yml ci-deploy@prod-server:/opt/myapp/docker-compose.yml
    - alpacon exec ci-deploy@prod-server "docker compose -f /opt/myapp/docker-compose.yml up -d"
  only:
    - main
  environment:
    name: production
  when: manual

완전한 CI/CD 파이프라인

yaml
stages:
  - build
  - deploy
 
build-image:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    - printf '%s\n' "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
    - docker build -t $DOCKER_USERNAME/myapp:$CI_COMMIT_SHORT_SHA .
    - docker push $DOCKER_USERNAME/myapp:$CI_COMMIT_SHORT_SHA
  only:
    - main
 
deploy:
  stage: deploy
  image:
    name: alpacax/alpacon-cli:latest
    entrypoint: [""]
  script:
    - alpacon login --workspace $ALPACON_WORKSPACE --region $ALPACON_REGION -t $ALPACON_SERVICE_TOKEN
    - alpacon exec --env="DOCKER_USERNAME" --env="DOCKER_PASSWORD" ci-deploy@prod-server 'printf "%s\n" "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin'
    - alpacon cp docker-compose.yml ci-deploy@prod-server:/opt/myapp/docker-compose.yml
    - alpacon exec --env="DOCKER_USERNAME" --env="IMAGE_TAG=$CI_COMMIT_SHORT_SHA" ci-deploy@prod-server "docker compose -f /opt/myapp/docker-compose.yml pull"
    - alpacon exec --env="DOCKER_USERNAME" --env="IMAGE_TAG=$CI_COMMIT_SHORT_SHA" ci-deploy@prod-server "docker compose -f /opt/myapp/docker-compose.yml up -d"
    - alpacon exec --env="DOCKER_USERNAME" --env="IMAGE_TAG=$CI_COMMIT_SHORT_SHA" ci-deploy@prod-server "docker compose -f /opt/myapp/docker-compose.yml ps"
  only:
    - main
  needs:
    - build-image

보안

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

문제 해결

Entrypoint 오류

증상: Error: unknown command "sh" for "alpacon"

해결 방법: 이미지 구성에 entrypoint: [""]를 추가하는 것을 잊었습니다. 다음과 같이 사용하세요:

yaml
image:
  name: alpacax/alpacon-cli:latest
  entrypoint: [""]

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

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

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

명령이나 파일이 거부됨

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

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

권한 거부

증상: Docker 명령 실행 시 permission denied

해결 방법: 애플리케이션 계정으로 실행하세요: alpacon exec ci-deploy@server-name "docker ps". 이 계정에 필요한 서버 권한이 있는지 확인하세요. 서비스 토큰은 root로 실행할 수 없으며 ACL 범위를 넓혀도 이 제한은 바뀌지 않습니다.

업로드 후 파일을 찾을 수 없음

증상: 파일이 성공적으로 업로드되었지만 명령 실행 시 찾을 수 없음

해결 방법: 서버 관리자에게 애플리케이션 계정이 쓸 상위 디렉터리를 준비해 달라고 요청하세요. 그다음 해당 계정으로 하위 디렉터리를 만들고 업로드하세요:

yaml
- alpacon exec ci-deploy@server "mkdir -p /path/to/dir"
- alpacon cp file.txt ci-deploy@server:/path/to/dir/

리소스

다음 단계

최종 수정: