Overview
Gitlab CI를 사용해서 Build 후 GCP Artifact Registry와 Harbor에 업로드 하는 방법에 대해서 알아본다.
Gitlab CI Build and Push(with GCP Artifact Registry, Harbor)
dockerConfigJson 작성
Harbor
- 사용자 이름과 비밀번호 인코딩: `echo -n` 을 사용하여 사용자 이름과 비밀번호를 한 줄로 출력하고, `base64` 명령으로 인코딩한다. `n` 옵션은 라인 끝의 개행문자를 제거한다.
- JSON 파일 생성: `cat <<EOF > config.json` 를 사용하여 다중 라인의 텍스트를 `config.json` 파일로 리다이렉션한다. 변수 `$AUTH` 는 이전 단계에서 생성된 인코딩된 문자열을 사용한다.
- 전체 JSON 파일 인코딩: `cat config.json` 으로 파일을 읽고, ` base64` 로 인코딩한 다음, `tr -d '\\n'` 으로 인코딩된 문자열에서 개행 문자를 제거한다.
- Kubernetes Secret 생성용 YAML 파일 준비: 위와 비슷한 방식으로 `YAML` 파일을 생성하며, 이 파일은 Kubernetes에서 사용할 수 있다.
사용자 이름과 비밀번호를 인코딩한다.
AUTH=$(echo -n 'somaz:somaz@2024' | base64)
JSON 파일을 생성한다.
cat <<EOF > config.json
{
"auths": {
"your.harbor.domain": {
"username": "somaz",
"password": "somaz@2024",
"email": "somaz.link",
"auth": "$AUTH"
}
}
}
EOF
# 한줄작성
echo '{"auths":{"your.harbor.domain":{"username":"somaz","password":"somaz@2024","email":"somaz.link","auth":"'"$AUTH"'"}}}' > config.json
전체 JSON 파일을 BASE64로 한번더 인코딩한다.
# JSON 파일을 BASE64로 인코딩
ENCODED_JSON=$(cat config.json | base64 -w 0)
or
# 둘중 하나 선택
ENCODED_JSON=$(cat config.json | base64 -w 0 | tr -d '\\n')
# 확인
echo $ENCODED_JSON
eyJhdXRocyI6eyJ5b3VyLmhhcmJvci5kb21haW4iOnsidXNlcm5hbWUiOiJzb21heiIsInBhc3N3b3JkIjoic29tYXpAMjAyNCIsImVtYWlsIjoic29tYXoubGluayIsImF1dGgiOiJjMjl0WVhvNmMyOXRZWHBBTWpBeU5BPT0ifX19Cg==
echo "eyJhdXRocyI6eyJ5b3VyLmhhcmJvci5kb21haW4iOnsidXNlcm5hbWUiOiJzb21heiIsInBhc3N3b3JkIjoic29tYXpAMjAyNCIsImVtYWlsIjoic29tYXoubGluayIsImF1dGgiOiJjMjl0WVhvNmMyOXRZWHBBTWpBeU5BPT0ifX19Cg==" |base64 -d -w 0
{"auths":{"your.harbor.domain":{"username":"somaz","password":"somaz@2024","email":"somaz.link","auth":"c29tYXo6c29tYXpAMjAyNA=="}}}
마지막으로 Kubernetes Secret 생성용 YAML 파일 준비한다.
cat <<EOF > k8s-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: myregistrykey
namespace: default
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: $ENCODED_JSON
EOF
Google Artifact Registry
- Docker 로그인 실행 : 로컬에서 `serviceaccount.json` 파일을 사용하여 Docker 로그인을 수행하고, 결과로 생성된 `config.json` 파일을 생성한다.
- dockerconfigjson 파일 준비 : 로그인 후 생성된 `~/.docker/config.json` 파일을 `base64` 로 인코딩한다. 인코딩된 결과는 Helm의 values 파일에 사용된다.
- Kubernetes Secret 생성 : 인코딩된 `dockerconfigjson`를 Helm 차트의 values 파일에 삽입하여 Kubernetes에서 사용할 수 있는 Secret을 생성한다.
`serviceaccount.json` 파일을 사용하여 로컬에서 `dockerconfigjson` 을 생성해본다.
export REGION=<YOUR-REGION>
cat serviceaccount.json | docker login -u _json_key --password-stdin https://$REGION.pkg.dev
생성된 `config.json` 파일의 내용을 복사하여 Helm values 파일의 `artifactregistry.dockerConfigJson` 필드에 `base64` 인코딩된 형태로 삽입한다.
cat ~/.docker/config.json | base64 -w 0
Kubernetes Secret을 생성한다. 이번에는 Helm Chart를 사용해본다. template을 먼저 생성한다.
`gcp-ar-secret.yaml`
{{- if .Values.artifactregistry.enabled }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "somaz.fullname" . }}
namespace: {{ .Release.Namespace }}
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: {{ .Values.artifactregistry.dockerConfigJson }}
{{- end }}
`values.yaml`
image:
repository: <region>-docker.pkg.dev/mgmt-2023/<repo name>/<image name>
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: "<image Tag>"
imagePullSecrets:
- name: <image pull secret name>
artifactregistry:
enabled: false
dockerConfigJson: "BASE64_ENCODED_JSON_HERE"
Gitlab CI 작성
Build에는 Kaniko를 사용한다. GCP Artifact Registry와 Harbor를 상황에 맞게 사용할 수 있는 Gitlab Ci를 작성해본다.
Harbor & GCP ArtifactRegistry
Namespace에 `somaz-` 가 들어가면 GCP로 Upload 하고, 그 이외의 값이 들어가면 Harbor로 업로드 하게 된다. Predefined 변수를 제외하곤 Gitlab Variables 값에 넣어줘야 한다.
stages:
- gcloud
- build # buld images & push to private image registry at once
# 스크립트에서 사용할 변수 설정
# CI_COMMIT_REF_NAME 파이프라인 실행하는 현재 브랜치명
variables:
NAMESPACE:
value: "dev1"
description: "Select the namespace: dev1 or dev2 or staging(use deploy)"
options:
- "dev1"
- "dev2"
- "staging"
- "qa1"
- "somaz-dev"
SERVICE:
value: "game"
description: "Select admin or game or batch or etc."
options:
- "game"
- "admin"
CI_REGISTRY_IMAGE: $CI_REGISTRY/$SERVICE
BUILD_TAG: $CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA
IMAGE_URL: '${CI_REGISTRY_IMAGE}:${BUILD_TAG}'
BUILD_TAG_LATEST: $CI_COMMIT_REF_NAME-latest
IMAGE_URL_LATEST: '${CI_REGISTRY_IMAGE}:${BUILD_TAG_LATEST}'
GCP_CI_REGISTRY_IMAGE: '$GCP_CI_REGISTRY/${SERVICE}-fgn/${SERVICE}-fgn'
GCP_IMAGE_URL: '${GCP_CI_REGISTRY_IMAGE}:${BUILD_TAG}'
GCP_IMAGE_URL_LATEST: '${GCP_CI_REGISTRY_IMAGE}:${BUILD_TAG_LATEST}'
gcloud:
stage: gcloud
image:
name: gcr.io/google.com/cloudsdktool/google-cloud-cli:latest
variables:
CLOUDSDK_CONFIG: $CI_PROJECT_DIR/gcloud
before_script:
- echo [INFO] Start gcloud config setting.
- echo [INFO] GCP_SERVICE_ACCOUNT is $GCP_SERVICE_ACCOUNT
- echo [INFO] CLOUDSDK_CONFIG is $CLOUDSDK_CONFIG
- echo [INFO] GCP_CI_REGISTRY is $GCP_CI_REGISTRY
- mkdir -p ${CLOUDSDK_CONFIG}
script:
- echo $GCP_SERVICE_ACCOUNT_KEY_BASE64 | base64 --decode > ${CLOUDSDK_CONFIG}/gcloud-service-key.json
- gcloud auth activate-service-account --key-file=${CLOUDSDK_CONFIG}/gcloud-service-key.json
- token=$(gcloud auth print-access-token)
- docker_token=$(echo -n "gclouddockertoken:$token" | base64 | tr -d "\\n")
- echo "{\\"auths\\":{\\"$GCP_CI_REGISTRY\\":{\\"auth\\":\\"$docker_token\\",\\"email\\":\\"admin@nerdystar.io\\"}}}" > gcloud/config.json
artifacts:
paths:
- gcloud/config.json
rules:
- if: '$NAMESPACE =~ /^somaz-/'
when: on_success
- when: never
tags:
- build-image
# web에서 수동 빌드 시 사용
build_manual_image:
stage: build
image:
name: gcr.io/kaniko-project/executor:v1.22.0-debug
# entrypoint 는 명시적으로 "" 빈 스트링 지정해야함.
entrypoint: [""]
before_script:
- echo [INFO] Start build image.
- echo [INFO] CI_REGISTRY is $CI_REGISTRY
- echo [INFO] CI_REGISTRY_IMAGE is $CI_REGISTRY_IMAGE
- echo [INFO] CI_COMMIT_REF_NAME is $CI_COMMIT_REF_NAME
- echo [INFO] BUILD_TAG is $BUILD_TAG
- echo [INFO] IMAGE_URL is $IMAGE_URL
- echo [INFO] BUILD_TAG_LATEST is $BUILD_TAG_LATEST
- echo [INFO] IMAGE_URL_LATEST is $IMAGE_URL_LATEST
- echo [INFO] CI_PROJECT_DIR is $CI_PROJECT_DIR
- echo [INFO] SERVICE is $SERVICE
- echo [INFO] GCP Config
- echo [INFO] GCP_CI_REGISTRY is $GCP_CI_REGISTRY
- echo [INFO] GCP_CI_REGISTRY_IMAGE is $GCP_CI_REGISTRY_IMAGE
- echo [INFO] GCP_IMAGE_URL is $GCP_IMAGE_URL
- echo [INFO] GCP_IMAGE_URL_LATEST is $GCP_IMAGE_URL_LATEST
- echo [INFO] NAMESPACE is $NAMESPACE
# registry 접속 정보를 저장하기 위한 디렉토리 생성
- mkdir -p /kaniko/.docker
# private 레지스트리에 대한 접속 정보 지정
- >
if [[ "$NAMESPACE" =~ ^somaz- ]]; then
echo "Configuring registry for special namespace $NAMESPACE"
# echo $GCP_SERVICE_ACCOUNT_KEY_BASE64 | base64 -d > /kaniko/.docker/config.json
cp gcloud/config.json /kaniko/.docker/config.json
else
echo "{\\"auths\\":{\\"$CI_REGISTRY\\":{\\"auth\\":\\"$(echo -n ${CI_REGISTRY_USER}:${CI_REGISTRY_PASSWORD} | base64)\\"}}}" > /kaniko/.docker/config.json
fi
script:
- >
if [[ "$NAMESPACE" =~ ^somaz- ]]; then
# somaz-가 포함된 NAMESPACE용 설정
echo "Using special build settings for $NAMESPACE"
/kaniko/executor --cache=true --cache-ttl=24h --snapshot-mode=redo --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/$SERVICE.Dockerfile --destination $GCP_IMAGE_URL --destination $GCP_IMAGE_URL_LATEST --build-arg NODE_ENV=$CI_COMMIT_REF_NAME --skip-tls-verify
else
/kaniko/executor --cache=true --cache-ttl=24h --snapshot-mode=redo --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/$SERVICE.Dockerfile --destination $IMAGE_URL --destination $IMAGE_URL_LATEST --build-arg NODE_ENV=$CI_COMMIT_REF_NAME --skip-tls-verify
fi
rules:
- if: '($CI_PIPELINE_SOURCE == "web")'
tags:
- build-image
Gitlab Runner 관련해서는 아래의 게시물 참고하면 된다.
2023.04.18 - [IaC/CI CD Tool] - 2. GitLab이란? / GitLab Runner 개념 및 설치
Reference
'IaC > CI CD Tool' 카테고리의 다른 글
8. Github Action Template 생성후 MarketPlace 등록하기 (2) | 2024.07.01 |
---|---|
7. Gitlab CI Template 활용 (0) | 2024.06.27 |
7. Github Action Build and Push(with GCP Artifact Registry) (0) | 2024.06.19 |
ArgoCD SSO 구성 가이드(GCP Oauth) (0) | 2024.04.14 |
6. Github Action (With Using Concurrency) (0) | 2024.03.20 |