Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

CI에서 Apollo 제품 릴리스 게시

CI 파이프라인에 Apollo CLI를 추가하면 소프트웨어 변경을 빌드한 뒤 새 제품 릴리스를 제품 카탈로그에 등록할 수 있습니다. 컨테이너 이미지와 Helm 차트를 저장소에 게시하는 단계, Apollo에 제품 릴리스 메타데이터를 등록하는 단계는 구분합니다. product-release create는 메타데이터를 등록하며 실제 차트나 컨테이너 이미지 자체를 게시하지 않습니다.

필요한 접근과 인증 정보

CI 실행 환경에서 Apollo 허브와 아티팩트 레지스트리에 접근할 수 있어야 합니다. 조직 내부 네트워크에서 CI를 실행한다면 허브 접근을 위한 외부 통신용 IP 허용 목록도 준비합니다.

CLI 인증은 다음 중 하나를 사용합니다.

방식CI에서 준비할 정보CLI 인증 옵션
Bearer 토큰(Bearer token)비밀 정보 APOLLO_TOKEN--apollo-token
서비스 계정클라이언트 ID(client ID)와 클라이언트 비밀값(client secret)--apollo-client-id, --apollo-client-secret

두 방식을 동시에 설정하지 않습니다. CI의 계정에는 대상 제품의 릴리스를 생성할 권한이 필요하며, 새 제품을 만들려면 제품 생성에 필요한 권한도 있어야 합니다.

허브 주소는 --apollo-url로 전달합니다. 제품 릴리스의 Maven 좌표는 groupID:artifactID:version 형식이며, Helm 차트 제품을 초기화할 때 --maven-coordinate로 지정합니다.

CI에서 CLI를 준비하는 방법

CLI를 사용할 수 있도록 만드는 방법은 네 가지입니다.

  • CI 작업 중 허브에서 직접 다운로드합니다. 권장되는 방법입니다.
  • 허브에서 받은 바이너리를 CI 실행 머신이 접근할 수 있는 위치에 보관합니다.
  • 코드 저장소에 CLI 바이너리를 포함합니다.
  • CLI가 포함된 Docker 이미지를 CI 작업 이미지로 사용합니다.

직접 다운로드할 때는 허브의 운영체제별 바이너리 경로를 사용합니다. 아래 명령은 APOLLO_URL에 끝의 /가 없는 허브 URL을, OS_DISTRIBUTION에 대상 배포판 식별자를 지정한다고 가정합니다. 이후 GitLab 예시는 Linux AMD64 실행 환경을 대상으로 linux-amd64를 사용합니다.

Bearer 토큰으로 다운로드

CLI_DOWNLOAD_TOKEN="${APOLLO_TOKEN}"

서비스 계정으로 다운로드

서비스 계정의 경우 Multipass에 클라이언트 인증 정보 방식(client credentials grant)으로 요청하여 다운로드에 사용할 Bearer 토큰을 얻습니다. 이 단계에는 curl과 jq가 필요합니다.

CLI_DOWNLOAD_TOKEN="$(
  curl --fail --silent --show-error \
    "${APOLLO_URL}/multipass/api/oauth2/token" \
    --header 'content-type: application/x-www-form-urlencoded' \
    --data-urlencode 'grant_type=client_credentials' \
    --data-urlencode "client_id=${CLIENT_ID}" \
    --data-urlencode "client_secret=${CLIENT_SECRET}" \
    | jq -er '.access_token'
)"

다운로드용 토큰과 이후 CLI의 인증 방식을 구분하여 관리합니다. 서비스 계정으로 CLI를 실행할 때는 클라이언트 ID와 클라이언트 비밀값을 전달하고 Bearer 토큰 옵션을 함께 전달하지 않습니다.

바이너리 받기

위 두 방식 중 하나로 CLI_DOWNLOAD_TOKEN을 준비한 뒤 다음 명령을 실행합니다.

curl --fail --silent --show-error --location \
  --output apollo-cli \
  --header "authorization: Bearer ${CLI_DOWNLOAD_TOKEN}" \
  "${APOLLO_URL}/assets/dyn/apollo-cli/bin/${OS_DISTRIBUTION}/apollo-cli"
chmod 700 apollo-cli

차트를 제품 릴리스로 등록하기

Helm 차트는 허브의 아티팩트 저장소나 외부 Artifactory, Harbor 등의 저장소에 게시할 수 있습니다. helm-chart init의 --repository-url은 차트가 있는 저장소를 지정합니다. 원격 OCI 차트의 --name에는 차트까지 포함한 전체 OCI URL을 사용합니다.

다음 Bash 예시는 이미 저장소에 게시된 가상의 apollo-demo-chart를 제품 com.example:apollo-demo-app으로 등록합니다. RELEASE_VERSION은 게시한 차트 버전이며, 레지스트리 사용자 이름과 비밀번호는 CI의 비밀 정보로 제공한다고 가정합니다.

먼저 선택한 인증 방식에 맞는 인수를 준비합니다. Bearer 토큰 방식은 다음과 같습니다.

apollo_auth=(
  --apollo-url "${APOLLO_URL}"
  --apollo-token "${APOLLO_TOKEN}"
)

서비스 계정 방식에서는 위 배열 대신 다음 배열을 사용합니다.

apollo_auth=(
  --apollo-url "${APOLLO_URL}"
  --apollo-client-id "${CLIENT_ID}"
  --apollo-client-secret "${CLIENT_SECRET}"
)

이후 차트 정보를 초기화하고 제품 릴리스를 등록합니다.

./apollo-cli product-release helm-chart init \
  "${apollo_auth[@]}" \
  --maven-coordinate "com.example:apollo-demo-app:${RELEASE_VERSION}" \
  --name "oci://${HUB_ARTIFACT_STORE_HOST}/apollo-demo-chart" \
  --version "${RELEASE_VERSION}" \
  --repository-url "oci://${HUB_ARTIFACT_STORE_HOST}/apollo-demo-chart" \
  --username "${HUB_ARTIFACT_STORE_USER}" \
  --password "${HUB_ARTIFACT_STORE_PASS}" \
  --output-dir "./chart"

./apollo-cli product-release create \
  "${apollo_auth[@]}" \
  --manifest "./chart/manifest.yml"

두 CLI 실행에 허브 URL과 선택한 인증 정보를 명시적으로 전달합니다. 레지스트리의 --username, --password는 차트를 가져오기 위한 인증 정보이며 Apollo 허브에 접근할 Bearer 토큰 또는 서비스 계정과 용도가 다릅니다.

기존 CI에 통합할 때는 차트를 게시한 작업 뒤에 이 초기화와 등록 작업을 추가할 수 있습니다.

전체 GitLab CI 예시

아래는 컨테이너 이미지 게시, Helm 차트 게시, Apollo 릴리스 등록을 연결한 예시입니다. 입력 조건은 다음과 같습니다.

  • 저장소 루트에 애플리케이션의 Dockerfile이 있습니다.
  • helm-chart/Chart.yaml의 차트 이름은 apollo-demo-chart입니다.
  • 차트가 values.yaml의 imageVersion을 컨테이너 이미지 태그로 사용합니다. 이미지 저장소는 게시할 apollo-demo-app 경로로 구성되어 있어야 합니다.
  • Git 태그는 2.0.0처럼 차트 버전으로 사용할 수 있는 Semantic Versioning 값입니다.
  • apollo-ci 태그가 있는 Linux AMD64 GitLab Docker executor Runner를 사용합니다.
  • Docker-in-Docker를 실행할 Runner에는 privileged = true와 서비스 및 작업 컨테이너가 공유할 /certs/client 볼륨이 설정되어 있습니다. 권한이 높은 컨테이너를 실행하므로 조직이 허용한 Runner에서 사용합니다.

다음 값을 CI 변수로 등록합니다. 인증 정보는 비밀 정보로 관리하며 저장소의 YAML에 직접 넣지 않습니다.

변수값
APOLLO_URL끝의 /가 없는 Apollo 허브 URL
APOLLO_TOKENApollo API에 접근할 Bearer 토큰
HUB_ARTIFACT_STORE_HOSTOCI 레지스트리 호스트. 예를 들어 허브의 컨테이너 저장소 호스트
HUB_ARTIFACT_STORE_USER레지스트리 사용자 이름
HUB_ARTIFACT_STORE_PASS레지스트리 비밀번호

예시는 Docker CLI와 Docker-in-Docker의 버전을 29.9.1로 맞추고, 차트 작업에는 alpine/helm:4.3.1을 사용합니다. Helm 이미지에는 curl, Bash, Git과 Go 기반 yq가 포함되어 있습니다. Helm 이미지의 기본 진입점은 helm이므로 GitLab 작업 스크립트를 실행하도록 entrypoint를 비웁니다.

stages:
  - build_and_push_container
  - build_and_push_helm_chart
  - publish_helm_chart_apollo

default:
  tags:
    - apollo-ci

.release_job:
  rules:
    - if: '$CI_COMMIT_TAG'

build_and_push_container:
  extends: .release_job
  stage: build_and_push_container
  image: docker:29.9.1-cli
  services:
    - name: docker:29.9.1-dind
      alias: docker
      variables:
        HEALTHCHECK_TCP_PORT: "2376"
  variables:
    DOCKER_HOST: tcp://docker:2376
    DOCKER_TLS_CERTDIR: /certs
    DOCKER_TLS_VERIFY: "1"
    DOCKER_CERT_PATH: /certs/client
  before_script:
    - docker info
    - |
      set -eu
      printf '%s' "${HUB_ARTIFACT_STORE_PASS}" | docker login \
        "${HUB_ARTIFACT_STORE_HOST}" \
        --username "${HUB_ARTIFACT_STORE_USER}" --password-stdin
  script:
    - |
      set -eu
      export RELEASE_VERSION="${CI_COMMIT_TAG}"
      docker build \
        --tag "${HUB_ARTIFACT_STORE_HOST}/apollo-demo-app:${RELEASE_VERSION}" .
      docker push "${HUB_ARTIFACT_STORE_HOST}/apollo-demo-app:${RELEASE_VERSION}"

build_and_push_helm_chart:
  extends: .release_job
  stage: build_and_push_helm_chart
  image:
    name: alpine/helm:4.3.1
    entrypoint: [""]
  script:
    - |
      set -eu
      export RELEASE_VERSION="${CI_COMMIT_TAG}"
      yq -i '.imageVersion = strenv(RELEASE_VERSION)' helm-chart/values.yaml
      cd helm-chart
      helm package . \
        --version "${RELEASE_VERSION}" \
        --app-version "${RELEASE_VERSION}"
      printf '%s' "${HUB_ARTIFACT_STORE_PASS}" | helm registry login \
        "${HUB_ARTIFACT_STORE_HOST}" \
        --username "${HUB_ARTIFACT_STORE_USER}" --password-stdin
      helm push "apollo-demo-chart-${RELEASE_VERSION}.tgz" \
        "oci://${HUB_ARTIFACT_STORE_HOST}"
  artifacts:
    paths:
      - helm-chart/*.tgz
      - helm-chart/values.yaml

publish_helm_chart_apollo:
  extends: .release_job
  stage: publish_helm_chart_apollo
  image:
    name: alpine/helm:4.3.1
    entrypoint: [""]
  dependencies:
    - build_and_push_helm_chart
  before_script:
    - |
      set -eu
      curl --fail --silent --show-error --location \
        --output apollo-cli \
        --header "authorization: Bearer ${APOLLO_TOKEN}" \
        "${APOLLO_URL}/assets/dyn/apollo-cli/bin/linux-amd64/apollo-cli"
      chmod 700 apollo-cli
  script:
    - |
      set -eu
      export RELEASE_VERSION="${CI_COMMIT_TAG}"
      ./apollo-cli product-release helm-chart init \
        --apollo-url "${APOLLO_URL}" \
        --apollo-token "${APOLLO_TOKEN}" \
        --chart-path "helm-chart/apollo-demo-chart-${RELEASE_VERSION}.tgz" \
        --repository-url "oci://${HUB_ARTIFACT_STORE_HOST}" \
        --maven-coordinate "com.example:apollo-demo-app:${RELEASE_VERSION}" \
        --output-dir "./chart"
      set -- \
        --apollo-url "${APOLLO_URL}" \
        --apollo-token "${APOLLO_TOKEN}" \
        --manifest "./chart/manifest.yml" \
        --default-config "helm-chart/values.yaml"
      if [ -f helm-chart/values.schema.json ]; then
        set -- "$@" --config-schema "helm-chart/values.schema.json"
      fi
      ./apollo-cli product-release create "$@"

CI_COMMIT_TAG를 세 단계에서 같은 RELEASE_VERSION으로 사용하므로 컨테이너 이미지 태그, 차트 버전, appVersion과 Apollo 제품 릴리스 버전이 연결됩니다. imageVersion은 문자열로 갱신하며, 태그 값을 숫자로 해석하지 않습니다.

dependencies는 차트 게시 작업의 아티팩트만 가져오도록 지정합니다. 마지막 작업은 앞 단계에서 패키징한 차트를 --chart-path로 읽으므로 이름과 버전을 그 패키지에서 얻습니다. 함께 전달한 values.yaml은 같은 빌드에서 갱신한 기본 구성값입니다. 차트의 선택적 values.schema.json이 있으면 기본 구성값과 함께 등록합니다.

rules는 태그 파이프라인에서만 세 작업을 실행합니다. 모든 커밋에서 게시하려면 실행 규칙을 바꾸고, 각 빌드에 사용할 유효하고 고유한 릴리스 버전도 정해야 합니다.

게시가 완료되면 Apollo 왼쪽 메뉴의 Products에서 제품 카탈로그를 열고 해당 제품 홈에서 새 릴리스를 확인할 수 있습니다. 실제 배포 환경이 아티팩트를 가져오려면 그 환경에 필요한 레지스트리 접근도 설정되어 있어야 합니다.