Пример развертывания кластера одним чартом#

О подходе#

gs-ctk - это инструмент по развертыванию Global ERP, который мы предлагаем для внедрения в CI/CD-процессы заказчика. В инструкции ниже мы рассмотрим создание Helm-чарта, использующего gs-ctk как зависимость. Такой Helm-чарт легко внедрить в пайплайн CI/CD.

У этого подхода есть ряд преимуществ:

  • Чарт с шаблоном конфигурационного ресурса можно хранить в git-репозитории.

  • Возможность свободно параметризовать чарт. Хранение параметров в переменных и секретах на CI/CD-платформе значительно уменьшает конфигурационный дрифт между тестовыми и продуктовыми кластерами.

  • CI/CD-воркеру требуется минимальный набор программного обеспечения: Helm, пакеты из базовой поставки вашей ОС, опционально nscli.

  • Чарт в Git-репозитории, переменные из CI/CD-платформы, комплект приложения (хранящийся, например, в репозитории бинарных артефактов) и образы контейнеров описывают все состояние системы - никаких данных хранить на CI/CD-воркере не требуется.

Инструкция по подготовке и развертывания чарта#

Шаг 1. Создайте наш чарт#

Создать чарт можно при помощи следующей команды:

helm create one-deploy

Шаг 2. Добавьте чарт gs-ctk#

Положите в one-deploy/charts/ чарт gs-ctk. Ваша папка с чартом будет выглядеть примерно так:

one-deploy/
├── charts
│   └── gs-ctk
│       ├── Chart.yaml
│       ├── Chart.yaml.j2
│       ├── crds
│       │   ├── crd.yaml
│       │   └── namespaced_crd.yaml
│       ├── templates
│       │   ├── clusterlevel.yaml
│       │   ├── _helpers.tpl
│       │   ├── namespacelevel.yaml
│       │   └── NOTES.txt
│       └── values.yaml
├── Chart.yaml
├── templates
│   └── ...
└── values.yaml

Шаг 3. Подготовьте шаблон GlobalConfiguration#

Удалите все шаблоны из папки templates созданного вами чарта one_deploy. Сделайте в папке файл globalconfugration.yaml с шаблоном вашего GlobalConfiguration.

Пример шаблона:

apiVersion: global-system.ru/v1
kind: NamespacedGlobalConfiguration
metadata:
  name: config
  namespace: {{ .Release.Namespace }}
spec:
  resgroups:
  - admin_secret: one-secret
    appkit:
      applib_sha1: "{{ .Values.applib_sha1 }}"
      globalserver_instance: "1"
      globalserver_sha1: "{{ .Values.globalserver_sha1 }}"
      path: "{{ .Values.appkit_path }}"
      profile_sha1: "{{ .Values.profile_sha1 }}"
      state: "{{ .Values.state }}"
    appvol:
      path: /app
      server: nfs.local
      type: nfs
    database_alias: test
    database_schema_version: "{{ .Values.applib_sha1 }}" # будем обновлять БД при каждом обновлении прикладного решения
    database_secret: db
    database_url: jdbc:postgresql://database.local/global
    enabled: true
    java_version: "21"
    name: gs-cluster
    prometheus_secret: one-secret
    admin_secret: one-secret
    resbooks:
    - name: global-server-excl
      type: global_server_excl
    - name: global-server-share
      replicas: 1
      type: global_server_share
    - name: grafana
      service:
        external_ip: 172.23.30.216
        type: ip
      type: grafana
    - name: haproxy
      replicas: 1
      service:
        annotations: {}
        host: ""
        ingress_class: traefik
        type: ingress
      statistics_secret: one-secret
      type: haproxy
    - name: rabbitmq
      type: rabbitmq
      vhost: globalrabbitmq
    - name: scheduler
      scheduler_token_secret: scheduler-token-secret
      type: global_scheduler
    - name: jgroups-dns
      type: jgroups_dns
    search_domains: []
    timezone: Europe/Moscow
  type: advanced

Вы можете параметризировать любой параметр конфигурации. Здесь, например, вынесены параметры комплекта приложений. Также вы, наверное, захотите параметризовать настройки базы данных, NFS, горячего обновления.

Шаг 4. Сформируйте файл values.yaml#

Очистите файл values.yaml в корне вашего Helm-чарта от шаблонного кода, сгенерированного helm create. Затем добавьте в него параметры шаблонов по умолчанию и переопределите нужные параметры чарта gs-ctk:

applib_sha1: "applib_placeholder"
globalserver_sha1: "globalserver_placeholder"
profile_sha1: "profile_placeholder"
state: "started"
appkit_path: "path_placeholder"

gs-ctk:
  addSecrets: true
  imagePullSecret: docker-secret
  imageRepository: dockerhub.global-system.ru
  systemVolume:
    nfs:
      path: /sys
      server: nfs.local

О параметрах values.yaml для gs-ctk читайте подробнее в шаге 2 инструкции по установке Global ERP в кластере Kubernetes.

Шаг 5. Загрузите ваш appkit на NFS#

Загрузите комплект приложений на NFS. Подготовить комплект к загрузке вы можете через nsctl или при помощи встроенных средств системы. Подробнее читайте здесь.

Шаг 6. Разверните систему при помощи Helm#

Выполните следующий bash-скрипт:

export nfs="/mnt/sys" # путь к примонтированному системному хранилищу NFS
export appkit="appkit/v1" # путь к комплекту приложений на NFS

helm upgrade one-deploy one-deploy \
  --namespace one-deploy \
  --install --create-namespace \
  --set applib_sha1="$(cat "$nfs/$appkit/applib.zip.sha1")" \
  --set globalserver_sha1="$(cat "$nfs/$appkit/globalserver.zip.sha1")" \
  --set profile_sha1="$(cat "$nfs/$appkit/profile.zip.sha1")" \
  --set appkit_path="$appkit" \
  --set secrets.gs-admin-auth.stringData.password="my_admin_password"

Helm развернет ваш чарт и gs-ctk, как его зависимость. Для применения изменений в комплекте приложений, gs-ctk или вашем чарте, повторите шаги 5 и 6.

Пример IaC и пайплайна развертывания и обновления с использованием GitLab CI/CD#

Сделаем пайплайн развертывания, используя подготовленный нами чарт, продолжающий уже существующий пайплайн сборки который публикует комплект приложений в репозиторий артефактов. О настройке сборки через GitLab CI/CD читайте здесь.

  1. Создайте еще один репозиторий, поместим в него наш чарт в папку one-deploy.

  2. В «Settings -> CI/CD -> Variables» добавим две переменные c флагом «Masked», в котором будем хранить наши секреты:

    • KUBECONFIG - содержимое ~/.kube/config

    • ADMIN_PASSWORD - пароль, который будем использовать как пароль администратора global

  3. Добавим в репозиторий и добавим файл .gitlab.ci, который автоматизирует шаги 5 и 6:

stages:
  - deploy

variables:
  NFS_PATH: "/mnt/sys"
  APPKIT_PATH: "appkit/v1"

deploy-appkit:
  stage: deploy
  image: alpine/helm:latest
  before_script:
    - apk add --no-cache kubectl coreutils
    # Настройка доступа к Kubernetes
    - mkdir -p ~/.kube
    - echo "${KUBECONFIG}" > ~/.kube/config
    - chmod 600 ~/.kube/config
  script:
    - |
      # 1. Скачивание appkit
      mkdir appkit
      echo "Скачивание appkit..."
      wget https://repo.example.net/appkit-SNAPSHOT.tar.gz -O appkit.tar.gz
      tar -xzvf appkit.tar.gz -c appkit/
      
      # 2. Загрузка на NFS
      # Здесь мы будем загружать комплект, используя уже развернутый под nsctl, что может вызвать проблемы при развертывании кластера "с нуля".
      # Мы выбрали этот способ, потому что он более универсален для нашего примера, так как делегирует задачу подключения к NFS на Kubernetes.
      echo "Загрузка на NFS..."
      export POD_NAME="$(kubectl get pods --namespace gs-ctk -l app=nsctl -o jsonpath='{.items[0].metadata.name}')"
      kubectl cp --namespace gs-ctk appkit/ "$POD_NAME:/root/nsctl/workspace/mnt/sys/$APPKIT_PATH"
      
      # 3. Развертывание Helm
      echo "Развертывание с Helm..."
      helm upgrade one-deploy one-deploy \
        --namespace one-deploy \
        --install --create-namespace \
        --set applib_sha1="$(cat "appkit/applib.zip.sha1")" \
        --set globalserver_sha1="$(cat "appkit/globalserver.zip.sha1")" \
        --set profile_sha1="$(cat "appkit/profile.zip.sha1")" \
        --set appkit_path="$APPKIT_PATH" \
        --set secrets.gs-admin-auth.stringData.password="${ADMIN_PASSWORD}"