이 내용은 docker-compose를 통해 구성한 Gitlab을 Kubernetes 환경으로 전환하기 위한 과정을 정리하였다.

- Install Gitlab using Helm

Chart

kubectl create ns gitlab

helm repo add gitlab https://charts.gitlab.io/
helm repo update

최상단 values.yaml 파일 수정

global:
  hosts:
    domain: bys.asia

  ## https://docs.gitlab.com/charts/charts/globals#configure-ingress-settings
  ingress:
    # apiVersion: ""
    # configureCertmanager: true
    # provider: nginx
    class: alb
    annotations:
      alb.ingress.kubernetes.io/group.name: gitlab
      alb.ingress.kubernetes.io/subnets: subnet-03720d77c88c997f3, subnet-0810de67a8498a53d
      alb.ingress.kubernetes.io/scheme : internet-facing
      alb.ingress.kubernetes.io/security-groups: shared-sg-alb-gitlab
      alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS13-1-2-2021-06
      alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-2:202949997891:certificate/57b91a03-9fb1-4f3a-a192-94ab30a5e105
      alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
      alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": {"Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
      alb.ingress.kubernetes.io/healthcheck-path: /
      alb.ingress.kubernetes.io/healthcheck-interval-seconds: '15'
      alb.ingress.kubernetes.io/healthcheck-timeout-seconds: '10'
      alb.ingress.kubernetes.io/healthy-threshold-count: '2'
      alb.ingress.kubernetes.io/unhealthy-threshold-count: '4'
      alb.ingress.kubernetes.io/healthcheck-port: traffic-port
      alb.ingress.kubernetes.io/success-codes: 200,301,302
      alb.ingress.kubernetes.io/target-type: ip
    enabled: true
    tls: {}

    path: /
    extraPaths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: ssl-redirect
            port:
              name: use-annotation
    pathType: Prefix


## Settings to for the Let's Encrypt ACME Issuer
certmanager-issuer:
#   # The email address to register certificates requested from Let's Encrypt.
#   # Required if using Let's Encrypt.
  email: skwltg90@naver.com


## https://docs.gitlab.com/charts/charts/nginx/
## https://docs.gitlab.com/charts/architecture/decisions#nginx-ingress
## Installation & configuration of charts/ingress-nginx:
nginx-ingress: &nginx-ingress
  enabled: false

## Installation & configuration of gitlab/gitlab-runner
## See requirements.yaml for current version
# bys
gitlab-runner:
  install: false
# Redis
redis:
  master:
    persistence:
      size: 30Gi
  replica:
    persistence:
      size: 30Gi

# Minio
minio:
  persistence:
    size: 20Gi

# Postgresql
postgresql:
  primary:
    persistence:
      size: 30Gi
  readReplicas:
    persistence:
      size: 30Gi

## Prometheus
prometheus:
  server:
    persistentVolume:
      size: 30Gi

gitlab:
  gitaly:
    persistence:
      size: 80Gi

위 와 같이 values.yaml 파일을 수정한다. Chart의 구조상 Dependency가 있는 Chart에 대해서는 Chart의 이름: 에서 values.yaml파일의 값을 다시 수정한다.


- Install Gitlab using Helm

helm repo update gitlab
helm upgrade --install gitlab gitlab/gitlab --namespace gitlab -f /Users/bys/workspace/kubernetes/gitlab/latest/values.yaml
helm upgrade --install gitlab gitlab/gitlab --namespace gitlab --version 8.11.1 -f /Users/bys/workspace/kubernetes/gitlab/latest/values.yaml

위 커맨드를 통해 설치시 AWS Load Balancer Controller를 통해 ALB가 설치된다. Nginx ingress를 사용하지 않고 ALB를 통해 서비스하기 위해서 사용한다. 또한 내부적으로 PVC 볼륨 사이즈 값들을 수정하였는데 remote가 아닌 수정된 내부 Chart values 파일을 적용하기 위해서는 pull 받은 디렉토리의 경로에서 차트를 실행시킨다.

kubectl get secrets gitlab-gitlab-initial-root-password -n gitlab -o jsonpath={.data.password}|base64 -d


TroubleShooting

- Kaniko의 ECR Credential 설정

빌드 수행 전 echo 커맨드를 통해 /kaniko/.docker/config.json 파일안에 ecr-login을 통해 자격증명 설정을 해준다. kaniko 이미지에는 기본적으로 ECR credential helper가 설치되어 있는 것으로 확인된다.

The Amazon ECR credential helper is built into the kaniko executor image.

gitlab-ci.yml

### Kaniko Build
- mkdir -p /kaniko/.docker
- echo "{"credsStore":"ecr-login","credHelpers":{"$REGISTRY_URL":"ecr-login"}}" > /kaniko/.docker/config.json

- /kaniko/executor
  --ignore-path=/var/mail
  --ignore-path=/var/spool/mail
  --context "${CI_PROJECT_DIR}"
  --dockerfile "${CI_PROJECT_DIR}/${DOCKER_FILE_NAME}"
  --destination "${ECR_BASE_URL}/${DOCKER_ECR_IMAGE_REPO}:${BASE_IMAGE_TAG}"


- Kubernetes executor, Runner 설정

Image를 Pull, Push 하기 위해서는 nerdctl 커맨드를 사용하여야 했는데 containerd 런타임을 통해 수행되기 때문에 노드의 containerd.sock을 마운트하여 사용할 수 있도록 한다.

containerd is a high-level container runtime. To put it simply, it’s a daemon that manages the complete container lifecycle on a single host: creates, starts, stops containers, pulls and stores images, configures mounts, networking, etc.

values.yaml

[[runners]]
  [runners.kubernetes]
  image = "202949997891.dkr.ecr.ap-northeast-2.amazonaws.com/common/build:kaniko-debug"
  pull_policy = ["always", "if-not-present"]
  [[runners.kubernetes.volumes.host_path]]
    name = "containerdsock"
    mount_path = "/run/containerd/containerd.sock"
    read_only = true
    host_path = "/run/containerd/containerd.sock"
  [runners.cache]

test

concurrent = 10
check_interval = 15
[[runners]]
  name = "standard-runner"
  executor = "kubernetes"
  tags = ["standard", "default"]
  [runners.kubernetes]
    image = "202949997891.dkr.ecr.ap-northeast-2.amazonaws.com/common/build:kaniko-debug"
    pull_policy = ["always", "if-not-present"]
    namespace = "gitlab"
    cpu_request="2"
    cpu_limit = "2"
    memory_request= "4Gi"
    memory_limit = "4Gi"

    [runners.kubernetes.node_selector]
      "karpenter.sh/nodepool" = "al2023-np"

    [[runners.kubernetes.volumes.host_path]]
      name = "containerdsock"
      mount_path = "/run/containerd/containerd.sock"
      read_only = true
      host_path = "/run/containerd/containerd.sock"

만약, 캐시를 사용하고 싶다면 Advanced configuration 문서를 참고할 수 있다.

[runners.cache]
  Type = "s3"
  Path = "path/to/prefix"
  Shared = false
  [runners.cache.s3]
    ServerAddress = "s3.amazonaws.com"
    AccessKey = "AWS_S3_ACCESS_KEY"
    SecretKey = "AWS_S3_SECRET_KEY"
    BucketName = "runners-cache"
    BucketLocation = "eu-west-1"
    Insecure = false
    ServerSideEncryption = "KMS"
    ServerSideEncryptionKeyID = "alias/my-key"


- Kubernetes Runner 추가 등록

Gitlab을 설치할 때 사용한 values.yaml 파일을 이용하면 Runners 가 하나만 등록 가능한 것으로 보이기 때문에 별도의 gitlab-runner를 추가로 등록한다. 아래의 Runner는 큰 규모의 빌드(Ex. jupyter-spark 이미지)를 실행하기 위한 러너다. 아래의 러너는 tags로 high, large 를 가지고 있다. 추후 gitlab-ci.yml 파일에서 tags를 통해 아래의 runner 와 맵핑할 수 있다. 추가적으로 runners.kubernetes.node_selector 를 통해 어떤 노드에서 실행시킬지 Karpenter 노드 풀을 지정하고 있으므로 추가적으로 EBS 볼륨의 스펙까지 컨트롤 할 수 있다.

GitLab Runner

large-values.yaml

serviceAccount:
  create: false
  name: "gitlab-gitlab-runner"
runnerToken: "glrt-dDoxCnU6Mm4qVIah8DUHQOZUpY-kC5cQ.0w1ruk0xi"
runners:
  config: |
    concurrent = 10
    check_interval = 15
    [[runners]]
      name = "gitlab-runner-large"
      executor = "kubernetes"
      url= "https://gitlab.bys.asia"
      tags = ["high", "large"]
      [runners.kubernetes]
        image = "202949997891.dkr.ecr.ap-northeast-2.amazonaws.com/common/build:kaniko"
        pull_policy = ["always", "if-not-present"]
        namespace = "gitlab"
        cpu_request="8"
        cpu_limit = "8"
        memory_request= "16Gi"
        memory_limit = "16Gi"
        [runners.kubernetes.node_selector]
          "karpenter.sh/nodepool" = "al2023-large-np"

        [[runners.kubernetes.volumes.host_path]]
          name = "containerdsock"
          mount_path = "/run/containerd/containerd.sock"
          read_only = true
          host_path = "/run/containerd/containerd.sock"
helm search repo -l gitlab/gitlab-runner
helm repo update gitlab
helm upgrade --install gitlab-runner-large gitlab/gitlab-runner -n gitlab -f /Users/bys/workspace/kubernetes/gitlab/latest/gitlab-runner-large-values.yaml

Gitlab 에서 분리하여 일반 standard 러너도 별도로 관리하기로 변경 하였다. runnerToken은 Gitlab 콘솔에서 Runner 인스턴스를 생성하면 조회할 수 있다.
standard-values.yaml

serviceAccount:
  create: false
  name: "gitlab-runner"
runnerToken: "glrt-4vtXro-fT0J3GalIJkOXKHQ6MQp1OjIH.01.0w186pwti"
runners:
  config: |
    concurrent = 10
    check_interval = 15
    [[runners]]
      name = "gitlab-runner-standard"
      executor = "kubernetes"
      url= "https://gitlab.bys.asia"
      [runners.kubernetes]
        image = "202949997891.dkr.ecr.ap-northeast-2.amazonaws.com/common/build:kaniko"
        pull_policy = ["always", "if-not-present"]
        namespace = "gitlab"
        cpu_request="2"
        cpu_limit = "2"
        memory_request= "4Gi"
        memory_limit = "4Gi"
        [runners.kubernetes.node_selector]
          "karpenter.sh/nodepool" = "al2023-np"

        [[runners.kubernetes.volumes.host_path]]
          name = "containerdsock"
          mount_path = "/run/containerd/containerd.sock"
          read_only = true
          host_path = "/run/containerd/containerd.sock"
helm search repo -l gitlab/gitlab-runner
helm repo update gitlab
helm upgrade --install gitlab-runner-standard gitlab/gitlab-runner -n gitlab -f /Users/bys/workspace/kubernetes/gitlab/latest/gitlab-runner-standard-values.yaml


- Gitlab 구성 요소에 대한 역할


- Mirroring Repositories

https를 통해 엔드포인트 연결 시에는 username/password 방식으로 동작해야 한다. Github에 연결할 때는 패스워드 인증 기능이 되지 않기 때문에 username에는 사용자, password에는 token을 입력한다.


- EKS on Gitlab v17 에서 v18로 업그레이드

Gitlab 17 버전에서 18버전으로 업그레이드 할 때는 helm upgrade 를 통해 업그레이드가 되지 않는다. 여러가지 오류들이 발생하며 PostgreSQL을 16버전으로 업그레이드 먼저 해주어야 하는 것을 알게되었다.

태그를 확인하여 현 시점에서 최신 버전인 Version v9.1.1 - contains GitLab EE 18.1.1을 확인했다.

# GITLAB_RELEASE should be the version of the chart you are installing, starting with 'v': v6.0.0
GITLAB_RELEASE=v9.1.1


## 1. DB 백업 단계
curl -O https://gitlab.com/gitlab-org/charts/gitlab/-/raw/${GITLAB_RELEASE}/scripts/database-upgrade
bash database-upgrade -r gitlab -n gitlab pre


# 2. Delete existing PostgreSQL data
kubectl delete statefulset RELEASE-NAME-postgresql
kubectl delete pvc data-RELEASE_NAME-postgresql-0


# 3. Upgrade GitLab
helm upgrade --install gitlab gitlab/gitlab --namespace gitlab \
--set gitlab.migrations.enabled=false \
-f /Users/bys/workspace/kubernetes/gitlab/latest/values.yaml

## 4. DB 복구 단계
kubectl rollout status -w deployment/gitlab-toolbox -n gitlab
bash database-upgrade -r gitlab -n gitlab post

DB 백업 단계에서 S3쪽(gitlab-backup)으로 업로드가 되지 않아서 생성된 데이터를 toobox 컨테이너 내부로 접속하여 S3 Presigned URL을 통해 직접 업로드 했다. 이 후 DB 복구 단계에서 post를 호출할 때 -f 옵션을 통해 Presigned URL을 추가해서 백업 파일을 직접 다운 받을 수 있도록 database-upgrade 스크립트를 수정해서 수행했다.

post() {
......
# Restore the database
    in_toolbox backup-utility --restore -t "${fake_timestamp}" --skip registry,uploads,artifacts,lfs,packages,external_diffs,terraform_state,ci_secure_files,repositories -f <PresignedURL>

}

이 작업을 통해 Gitlab 18 버전으로 정상적인 마이그레이션을 할 수 있었다. 18버전에서 오류가 발생하여 17버전으로 Helm Rollback을 한 경우에도 이미 데이터베이스 스키마가 망가져서 파이프라인 정보나 이런 것들도 조회가 되지 않았다. 아예 18버전으로 데이터 마이그레이션 까지 해서 띄우는 것이 좋다.

이 후 권한이슈가 일부 있어서 Runner 설정을 변경했다. Runner는 Gitlab 과 분리하여 별도의 차트로 관리하게 하고 SA와 Role을 정리했다. Role은 문서 참고.