Featured image of post Установка Gitlab в Offline Kubernetes

Установка Gitlab в Offline Kubernetes

Пошаговая инструкция по установке Gitlab CI

Хранить кучу манифестов кубера и кусков кода в блокноте плохая идея. Непонятно, где тут источник правды?
Для этого используются Git репозитории. В этом гайде мы выполним установку Gitlab в кластер кубернетес. Но установка в кластер у которого есть выход в интернет мало похожа на продакшн задачу. Именно поэтому сначала мы загрузим все пакеты и helm чарты на компе или сервере с выходом в интернет, а уже после выполним установку в закрытом периметре. (air-gapped).

Собираю единомышленников в телеграм канале. Там же отвечаю на вопросы.
Присоединяйся Telegram

Настройка очень тонкая. Всё зависит от тех компонентов, которые у вас уже есть.
В данной инструкции я постарался максимально приблизиться к той установке, что работает в проде.

Шаг 1. Требования

На компе/сервере с выходом в инет установлены:

  • Helm
  • Docker Закрытый контур установлены:
  • Docker или Nerdctl
  • Helm
  • Harbor или Nexus
  • Minio или Ceph
  • Longhorn или NFS

План такой:
На машине с инетом:

  1. Скачать helm-чарт
  2. Вытащить имена образов
  3. Сделать тестовый values.yaml
  4. Скачать образы
  5. Перенести в закрытый контур

В закрытым контуре:

  1. Запушить в свой репозиторий образы
  2. Запушить в свой репозиторий chart
  3. Написать values.yaml файл
  4. Подключить (создать секреты) интеграций
  5. Запустить установку

Шаг 2. Подготовка образов

1
2
3
helm repo add gitlab https://charts.gitlab.io
helm repo update
helm pull gitlab/gitlab --untar

Создаём файл:

1
nano values.yaml

Вставляем, изменяем переменные на свои:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
global:
  edition: ce
  hosts:
    domain: k8s.domain.local
    gitlab:
      name: gitlab.k8s.domain.local
  ingress:
    enabled: true
    configureCertmanager: false
    provider: nginx
    class: nginx
    tls:
      enabled: false
  registry:
    enabled: false
  minio:
    enabled: false
gitlab-runner:
  install: false
prometheus:
  install: false
grafana:
  enabled: false

Я не использую tls сертификаты, так как это перегрузит инструкцию, поэтому настраиваю http соединение и tls выбираю false

Выгружаем список образов:

1
helm template gitlab ./gitlab -f values.yaml > rendered.yaml

Выгружаем образы в файл:

1
2
grep image: rendered.yaml | awk '{print $2}' | sort -u > git-images.txt
grep -oE 'image:\s*"?[^"]+' rendered.yaml | sed -E 's/^image:\s*"?//; s/"$//' | sort -u > git-images.txt

Я создал в своём Harbor проект с именем gitlab. Публичный. Далее я буду использовать его в переменных окружения.

Сейчас мы выкачаем образы и затегаем.
Задаём переменные окружения:

1
2
export HARBOR="harbor.domain.local"
export PROJECT="gitlab"

Выполняем скрипт:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
cat git-images.txt | tr -d '\r' | while IFS= read -r img; do
  img="$(echo "$img" | tr -d '"' | xargs)"
  [ -z "$img" ] && continue

  cleaned="$(echo "$img" | sed -E 's#^(docker\.io|registry\.gitlab\.com|quay\.io|gcr\.io|ghcr\.io|registry\.k8s\.io)/##')"
  new="${HARBOR}/${PROJECT}/${cleaned}"
  
  echo "PULL  $img"
  sudo docker pull "$img" || { echo "FAIL pull: $img"; exit 1; }
  
  echo "TAG   $img -> $new"
  sudo docker tag "$img" "$new" || { echo "FAIL tag: $img -> $new"; exit 1; }
done

Сохранить имена в файл:

1
2
3
4
5
6
cat git-images.txt | tr -d '\r' | while IFS= read -r img; do
  img="$(echo "$img" | tr -d '"' | xargs)"
  [ -z "$img" ] && continue
  cleaned="$(echo "$img" | sed -E 's#^(docker\.io|registry\.gitlab\.com|quay\.io|gcr\.io|ghcr\.io|registry\.k8s\.io)/##')"
  echo "${HARBOR}/${PROJECT}/${cleaned}"
done | sort -u > harbor-images.txt

Сохраняем в архив:

1
sudo docker save -o gitlab-harbor-images.tar $(cat harbor-images.txt)

Также запаковываем чарт:

1
tar -cvf gitlab-helm.tgz gitlab 

Перенеси в закрытый контур:

1
2
3
harbor-images.txt
gitlab-harbor-images.tar
gitlab-helm.tgz

Шаг 3. Распаковка образов

Внутри закрытого контура:

1
sudo docker load -i gitlab-harbor-images.tar

Задаём переменные окружения:

1
2
export HARBOR="harbor.domain.local"
export PROJECT="gitlab"

Логинимся:

1
docker login ${HARBOR}

Пушим все образы:

1
2
3
4
5
6
cat harbor-images.txt | tr -d '\r' | while IFS= read -r img; do
  img="$(echo "$img" | tr -d '"' | xargs)"
  [ -z "$img" ] && continue
  echo "PUSH $img"
  sudo docker push "$img" || { echo "FAIL push: $img"; exit 1; }
done

Получился 21 образ в репозитории + возможно также потребуется перетегать postgres-exporter в postgresql-exporter, будет 22 образа.
Создаём репозиторий с именем helm в Harbor, если он ещё не создан. И пушим наш архив с Helm.

1
helm push gitlab-helm.tgz oci://harbor.doman.local/helm

Образы готовы к установке. Переходим к конфигурированию значений Helm.

Шаг 4. Конфигурация HELM values для Gitlab

У меня будет ArgoCD, с помощью него я установлю мониторинг, поэтому я не буду устанавливать Grafana/Prometheus и отключу этот параметр.
За Ingress у меня отвечает NGINX в k8s поэтому он мне не нужен.
Также у меня есть кластер серверов MinIO, свой репозиторий на основе Harbor, и хранилище на Longhorn.
Сертификаты пока не настроены, поэтому cert-manager тоже долой.
Соответственно эти компоненты я ставлю disabled/false.
А вот redis, postgresql у меня нет, поэтому их я их установлю, по умолчанию все компоненты = enabled/true.
Создаём файл:

1
nano values.yaml

Содержимое:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
installCertmanager: false
nginx-ingress:
  enabled: false
gitlab-runner:
  install: false
prometheus:
  install: false
grafana:
  install: false
global:
  edition: ce
  hosts:
    domain: k8s.domain.local
    https: false
    gitlab:
      name: gitlab.k8s.domain.local
  image:
    registry: harbor.domain.local
  ingress:
    enabled: true
    configureCertmanager: false
    class: nginx
    tls:
      enabled: false
    annotations:
      kubernetes.io/ingress.class: nginx
  certificates:
    image:
      repository: harbor.domain.local/gitlab/gitlab-org/build/cng/certificates
      tag: "v18.8.4"
    # Рутовый ЦА для доверия между gitlab и minio
    customCAs:
      - secret: gitlab-ca
  kubectl:
    image:
      repository: harbor.domain.local/gitlab/gitlab-org/build/cng/kubectl
      tag: "v18.8.4"
  gitlabBase:
    image:
      repository: harbor.domain.local/gitlab/gitlab-org/build/cng/gitlab-base
      tag: "v18.8.4"
  registry:
    enabled: false
  minio:
    enabled: false
  appConfig:
    object_store:
    # Эти хранилища (бакеты) я создаю в следующем шаге
      enabled: true
      connection:
        secret: gitlab-storage
        key: config
    artifacts:
      enabled: true
      bucket: gitlab-artifacts
    lfs:
      enabled: true
      bucket: gitlab-lfs
    uploads:
      enabled: true
      bucket: gitlab-uploads
    packages:
      enabled: true
      bucket: gitlab-packages
    backups:
      bucket: gitlab-backups
      tmpBucket: tmp

gitlab:
  toolbox:
    image:
      repository: harbor.domain.local/gitlab/gitlab-org/build/cng/gitlab-toolbox-ce
      tag: "v18.8.4"
    backups:
      objectStorage:
        config:
        # Этот секрет я создаю в следующем шаге
          secret: s3-credentials
          key: config
  webservice:
    image:
      repository: harbor.domain.local/gitlab/gitlab-org/build/cng/gitlab-webservice-ce
    workhorse:
      image: harbor.domain.local/gitlab/gitlab-org/build/cng/gitlab-workhorse-ce
  migrations:
    image:
      repository: harbor.domain.local/gitlab/gitlab-org/build/cng/gitlab-toolbox-ce
      tag: "v18.8.4"
  gitaly:
    image:
      repository: harbor.domain.local/gitlab/gitlab-org/build/cng/gitaly
      tag: "v18.8.4"
    persistence:
      size: 20Gi
      storageClass: longhorn
  kas:
    image:
      repository: harbor.domain.local/gitlab/gitlab-org/build/cng/gitlab-kas
      tag: "v18.8.4"
  sidekiq:
    image:
      repository: harbor.domain.local/gitlab/gitlab-org/build/cng/gitlab-sidekiq-ce
  gitlab-shell:
    image:
      repository: harbor.domain.local/gitlab/gitlab-org/build/cng/gitlab-shell
  gitlab-exporter:
    image:
      repository: harbor.domain.local/gitlab/gitlab-org/build/cng/gitlab-exporter

registry:
  enabled: false

redis:
  image:
    registry: harbor.domain.local
    repository: gitlab/bitnamilegacy/redis
    pullPolicy: IfNotPresent
  metrics:
    image:
      registry: harbor.domain.local
      repository: gitlab/bitnamilegacy/redis-exporter
      pullPolicy: IfNotPresent
postgresql:
  image:
    registry: harbor.domain.local
    repository: gitlab/bitnamilegacy/postgresql
    pullPolicy: IfNotPresent
  metrics:
    image:
      registry: harbor.domain.local
      repository: gitlab/bitnamilegacy/postgresql-exporter
      pullPolicy: IfNotPresent

Каждая строчка конфига выверена и побеждена в отладке на ошибки. Поэтому за правильность секций можно быть уверенными.
Версии (теги) устанавливайте свои. На момент написания актуальная версия образов: v18.8.4.
Чтобы поды гитлаба доверяли MinIO и другим сервисам я помещаю рутовый сертификат своего CA внутрь контейнера.

1
kubectl -n gitlab create secret generic gitlab-ca --from-file=root-ca.crt=/usr/local/share/ca-certificates/root-ca.crt

Шаг 5. Настройка бакетов в MinIO

Создать в MinIO бакеты. Или подключите существующие.

  • gitlab-artifacts
  • gitlab-backups
  • gitlab-lfs
  • gitlab-registry
  • gitlab-uploads

Имена этих бакетов для хранения данных мы указали в values.yaml

Чтобы Gitlab умел авторизовать в Minio и не говорил ошибку 500, “нет прав на запись” ему нужно прописать ключи и доступы.
Сначала в Minio нужно провести работы по созданию пользователя, политики и токена. Приступим.
Cоздаём пользователя gitlab-s3
Создаём политику IAM Policies -> Create policy -> gitlab
И содержимое:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::gitlab-artifacts",
                "arn:aws:s3:::gitlab-backups",
                "arn:aws:s3:::gitlab-lfs",
                "arn:aws:s3:::gitlab-uploads"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:DeleteObject",
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::gitlab-artifacts/*",
                "arn:aws:s3:::gitlab-backups/*",
                "arn:aws:s3:::gitlab-lfs/*",
                "arn:aws:s3:::gitlab-uploads/*"
            ]
        }
    ]
}

И добавляем пользователя gitlab-s3 к политике.

Создать ключ к бакету gitlab-s3:
Minio -> Users -> Access Key -> Create
Получится примерно такое:

1
2
TasdasdaspksOr1iwOPABR
mS9pitEsdfsdfsdfsdfsue

Создать секрет

1
nano minio-secret.yaml

В качестве Endpoint у меня стоит nginx, который слушает s3.minio.domain.local на 443 и перенаправляет его на 9000.
Инструкция по установке MinIO здесь: ТЫК

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
apiVersion: v1
kind: Secret
metadata:
  name: gitlab-storage
  namespace: gitlab
type: Opaque
stringData:
  config: |
    provider: AWS
    region: us-east-1
    endpoint: "https://s3.minio.domain.local"
    path_style: true
    aws_access_key_id: TasdasdaspksOr1iwOPABR
    aws_secret_access_key: "mS9pitEsdfsdfsdfsdfsue"

Далее создаём второй файл с секретом, оба файла мы указали в values.yaml в ObjectStorage.

1
nano s3-gitlab.yaml

Если указать неверные данные, то Gitlab не сможет записывать и хранить данные в MinIO.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
apiVersion: v1
kind: Secret
metadata:
  name: s3-credentials
  namespace: gitlab
type: Opaque
stringData:
  config: |
    s3:
      bucket: gitlab-registry-storage
      accesskey: TasdasdaspksOr1iwOPABR
      secretkey: "mS9pitEsdfsdfsdfsdfsue"
      region: us-east-1
      regionendpoint: "https://s3.minio.domain.local"
      v4auth: true

Создаём namespace в кубере:

1
kubectl create ns gitlab

И применяем секреты:

1
2
kubectl apply -f gitlab-secret.yaml
kubectl apply -f s3.yaml

Шаг 6. Установка Gitlab из Helm

1
helm install gitlab oci://harbor.domain.local/helm/gitlab -n gitlab -f values.yaml

После успешной установки, которую можно проверить так:

1
kubectl get po -n gitlab

Открываем вебку по адресу, который указали в конфиге (Добавьте имя в DNS):
https://gitlab.domain.local

Пользователь для авторизации: root
Получить пароль для входа:

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

Поздравляю! Установка завершена

Информацию можно использовать в свободном доступе, с указанием ссылки на сайт
Telegram GitHub YouTube