GitLab: Helm-чарт values, залежності та деплой у Kubernetes з AWS S3

Автор |  04/02/2023
 

Продовжуємо зайомство з GitLab та його деплоєм у Kubernetes. Перша частина –  GitLab: компоненти, архітектура, інфраструктура та запуск із Helm-чарту в Minikube, тепер давайте готуватися деплоїти в AWS Elastic Kubernetes Service.

Що робитимемо і де:

  • деплоїмо в AWS з Helm-чарту, для початку якийсь “test env”
  • Kubernetes – AWS EKS
  • object store – AWS S3
  • PostgreSQL – з operator
  • Redis – поки використовуємо дефолтний, потім переїдемо на KeyDB, який теж розгортається оператором
  • Gitaly – спробуємо в кластері, можливо, на окремій ноді – у нас всього 150-200 користувачів, навантаження не повинно бути великим, скейлінг і тим більше Praefik не потрібні

GitLab Operator виглядає в цілому цікаво, але в документації через слово “Experimental” і “Beta”, тому поки не чіпаємо – використовуємо чарт.

Helm chart prerequisites

По чарту: для початку треба пройтися по доступним параметрам чарту, і подивитися, що нам взагалі треба буде із зовнішніх ресурсів (лоад-балансери, корзини S3, PostgreSQL), і що ще можна налаштувати через чарт.

Не забуваємо подивитися GitLab chart prerequisites , з якого нам поки що цікаві:

  • PostgreSQL: ми будемо використовувати оператор, та розгорнемо свій кластер з блекджеком і базами
  • Redis: у нас є KeyDB-оператор, потім будемо використовувати його, поки дефолтний із чарту
  • Networking and DNS: використовуємо AWS ALB Contoller, створимо ACM сертифікат, DNS у Route53, записи створюються через External DNS
  • Persistence: цікавий нюанс, можливо, треба буде налаштувати reclaimPolicy to Retain, див. Configuring Cluster Storage
  • Prometheus: теж поінт на подумати – у нас є Kube Prometheus Stack зі своїм Prometheus та Alertmanager, треба буде подумати чи відключати вбудований у GitLab, чи залишати
  • Outgoing email: поки не налаштовуватимемо, але потім треба буде подумати. У принципі є підтримка AWS SES, десь у документації зустрічав, так що нормально
  • RBAC: у нас є, підтримується, тож залишаємо за замовчуванням, тобто включаємо

Враховуємо, що чарт включає цілу пачку залежностей, і корисно пройтися і подивитися що там ще деплоїться і з якими параметрами.

Структура Helm-чарту та його values.yaml

У GitLab Helm-чарту досить складна структура його values, так як чарт включає набір сабчартів і залежностей, див. GitLab Helm subcharts .

Щоб краще зрозуміти структуру його values – можна подивитися структуру каталогу charts з дочірніми чартами:

[simterm]

$ tree -d gitlab/charts/
gitlab/charts/
|-- certmanager-issuer
|   `-- templates
|-- gitlab
|   |-- charts
|   |   |-- geo-logcursor
|   |   |   `-- templates
|   |   |-- gitaly
|   |   |   `-- templates
|   |   |-- gitlab-exporter
|   |   |   `-- templates
|   |   |-- gitlab-grafana
|   |   |   `-- templates
|   |   |-- gitlab-pages
|   |   |   `-- templates
|   |   |-- gitlab-shell
|   |   |   `-- templates
|   |   |-- kas
|   |   |   `-- templates
|   |   |-- mailroom
|   |   |   `-- templates
|   |   |-- migrations
|   |   |   `-- templates
|   |   |-- praefect
|   |   |   `-- templates
|   |   |-- sidekiq
|   |   |   `-- templates
|   |   |-- spamcheck
|   |   |   `-- templates
|   |   |-- toolbox
|   |   |   `-- templates
|   |   `-- webservice
|   |       `-- templates
|   |           `-- tests
|   `-- templates
|-- minio
|   `-- templates
|-- nginx-ingress
|   `-- templates
|       `-- admission-webhooks
|           `-- job-patch
`-- registry
    `-- templates

[/simterm]

Крім того, є набір зовнішніх залежностей, див requirements.yaml.

Відповідно у values основного чарту параметри розбиті на global (див. Subcharts and Global Values), які використовуються дочірніми чартами, та параметри для конкретних чартів, див. Configure charts using globals, тобто наш values.yaml виглядатиме так:

global: 

  hosts:
    domain:
    hostSuffix: # використовується у ./charts/gitlab/charts/webservice, ./charts/gitlab/charts/toolbox/, ./charts/registry/, etc
  ...

gitlab:
  kas:
    enabled: # використовується у ./charts/gitlab/charts/kas/
...

nginx-ingress:
  enabled: # використовується для ./gitlab/charts/nginx-ingress
...

postgresql:
  install: # використовується при встановленні зовнішнього чарту postgresql

Тепер подивимося на самі values, і які нам можуть бути корисні.

Helm chart values

“Стартова точка” для роботи з чартом – Installing GitLab by using Helm .

Ще добре пройтися дефолтним values.yaml– там у коментарях є посилання на сервіси/параметри.

Власне, параметри, які нам можуть бути цікаві, див. у Configure charts using globals та GitLab Helm chart deployment options :

  • global.hosts:
    • domain: вказуємо домен, в якому будуть створюватися записи для GitLab
    • externalIP: він начебто обов’язковий, але оскільки у нас буде AWS ALB, то не використовуємо
    • hostSuffixtest – додамо суффікс до субдоменів, що створюються, отримаємо запис виду gitlab-test.example.com
    • httpstrue , буде ALB із AWS Certificate Manager
    • ssh: тут потрібно буде задати окремий субдомен для доступу до GitLab Shell
  • global.ingress: так як у нас AWS ALB, то див. alb-full.yaml
    • annotations.*annotation-key*: додамо аннотації для ALB
    • configureCertmanager: треба буде відключити, так як SSL термінейтимо на лоад-балансері
    • tls.secretName: нам не потрібен, так як SSL термінейтимо на лоад-балансері
    • path: для ALB буде потрібен /*
    • provider: для ALB == aws
  • global.gitlabVersion: думав тут задати версію Gitlab, яку будемо деплоїти, але виявилося, що ні – правильніше через версію чарту, див. GitLab Version
  • global.psql: параметри для підключення до PostgreSQL сервісами GitLab, див. Configure PostgreSQL settings
    • host: адреса PosgtreSQL Service
    • databaseusername: зрозуміло
    • password:
      • useSecret: пароль зберігатимемо в Secret
      • secret: ім’я секрету
      • key: ключ/поле у ​​Секреті, за яким отримуємо пароль
  • global.redis: взагалі буде зовнішній, KeyDB, і тут треба буде вказати параметри доступу до нього, але спочатку залишимо дефолтний, див. Configure Redis settings
  • global.grafana.enabled: включаємо – подивимося, які там є дашборди (таки треба буде налаштовувати окремо, див. Grafana JSON Dashboards )
  • global.registry: див. Using the Container Registry
    • bucket: треба буде створити S3 бакет, цей параметр використовується /charts/gitlab/charts/toolbox/ для бекапів, сам GitLab Registry налаштовується через окремі параметри, розглянемо нижче
  • global.gitaly: поки використовуємо з чарту, незважаючи на рекомендації – будемо деплоїти у вигляді Kubernetes Pod в кластер, залишаємо за замовчуванням, але маємо на увазі
  • global.minio: відключимо – використовуємо відразу AWS S3
  • global.appConfig: ось тут прям багато всього, див. Configure appConfig settings – містить загальні параметри для чартів WebserviceSidekiq та Gitaly
    • cdnHost: взагалі-то корисна начебто річ, але подивимося, як його використовувати, поки не чіпаємо
    • contentSecurityPolicy: теж корисна штука, але налаштуємо потім, див. Content Security Policy
    • enableUsagePing: “телеметрія” для самого GitLab Inc, не бачу сенсу, відключимо
    • enableSeatLink: не зрозумів, що це, посилання seat link support веде в “нікуди” – на сторінці інформації про seat не знайшов, але мабуть це щось пов’язане з кількістю користувачів в ліцензії, а оскільки ми її не купуємо – то можна вимкнути
    • object_store: загальні параметри для роботи з S3 типу ключів доступу та proxy, див. Consolidated object storage
      • connection: тут потрібно буде створити секрет, в якому описуються налаштування підключення до корзин, у тому числі ACCESS/SECRET ключі, але ми замість ключів використовуємо ServiceAccount та IAM role
    • Specify buckets : які корзини потрібні, є набір дефолтних імен типу gitlab-artifacts , але для dev- та test- має сенс перевизначити
      • storage_options: шифрування для бакетів, має сенс змінювати якщо використовується AWS KMS, але ми швидше за все залишимо дефолтне шифрування
    • LFS, Artifacts, Uploads, Packages, External MR diffs, and Dependency Proxy – налаштування корзин для різних сервісів, поки не чіпатимемо, подивимося по ходу використання
    • gitlab_kas: налаштування для GitLab Agent for Kubernetes, поки залишимо за замовчуванням, не впевнений, що він нам знадобиться
    • omniauth: налаштування для SSO, якось потім, взагалі будемо підключати аутентифікацію через Google, див. OmniAuth
  • global.serviceAccounts: замість ACCESS/SECRET будемо використовувати Kubernetes ServiceAccounts з IAM Role для подів:
    • create: включаємо створення SA для сервісів
    • annotations: а тут вкажемо ARN IAM-ролі
  • global.nodeSelector: корисно, потім будемо на виділених нодах
  • global.affinity&& global.antiAffinity: плюс можна налаштувати Affinity
  • global.common.labels: задамо тут всякі environment , team , etc
  • global.tracing: поки не чіпаємо, але маємо на увазі на майбутнє – потім додамо якийсь Jaeger/Grafana Tempo
  • global.priorityClassName: можливо корисно або навіть потрібно, потім потикаємо, див. Pod Priority and Preemption

З глобальних змінних це начебто все, крім них нам треба буде:

  • вимкнути certmanager – використуємо AWS Certificate Manager на AWS LoadBalncer
  • вимкнути postgresql – використуємо зовнішній
  • відключити gitlab-runner – у нас вже є запущені раннери, потім спробуємо прикрутити їх до цього інстансу GitLab
  • відключити nginx-ingress – у нас AWS ALB Controller та AWS ALB балансери
  • налаштувати Services для webservice та gitlab-shell
  • налаштувати registry

Тепер перед деплоєм чарту треба підготувати зовнішні сервіси:

  • кластер та база PostgreSQL
  • бакети AWS S3
  • сертифікат в AWS Certificate Manager для лоад-балансеру

Підготовка – створення зовнішніх ресурсів

PostgreSQL

У нас використовується PostgreSQL Operator – описуємо створення кластера.

Параметри по коннектам, пам’яті, диску та реквестам-лімітам поки що дефолтні – подивимося по ходу діла, як сильно навантажуватиметься база.

Описуємо створення бази gitlabhq_test та дефолтних юзерів – defaultUsers=true:

kind: postgresql
apiVersion: acid.zalan.do/v1
metadata:
  name: gitlab-cluster-test-psql
  namespace: gitlab-cluster-test
  labels:
    team: devops
    environment: test
spec:
  teamId: devops
  postgresql:
    version: "14"
    parameters:
      max_connections: '100'
      shared_buffers: 256MB
      work_mem: 32MB
  numberOfInstances: 3
  preparedDatabases:
    gitlabhq_test:
      defaultUsers: true
      schemas:
        public:
          defaultRoles: false
  enableMasterLoadBalancer: false
  enableReplicaLoadBalancer: false
  enableConnectionPooler: false
  enableReplicaConnectionPooler: false
  volume:
    size: 10Gi
    storageClass: encrypted
  resources:
    requests:
      cpu: "100m"
      memory: 100Mi
    limits:
      memory: 1024Mi
  enableLogicalBackup: true
  logicalBackupSchedule: "0 1 * * *"
  sidecars:
    - name: exporter
      image: quay.io/prometheuscommunity/postgres-exporter:v0.11.1
      ports:
        - name: exporter
          containerPort: 9187
          protocol: TCP
      resources:
        limits:
          memory: 50M
        requests:
          cpu: 50m
          memory: 50M
      env:
      - name: DATA_SOURCE_URI
        value: localhost/postgres?sslmode=disable
      - name: DATA_SOURCE_USER
        value: "$(POSTGRES_USER)"
      - name: DATA_SOURCE_PASS
        value: "$(POSTGRES_PASSWORD)"
      - name: PG_EXPORTER_AUTO_DISCOVER_DATABASES
        value: "true"

Створюємо неймспейс:

[simterm]

$ kk create ns gitlab-cluster-test

[/simterm]

Деплоїмо кластер:

[simterm]

$ kk apply -f postgresql.yaml 
postgresql.acid.zalan.do/gitlab-cluster-test-psql created

[/simterm]

Перевіряємо поди:

[simterm]

$ kk -n gitlab-cluster-test get pod
NAME                                READY   STATUS              RESTARTS   AGE
devops-gitlab-cluster-test-psql-0   2/2     Running             0          24s
devops-gitlab-cluster-test-psql-1   0/2     ContainerCreating   0          4s

[/simterm]

Окей, створюються.

Перевіряємо Секрети – потім використуємо секрет юзера postgres у конфігах GitLab:

[simterm]

$ kk -n gitlab-cluster-test get secret
NAME                                                                                             TYPE                                  DATA   AGE
default-token-2z2ct                                                                              kubernetes.io/service-account-token   3      4m12s
gitlabhq-test-owner-user.devops-gitlab-cluster-test-psql.credentials.postgresql.acid.zalan.do    Opaque                                2      65s
gitlabhq-test-reader-user.devops-gitlab-cluster-test-psql.credentials.postgresql.acid.zalan.do   Opaque                                2      65s
gitlabhq-test-writer-user.devops-gitlab-cluster-test-psql.credentials.postgresql.acid.zalan.do   Opaque                                2      66s
postgres-pod-token-p7b4g                                                                         kubernetes.io/service-account-token   3      66s
postgres.devops-gitlab-cluster-test-psql.credentials.postgresql.acid.zalan.do                    Opaque                                2      66s
standby.devops-gitlab-cluster-test-psql.credentials.postgresql.acid.zalan.do                     Opaque                                2      66s

[/simterm]

Наче ОК.

AWS S3

Тепер створимо корзини.

Нам будуть потрібні:

Щоб уникнути помилки BucketAlreadyExists, до імен корзин додаємо or як власний “ідентифікатор”, бо імена загальні, і ім’я оточення – test , тобто список виходить такий:

  • or-gitlab-registry-test
  • or-gitlab-artifacts-test
  • or-git-lfs-test
  • or-gitlab-packages-test
  • or-gitlab-uploads-test
  • or-gitlab-mr-diffs-test
  • or-gitlab-terraform-state-test
  • or-gitlab-ci-secure-files-test
  • or-gitlab-dependency-proxy-test
  • or-gitlab-pages-test
  • or-gitlab-backups-test
  • or-gitlab-tmp-test

Не факт, що знадобляться всі, подивимося по ходу налаштування GitLab та його фіч, але поки що створимо.

Створюємо з AWS CLI:

[simterm]

$ aws --profile internal s3 mb s3://or-gitlab-registry-test
make_bucket: or-gitlab-registry-test

[/simterm]

Повторюємо для решти корзин.

AWS Certificate Manager

Для Ingress нам потрібен TLS-сертифікат, див. Requesting a public certificate, а для отримання сертифіката – вочевидь, що домен.

У нашому випадку використовуємо internal.example.com, для якого створимо wildcard-сертифікат в ACM:

У FQDN вказуємо *.internal.example.com, щоб включити всі субдомени. Потім для GitLab використуємо параметри global.hosts.domain=internal.example.com та hostSuffix=test, що в результаті створить кілька Ingress та Services, які через ExternalDNS створять необхідні записи у Route53.

У Validation Method вибираємо DNS – найпростіший, тим більш що доменна зона хоститься в Route53 – все створюється в пару кліків:

Переходимо до сертифікату – він зараз у Pending validation, клікаємо Create records in Route53 :

Тепер статус Issued, запам’ятовуємо його ARN – він нам знадобиться у values:

AWS IAM Policy та IAM Role для ServiceAccount

Для ServiceAccount, який повинен буде давати доступ до AWS S3, потрібно створити IAM Policy та IAM Role. Детально див. Kubernetes ServiceAccounts з IAM Role для подів, тут швиденько.

Створюємо поліси:

{
    "Statement": [
        {
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObject",
                "s3:ListMultipartUploadParts",
                "s3:AbortMultipartUpload"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::or-gitlab-registry-test/*",
                "arn:aws:s3:::or-gitlab-artifacts-test/*",
                "arn:aws:s3:::or-git-lfs-test/*",
                "arn:aws:s3:::or-gitlab-packages-test/*",
                "arn:aws:s3:::or-gitlab-uploads-test/*",
                "arn:aws:s3:::or-gitlab-mr-diffs-test/*",
                "arn:aws:s3:::or-gitlab-terraform-state-test/*",
                "arn:aws:s3:::or-gitlab-ci-secure-files-test/*",
                "arn:aws:s3:::or-gitlab-dependency-proxy-test/*",
                "arn:aws:s3:::or-gitlab-backups-test/*",
                "arn:aws:s3:::or-gitlab-tmp-test/*"
            ]
        },
        {
            "Action": [
                "s3:ListBucket",
                "s3:ListAllMyBuckets",
                "s3:GetBucketLocation",
                "s3:ListBucketMultipartUploads"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::or-gitlab-registry-test",
                "arn:aws:s3:::or-gitlab-artifacts-test",
                "arn:aws:s3:::or-git-lfs-test",
                "arn:aws:s3:::or-gitlab-packages-test",
                "arn:aws:s3:::or-gitlab-uploads-test",
                "arn:aws:s3:::or-gitlab-mr-diffs-test",
                "arn:aws:s3:::or-gitlab-terraform-state-test",
                "arn:aws:s3:::or-gitlab-ci-secure-files-test",
                "arn:aws:s3:::or-gitlab-dependency-proxy-test",
                "arn:aws:s3:::or-gitlab-backups-test",
                "arn:aws:s3:::or-gitlab-tmp-test"
            ]
        }
    ],
    "Version": "2012-10-17"
}

Створюємо IAM Role – вибираємо Web identity:

Підключаємо створену вище Policy:

Наче все? Можна писати values.

Деплой Gitlab Helm

Створення values.yaml

Всі дефолтні values ​​тут>>>, можна використати як приклад, але не варто повністю копіювати – у свій values ​​пишемо тільки те, що у нас відрізняється від дефолтного.

global

hosts

Configure Host settings

Вказуємо домен, використовуючи який чарт пропише значення для Ingress та Services які буде створювати – отримаємо набір доменів виду gitlab.internal.example.comregistry.internal.example.com і т.д.

Для SSH у прикладі для Ingress вказаний окремий субдомен, оскільки під SSH буде створюватися окремий Service з Network Load Balancer для доступу до 22 TCP.

hostSuffix додасть суфікс до створюваних записів, тобто в результаті будуть субдомени виду gitlab-test.internal.example.com та registry-test.internal.example.com .

Але для SSH hostSuffix не застосовується, тому вказуємо відразу з суфіксом.

Виходить так:

global:
  hosts:
    domain: internal.example.com
    hostSuffix: test
    ssh: gitlab-shell-test.internal.example.com

ingress

Configure Ingress settings

Беремо для прикладу alb-full.yaml, від себе додамо тільки load_balancing.algorithm.type=least_outstanding_requests:

ingress:
  # Common annotations used by kas, registry, and webservice
  annotations:
    alb.ingress.kubernetes.io/backend-protocol: HTTP
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:eu-central-1:514***799:certificate/7227a8fa-1124-441c-81d7-ec168180190d
    alb.ingress.kubernetes.io/group.name: gitlab
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS": 443}]'
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-group-attributes: load_balancing.algorithm.type=least_outstanding_request
    alb.ingress.kubernetes.io/target-type: ip
    kubernetes.io/ingress.class: alb
    nginx.ingress.kubernetes.io/connection-proxy-header: "keep-alive"
  class: none
  configureCertmanager: false
  enabled: true
  path: /*
  pathType: ImplementationSpecific
  provider: aws
  tls:
    enabled: false

Якщо використовувати KAS, йому потрібен буде окремий LoadBalancer, налаштуємо його трохи пізніше в блоці gitlab.kas.

psql

Configure PostgreSQL settings

Знаходимо ім’я Service, який був створений під час деплою PostgreSQL кластеру:

[simterm]

$ kk -n gitlab-cluster-test get svc
NAME                                     TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
devops-gitlab-cluster-test-psql          ClusterIP   172.20.67.135    <none>        5432/TCP   63m
devops-gitlab-cluster-test-psql-config   ClusterIP   None             <none>        <none>     63m
devops-gitlab-cluster-test-psql-repl     ClusterIP   172.20.165.249   <none>        5432/TCP   63m

[/simterm]

Користувача поки що візьмемо дефолтного postgress, з готового секрету:

[simterm]

$ kk -n gitlab-cluster-test get secret postgres.devops-gitlab-cluster-test-psql.credentials.postgresql.acid.zalan.do        
NAME                                                                            TYPE     DATA   AGE
postgres.devops-gitlab-cluster-test-psql.credentials.postgresql.acid.zalan.do   Opaque   2      67m

[/simterm]

Для production таки треба буде робити окремого, бо postgress == root .

Готуємо конфіг:

psql:
  host: devops-gitlab-cluster-test-psql
  database: gitlabhq_test
  username: postgres
  password:
    useSecret: true    
    secret: postgres.devops-gitlab-cluster-test-psql.credentials.postgresql.acid.zalan.do
    key: password

redis

Configure Redis settings

Configure Redis chart-specific settings

Configure the GitLab chart with an external Redis

Поки залишимо все за замовчуванням – Redis використовується тільки для кешування, подивимося, як він працюватиме і що по ресурсам.

registry

Configure Registry settings

В globals для registry вказуємо тільки корзину:

registry:
  bucket: or-gitlab-registry-test

gitaly

Поки що залишимо, як є. Потім подумаємо, може винесемо на окрему ноду.

Using the GitLab-Gitaly chart

Треба буде моніторити як він ресурси використовує, але у випадку з нашими 150-200 користувачів навряд чи там буде необхідність сильно допилювати його або тим більше розгортати кластер Praefect .

minio

Відключаємо, ходитимемо відразу в AWS S3:

minio:
  enabled: false

grafana

Включимо, подивимося, що в ній є (нічого 🙂):

grafana:
  enabled: true

appConfig

Список корзин є у values.

object_store таки треба налаштовувати – додати секрет, в якому буде вказано провайдер і регіон бакетів. Ключі не використовуємо – буде ServiceAccount.

Приклад візьмемо з , rails.s3.yaml, див. connection:

provider: AWS
region: eu-central-1

Створюємо Secret:

[simterm]

$ kk -n gitlab-cluster-test create secret generic gitlab-rails-storage --from-file=connection=rails.s3.yaml

[/simterm]

І описуємо appConfig, виходить так:

appConfig:
  enableUsagePing: false
  enableSeatLink: true # disable?
  object_store:
    enabled: true
    proxy_download: true
    connection:  
      secret: gitlab-rails-storage
      key: connection
  artifacts:
    bucket: or-gitlab-artifacts-test
  lfs:
    bucket: or-git-lfs-test
  packages:
    bucket: or-gitlab-packages-test
  uploads:
    bucket: or-gitlab-uploads-test
  externalDiffs:
    bucket: or-gitlab-mr-diffs-test
  terraformState:
    bucket: or-gitlab-terraform-state-test
  ciSecureFiles:
    bucket: or-gitlab-ci-secure-files-test
  dependencyProxy:
    bucket: or-gitlab-dependency-proxy-test
  backups:
    bucket: or-gitlab-backups-test
    tmpBucket: or-gitlab-tmp-test

serviceAccount

Див. Kubernetes: ServiceAccount з AWS IAM Role для Kubernetes Pod.

Начебто можна без створення ServiceAccount, просто через анотації до сервісів – IAM roles for AWS when using the GitLab chart.

Але ми будемо використовувати ServiceAccount, роль із політикою вже робили – додаємо:

serviceAccount:
  enabled: true
  create: true
  annotations: 
    eks.amazonaws.com/role-arn: arn:aws:iam::514***799:role/S3GitlabClusterTest

Так, з globals начебто все.

registry

Defining the Registry Configuration

Тут треба налаштувати storage, який зберігається в Secret, і в якому теж необхідно вказати ім’я корзини: параметр globals.registry буде використовуватися для бекапів, а параметр тут – самим сервісом Registry, див Docker Registry images .

Для прикладу візьмемо файл registry.s3.yaml, але без ключів, тому що для Registry буде створено свій ServiceAccoumt з IAM Role:

s3:
  bucket: or-gitlab-registry-test
  region: eu-central-1
  v4auth: true

Створюємо секрет:

[simterm]

$ kk -n gitlab-cluster-test create secret generic registry-storage --from-file=config=registry.s3.yaml

[/simterm]

Описуємо конфіг:

registry:
  enabled: true
  service:
    type: NodePort
  storage:
    secret: registry-storage
    key: config

gitlab – Services

Окремо описуємо Services для kaswebservice та gitlab-shell, з того ж прикладу alb-full.yaml.

Для gitlab-shell Service в аннотації external-dns.alpha.kubernetes.io/hostname вказуємо ім’я хоста:

gitlab:
  kas:
    enabled: true
    ingress:
      # Specific annotations needed for kas service to support websockets
      annotations:
        alb.ingress.kubernetes.io/healthcheck-path: /liveness
        alb.ingress.kubernetes.io/healthcheck-port: "8151"
        alb.ingress.kubernetes.io/healthcheck-protocol: HTTP
        alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=4000,routing.http2.enabled=false
        alb.ingress.kubernetes.io/target-group-attributes: stickiness.enabled=true,stickiness.lb_cookie.duration_seconds=86400
        alb.ingress.kubernetes.io/target-type: ip
        kubernetes.io/tls-acme: "true"
        nginx.ingress.kubernetes.io/connection-proxy-header: "keep-alive"
        nginx.ingress.kubernetes.io/x-forwarded-prefix: "/path"
    # k8s services exposed via an ingress rule to an ELB need to be of type NodePort
    service:
      type: NodePort
  webservice:
    enabled: true
    service:
      type: NodePort
  # gitlab-shell (ssh) needs an NLB
  gitlab-shell:
    enabled: true
    service:
      annotations:
        external-dns.alpha.kubernetes.io/hostname: "gitlab-shell-test.internal.example.com"
        service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"
        service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
        service.beta.kubernetes.io/aws-load-balancer-type: "external"
      type: LoadBalancer

Інше

Відключаємо непотрібні нам сервіси:

certmanager:
  install: false

postgresql:
  install: false

gitlab-runner:
  install: false

nginx-ingress:
  enabled: false

Повний values.yaml

В результаті отримуємо такий конфіг:

global:

  hosts:
    domain: internal.example.com
    hostSuffix: test
    ssh: gitlab-shell-test.internal.example.com

  ingress:
    # Common annotations used by kas, registry, and webservice
    annotations:
      alb.ingress.kubernetes.io/backend-protocol: HTTP
      alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:eu-central-1:514***799:certificate/7227a8fa-1124-441c-81d7-ec168180190d
      alb.ingress.kubernetes.io/group.name: gitlab
      alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS": 443}]'
      alb.ingress.kubernetes.io/scheme: internet-facing
      alb.ingress.kubernetes.io/target-group-attributes: load_balancing.algorithm.type=least_outstanding_requests
      alb.ingress.kubernetes.io/target-type: ip
      kubernetes.io/ingress.class: alb
      nginx.ingress.kubernetes.io/connection-proxy-header: "keep-alive"
    class: none
    configureCertmanager: false
    enabled: true
    path: /*
    pathType: ImplementationSpecific
    provider: aws
    tls:
      enabled: false

  psql:
    host: devops-gitlab-cluster-test-psql
    database: gitlabhq_test
    username: postgres
    password:
      useSecret: true
      secret: postgres.devops-gitlab-cluster-test-psql.credentials.postgresql.acid.zalan.do
      key: password

  registry:
    bucket: or-gitlab-registry-test

  minio:
    enabled: false

  grafana:
    enabled: true

  appConfig:
    enableUsagePing: false
    enableSeatLink: true # disable?
    object_store:
      enabled: true
      proxy_download: true
      connection:
        secret: gitlab-rails-storage
        key: connection
    artifacts:
      bucket: or-gitlab-artifacts-test
    lfs:
      bucket: or-git-lfs-test
    packages:
      bucket: or-gitlab-packages-test
    uploads:
      bucket: or-gitlab-uploads-test
    externalDiffs:
      bucket: or-gitlab-mr-diffs-test
    terraformState:
      bucket: or-gitlab-terraform-state-test
    ciSecureFiles:
      bucket: or-gitlab-ci-secure-files-test
    dependencyProxy:
      bucket: or-gitlab-dependency-proxy-test
    backups:
      bucket: or-gitlab-backups-test
      tmpBucket: or-gitlab-tmp-test

  serviceAccount:
    enabled: true
    create: true
    annotations:
      eks.amazonaws.com/role-arn: arn:aws:iam::514***799:role/S3GitlabClusterTest

  common:
    labels:
      environment: test

gitlab:
  kas:
    enabled: true
    ingress:
      # Specific annotations needed for kas service to support websockets
      annotations:
        alb.ingress.kubernetes.io/healthcheck-path: /liveness
        alb.ingress.kubernetes.io/healthcheck-port: "8151"
        alb.ingress.kubernetes.io/healthcheck-protocol: HTTP
        alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=4000,routing.http2.enabled=false
        alb.ingress.kubernetes.io/target-group-attributes: stickiness.enabled=true,stickiness.lb_cookie.duration_seconds=86400
        alb.ingress.kubernetes.io/target-type: ip
        kubernetes.io/tls-acme: "true"
        nginx.ingress.kubernetes.io/connection-proxy-header: "keep-alive"
        nginx.ingress.kubernetes.io/x-forwarded-prefix: "/path"
    # k8s services exposed via an ingress rule to an ELB need to be of type NodePort
    service:
      type: NodePort
  webservice:
    enabled: true
    service:
      type: NodePort
  # gitlab-shell (ssh) needs an NLB
  gitlab-shell:
    enabled: true
    service:
      annotations:
        external-dns.alpha.kubernetes.io/hostname: "gitlab-shell-test.internal.example.com"
        service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"
        service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
        service.beta.kubernetes.io/aws-load-balancer-type: "external"
      type: LoadBalancer

registry:
  enabled: true
  service:
    type: NodePort
  storage:
    secret: registry-storage
    key: config

certmanager:
  install: false

postgresql:
  install: false

gitlab-runner:
  install: false

nginx-ingress:
  enabled: false

Gitlab deploy

Ну і начебто все? Давайте деплоїти:

[simterm]

$ helm repo add gitlab https://charts.gitlab.io/
$ helm repo update
$ helm upgrade --install --namespace gitlab-cluster-test gitlab gitlab/gitlab --timeout 600s -f gitlab-cluster-test-values.yaml

[/simterm]

Перевіряємо Ingresses:

[simterm]

$ kk -n gitlab-cluster-test get ingress
NAME                        CLASS    HOSTS                                ADDRESS                                                           PORTS   AGE
gitlab-grafana-app          <none>   gitlab-test.internal.example.com     k8s-***.eu-central-1.elb.amazonaws.com   80      117s
gitlab-kas                  <none>   kas-test.internal.example.com        k8s-***.eu-central-1.elb.amazonaws.com   80      117s
gitlab-registry             <none>   registry-test.internal.example.com   k8s-***.eu-central-1.elb.amazonaws.com   80      117s
gitlab-webservice-default   <none>   gitlab-test.internal.example.com     k8s-***.eu-central-1.elb.amazonaws.com   80      117s

[/simterm]

Відкриваємо URL https://gitlab-test.internal.example.com:

Отримуємо рутовий пароль:

[simterm]

$ kubectl -n gitlab-cluster-test get secret gitlab-gitlab-initial-root-password -ojsonpath='{.data.password}' | base64 --decode ; echo
cV6***y1t

[/simterm]

Логінимося під root:

Перевірка деплою

Не віриться мені, що з першого разу все завелося.

Repository

Перевіряємо роботу з репозиторієм, тобто роботу сервісів Gitaly та GitLab Shell.

Створюємо тестовий репозиторій:

Копіюємо адресу – з субдоменом gitlab-shell-test.internal.example.com, який вказували в конфігах:

Клонуємо:

[simterm]

$ git clone [email protected]:gitlab-instance-da4355a9/test-repo.git
Cloning into 'test-repo'...
The authenticity of host 'gitlab-shell-test.internal.example.com (3.***.***.79)' can't be established.
ED25519 key fingerprint is SHA256:xhC1Q/lduNbg49kGljYUb21YlBBsxrG89xE+iCHD+xc.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'gitlab-shell-test.internal.example.com' (ED25519) to the list of known hosts.
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.

[/simterm]

І зміст:

[simterm]

$ ll test-repo/
total 8
-rw-r--r-- 1 setevoy setevoy 6274 Feb  4 13:24 README.md

[/simterm]

Спробуємо пушнути якісь зміни назад:

[simterm]

$ cd test-repo/
$ echo test > test.txt
$ git add test.txt
$ git commit -m "test"
$ git push
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 16 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 285 bytes | 285.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To gitlab-shell-test.internal.example.com:gitlab-instance-da4355a9/test-repo.git
   7217947..4eb84db  main -> main

[/simterm]

І в WebUI:

Окей, працює.

Container Registry

Далі перевіримо Registry – приклади команд є у веб-інтерфейсі > Container Registry :

Логінимося з тим же логіном:паролем, які використовували для логіна в веб-інтерфейс GitLab (користувач root, пароль з секрету gitlab-gitlab-initial-root-password):

[simterm]

$ docker login registry-test.internal.example.com
Username: root
Password:
...
Login Succeeded

[/simterm]

Створюємо Dockerfile:

FROM busybox
RUN echo "hello world"

Збираємо образ, тегаємо з ім’ям нашого Registry:

[simterm]

$ docker build -t registry-test.internal.example.com/gitlab-instance-da4355a9/test-repo:1 .

[/simterm]

І пушимо:

[simterm]

$ docker push registry-test.internal.example.com/gitlab-instance-da4355a9/test-repo:1  
The push refers to repository [registry-test.internal.example.com/gitlab-instance-da4355a9/test-repo]
b64792c17e4a: Mounted from gitlab-instance-da4355a9/test 
1: digest: sha256:eb45a54c2c0e3edbd6732b454c8f8691ad412b56dd10d777142ca4624e223c69 size: 528

[/simterm]

Перевіряємо корзину or-gitlab-registry-test:

[simterm]

$ aws --profile internal s3 ls or-gitlab-registry-test/docker/registry/v2/repositories/gitlab-instance-da4355a9/test-repo/_manifests/tags/1/
                           PRE current/
                           PRE index/

[/simterm]

Окей – Registry працює, доступ до S3 є, з ServiceAccounts проблем начебто немає.

ServiceAccounts та S3 access

Але про всяк випадок перевіримо ServiceAccounts та доступ до S3 в інших сервісах, наприклад з поду Toolbox:

[simterm]

$ kk -n gitlab-cluster-test exec -ti gitlab-toolbox-565889b874-vgqcb -- bash
git@gitlab-toolbox-565889b874-vgqcb:/$ aws s3 ls or-gitlab-registry-test
                           PRE docker/

[/simterm]

Окей – тут також все працює.

Grafana

Перевіряємо Grafana – https://gitlab-test.internal.example.com/-/grafana/.

Логін root, пароль беремо із секрету:

[simterm]

$ kubectl -n gitlab-cluster-test get secret gitlab-grafana-initial-password -ojsonpath='{.data.password}' | base64 --decode ; echo
Cqc***wFS

[/simterm]

Працює. Дашборди треба підключати окремо, потім займемося, як дійдемо до моніторингу взагалі, поки див. Grafana JSON Dashboards .

Загалом, начебто все.

Подивимося, що далі – адміністрування, міграція проектів, моніторинг, секьюріті.