Kubernetes

Раздел описывает развёртывание платформы Citeck в среде Kubernetes: управление ресурсами подов и контейнеров, настройку Helm chart, а также генерацию ключей шифрования.

Менеджмент ресурсов подов и контейнеров

Ниже описаны минимальные требования к ресурсам MEM/CPU для стабильной работы микросервисов в сочетании с XMX/XMS параметрами java. На данной конфигурации было произведено нагрузочное тестирование в 1000 одновременно работающих пользователей, длительностью в 1 час.

Состав сценария и распределение нагрузки:

  • логин в систему и просмотр главной страницы с загрузкой меню, дашборда, информации о пользователе (20%);

  • просмотр журнала контрактов (30%);

  • переход на страницу просмотра контракта с загрузкой всех виджетов: информация о контракте, действия, задачи, комментарии, связи, история версий и т.д. (30%);

  • просмотр журнала активных задач (30%);

  • создание документов (20%);

  • старт процессов по документам (10%);

  • выполнение задач по процессу (50%).

В ходе нагрузки было сгенерировано 2 043 398 запросов, из них 1 запроса (0.00 %) завершилось с ошибками или превысило лимит времени выполнения.

Метрика

Значение

Среднее время отклика

6.88 мс

Медиана

6 мс

90% запросов

< 16 мс

95% запросов

< 25 мс

99% запросов

< 47 мс

Ecos Registry

EcosRegistryApp:
    environments:
        javaOpts: "-Xmx256m -Xms256m"
    resources: |
        limits:
            cpu: 1
            memory: 1Gi
        requests:
            cpu: 300m
            memory: 1Gi

Ecos Model

EcosModelApp:
    environments:
        javaOpts: "-Xmx256m -Xms256m"
    resources: |
        limits:
            cpu: 2
            memory: 1Gi
        requests:
            cpu: 2
            memory: 1Gi

Ecos Gateway

EcosGatewayApp:
    environments:
        javaOpts: "-Xmx256m -Xms256m"
    resources: |
        limits:
            cpu: 2
            memory: 1Gi
        requests:
            cpu: 2
            memory: 1Gi

Ecos Apps

EcosAppsApp:
    environments:
        javaOpts: "-Xmx256m -Xms256m"
    resources: |
        limits:
            cpu: 1
            memory: 1Gi
        requests:
            cpu: 100m
            memory: 1Gi

Ecos Process

EcosProcessApp:
    environments:
        javaOpts: "-Xmx2G -Xms2G"
    resources: |
        limits:
            cpu: 1
            memory: 3548Mi
        requests:
            cpu: 1
            memory: 3548Mi

Ecos Uiserv

EcosUiservApp:
    environments:
        javaOpts: "-Xmx256m -Xms256m"
    resources: |
        limits:
            cpu: 1
            memory: 1Gi
        requests:
            cpu: 1
            memory: 1Gi

Ecos History

EcosHistoryApp:
    environments:
        javaOpts: "-Xmx256m -Xms256m"
    resources: |
        limits:
            cpu: 1
            memory: 1Gi
        requests:
            cpu: 100m
            memory: 1Gi

Ecos Integrations

EcosIntegrationsApp:
    environments:
        javaOpts: "-Xmx256m -Xms256m"
    resources: |
        limits:
            cpu: 1
            memory: 1Gi
        requests:
            cpu: 100m
            memory: 1Gi

Ecos Notifications

EcosNotificationsApp:
    environments:
        javaOpts: "-Xmx256m -Xms256m"
    resources: |
        limits:
            cpu: 1
            memory: 1Gi
        requests:
            cpu: 100m
            memory: 1Gi

Ecos Transformations

EcosTransformationsApp:
    environments:
        javaOpts: "-Xmx256m -Xms256m"
    resources: |
        limits:
            cpu: 1
            memory: 1Gi
        requests:
            cpu: 100m
            memory: 1Gi

Ecos Ecom

EcosEcomApp:
    environments:
        javaOpts: "-Xmx256m -Xms256m"
    resources: |
        limits:
            cpu: 1
            memory: 1Gi
        requests:
            cpu: 100m
            memory: 1Gi

Ecos Service Desk

EcosServiceDeskApp:
    environments:
        javaOpts: "-Xmx256m -Xms256m"
    resources: |
        limits:
            cpu: 1
            memory: 1Gi
        requests:
            cpu: 100m
            memory: 1Gi

Ecos Edi

EcosEdiApp:
    environments:
        javaOpts: "-Xmx256m -Xms256m"
    resources: |
        limits:
            cpu: 1
            memory: 1Gi
        requests:
            cpu: 100m
            memory: 1Gi

Ecos Content

EcosContentApp:
    environments:
        javaOpts: "-Xmx256m -Xms256m"
    resources: |
        limits:
            cpu: 1
            memory: 1Gi
        requests:
            cpu: 100m
            memory: 1Gi

Ecos Proxy

EcosProxyApp:
    resources: |
        limits:
            cpu: 1
            memory: 512Mi
        requests:
            cpu: 300m
            memory: 256Mi

Microservices Posgtresql

EcosMicroservicesPostgresqlApp:
    resources: |
        limits:
            cpu: 2
            memory: 2Gi
        requests:
            cpu: 2
            memory: 2Gi

Mongo DB

MongoDBApp:
    resources: |
        limits:
            cpu: 500m
            memory: 512Mi
        requests:
            cpu: 300m
            memory: 512Mi

Zookeeper

ZookeeperApp:
    resources: |
        limits:
            cpu: 1
            memory: 1Gi
        requests:
            cpu: 500m
            memory: 1Gi

RabbitMQ

RabbitmqApp:
    resources: |
        limits:
            cpu: 1
            memory: 1Gi
        requests:
            cpu: 500m
            memory: 1Gi

Ecos Indentity

EcosIdentityApp:
    resources: |
        limits:
            cpu: 1
            memory: 1Gi
        requests:
            cpu: 300m
            memory: 1Gi

Onlyoffice

OnlyofficeApp:
    resources: |
        limits:
            cpu: 2
            memory: 2Gi
        requests:
            cpu: 100m
            memory: 2Gi

Параметры конфигурации Helm chart

Примечание

Доступно только в Enterprise версии.

Раздел описывает параметры Helm chart, используемые для тонкой настройки развёртывания платформы Citeck в Kubernetes-кластере. Параметры позволяют управлять ресурсами, репликами, переменными окружения и другими характеристиками микросервисов.

Описание параметров представлено в примере Helm chart.

Общее описание

Примечание

<mSRV> заменяется на имя микросервиса, например EcosApp, RabbitmqApp и т.д.

Общие параметры

Параметр

Описание

.Values.FQDN

Доменное имя платформы

.Values.TenantID

Уникальный идентификатор тенанта

.Values.clusterDomain

Домен кластера Kubernetes

Управление микросервисами

Параметр

Описание

.Values.<mSRV>.enabled

Включение/отключение микросервисов

.Values.<mSRV>.clearData

Очистка данных при старте контейнера

.Values.<mSRV>.type

Тип ingress

.Values.<mSRV>.apiVersion

Версия API ingress

.Values.<mSRV>.secretName

Используемый TLS сертификат

.Values.<mSRV>.albIngress.enabled

Использовать ALB ingress контроллер

Контейнеры и образы

Параметр

Описание

.Values.<mSRV>.image.registry

Реестр образов

.Values.<mSRV>.image.repository

Репозиторий образов

.Values.<mSRV>.image.tag

Тег образа

.Values.<mSRV>.image.pullSecrets

Секреты для доступа к реестру

.Values.<mSRV>.initContainers.image.*

Настройки init-контейнеров

Vault и секреты

Параметр

Описание

.Values.<mSRV>.vault.enabled

Включение Vault

.Values.<mSRV>.vault.*

Переменные окружения и пароли для сервисов (MongoDB, PostgreSQL, Keycloak и др.)

Переменные окружения

Параметр

Описание

.Values.<mSRV>.environments.username/password

Логин/пароль администратора

.Values.<mSRV>.environments.javaOpts

Java-опции старта микросервисов

.Values.<mSRV>.environments.*

Специфичные переменные (Solr, Alfresco, Flowable и др.)

Хранилища и PVC

Параметр

Описание

.Values.<mSRV>.persistence.enabled

Включение persistent-хранилища

.Values.<mSRV>.persistence.size

Размер PVC

.Values.<mSRV>.persistence.storageClass

StorageClass PVC

.Values.<mSRV>.persistence.accessModes

Режим доступа PVC

.Values.<mSRV>.persistence.existingClaim

Использовать существующий PVC

.Values.<mSRV>.persistence.backup*

Параметры PVC для бэкапов

Метрики и мониторинг

Параметр

Описание

.Values.<mSRV>.metrics.enabled

Включение экспорта метрик

.Values.<mSRV>.metrics.config

Конфигурация jmx-exporter

.Values.<mSRV>.metrics.serviceMonitor.*

Настройки ServiceMonitor

.Values.<mSRV>.metrics.service.ports.*

Порты метрик

.Values.<mSRV>.metrics.containerSecurityContext.*

Контекст безопасности контейнера

.Values.<mSRV>.metrics.startupProbe.*

Startup Probe

.Values.<mSRV>.metrics.readinessProbe.*

Readiness Probe

.Values.<mSRV>.metrics.livenessProbe.*

Liveness Probe

Ресурсы и ограничения

Параметр

Описание

.Values.<mSRV>.resources

CPU и память для микросервисов

.Values.<mSRV>.tolerations

Tolerations для Pods

Прочее

Параметр

Описание

.Values.<mSRV>.webapp.properties.webUrl

URL для Spring-приложений

.Values.<mSRV>.x509.certs

Сертификаты (неясное назначение)

ZooKeeper в чарте ecos

Начиная с версии 1.3.108 чарт поддерживает два образа Zookeeper: Bitnami и официальный Apache. Дефолтный не менялся — без новых флагов, остаётся на Bitnami.

Режимы

ZookeeperApp.legacyStartCmd.enabled выбирает layout и команду старта.

Свойство

Bitnami (true, дефолт)

Official (false)

Команда

/entrypoint.sh /run.sh

/docker-entrypoint.sh zkServer.sh start-foreground

Том

/bitnami/zookeeper (данные в data/myid)

/data (/data/myid)

UID / fsGroup

1001

1000

Env

ZOO_SERVER_ID, ZOO_PORT_NUMBER, …

ZOO_MY_ID, ZOO_DATA_DIR=/data, ZOO_SERVERS вида server.1=host:2888:3888;2181

Проба

echo ruok | nc localhost 2181 | grep imok

ruok через bash /dev/tcp (в образе нет nc)

Тег чарта по умолчанию

3.6.2-debian-10-r124

—

legacyStartCmd без нужного образа не переключать: Bitnami не поймёт /data и /docker-entrypoint.sh, переход с Bitnami на official — возможен.

Флаги

ZookeeperApp:
  legacyStartCmd:
    enabled: true    # true = Bitnami, false = official
  migrateFromBitnami:
    enabled: true    # только official: flatten data/ → /data и chown

Апгрейд Bitnami → Bitnami

Остаётесь на Bitnami, нужен только более новый тег (3.6 / 3.8 → 3.9.3). Флаг не выключать, migrate не нужен.

ZookeeperApp:
  legacyStartCmd:
    enabled: true
  image:
    tag: 3.9.3-debian-12-r22

Тот же PVC, /bitnami/zookeeper, UID 1001. Snapshot читается как есть.

Дальше 3.9.3 на Bitnami не поднимать: у 3.9.4+ другой entrypoint, чарт под него не заточен. Если нужна 3.9.4+ — official.

Переход Bitnami → official (тот же PVC)

Данные на диске не копируются и не удаляются. Меняется только путь, по которому контейнер видит том, и init один раз поправляет вложенную папку.

На Bitnami PVC смонтирован как /bitnami/zookeeper. Файлы лежат так:

/bitnami/zookeeper/data/myid
/bitnami/zookeeper/data/version-2/

На official тот же PVC монтируется как /data. Содержимое диска то же, точка монтирования другая, поэтому те же файлы видны глубже:

/data/data/myid
/data/data/version-2/

Official ищет /data/myid, не /data/data/myid. Init init-migrate-from-bitnami (busybox) поднимает содержимое на уровень выше:

/data/myid
/data/version-2/
/data/.migrated-from-bitnami

Порядок работы init:

  1. Есть /data/myid — том уже в формате official, файлы не трогает.

  2. Есть /data/data/myid — переносит всё из data/ в /data, пишет маркер .migrated-from-bitnami.

  3. Нет ни того ни другого — пустой том, ZK сам создаст myid.

  4. В любом случае chown на runAsUser:fsGroup (для official это 1000:1000). Если оставить UID Bitnami 1001, official не сможет писать в том.

ZookeeperApp:
  legacyStartCmd:
    enabled: false
  migrateFromBitnami:
    enabled: true
  securityContext:
    runAsUser: 1000
    fsGroup: 1000
  image:
    registry: harbor.citeck.ru
    repository: docker-hub/library/zookeeper
    tag: "3.9.5"
    pullSecrets: harbor-docker-rpoxy
  persistence:
    enabled: true
    volumePermissions:
      enabled: true

После этого шага legacyStartCmd: true обратно не включать: пути уже не Bitnami, под не будет стартовать.

Пробы

Тайминги из values (дефолт):

  • liveness delay 30 с,

  • readiness 5 с,

  • timeout 5 с,

  • 6 фейлов.

На апгрейде чарта Bitnami — пробу не меняют.

Память

В поде два разных лимита: Kubernetes (resources.limits.memory) и JVM-куча (heap). Если Java просит больше, чем даёт kube, под убивают с OOMKilled.

Bitnami режет сам. Чарт ставит ZOO_HEAP_SIZE из environments.heapSize (дефолт 512, в мегабайтах):

ZookeeperApp:
  environments:
    heapSize: 512
  resources: |
    limits:
      memory: 768Mi
    requests:
      memory: 768Mi

JVM-куча ~512 Mi, запас в limit на метаспейс и нативные буферы. Так устроен дефолт чарта (768 Mi).

Official переменную ZOO_HEAP_SIZE игнорирует. Без JVMFLAGS JVM сама выбирает JVM-кучу (часто от размера контейнера). Чарт пишет JVMFLAGS, только если задать environments.jvmFlags. Если official начнёт упираться в память (OOM или тяжёлые пробы), поднять limit и явно ограничить кучу:

ZookeeperApp:
  environments:
    jvmFlags: "-Xmx256m -Xms256m"
  resources: |
    limits:
      cpu: 500m
      memory: 768Mi
    requests:
      cpu: 300m
      memory: 768Mi

-Xmx держать заметно ниже limits.memory: кроме кучи есть метаспейс, треды, прямые буферы. heapSize на official на это не влияет.

Итого: выставлять heapSize на official можно, но без смысла. Это не ошибка чарта и не поломка — просто мёртвая env.

Проверка после деплоя

kubectl -n <ns> get pod zookeeper-app-0
kubectl -n <ns> logs zookeeper-app-0 --tail=50
kubectl -n <ns> logs zookeeper-app-0 -c init-migrate-from-bitnami
kubectl -n <ns> exec zookeeper-app-0 -- zkCli.sh -server 127.0.0.1:2181 ls /ecos

Под должен быть 1/1 Running, в логах ZK — bind на 2181 и чтение snapshot, /ecos — прежний набор каталогов. Лог init-контейнера покажет один из трёх исходов: flatten bitnami data/ -> /data (первый переход), already official layout (повторный старт после миграции) или empty volume, nothing to migrate (пустой PVC). На томе после миграции (ls -la /data) должны быть myid и version-2, без вложенного /data/data/myid.

Чего не делать:

  • Не ставить official-тег при legacyStartCmd: true.

  • Не возвращать Bitnami после migrate.

Генерация уникального ключа шифрования

  1. При развертывании нового сервера необходимо каждый раз генерировать уникальный ключ шифрования.

  2. Используйте следующий код для генерации AES-ключа:

fun main() {

    val keyGen = KeyGenerator.getInstance("AES")
    keyGen.init(128) // AES key size 128
    val secretKey = keyGen.generateKey()
    val base64Key = Base64.getEncoder().encodeToString(secretKey.encoded)

    println("Base64 Key: $base64Key")

}
  1. Убедитесь, что ключ по умолчанию заменен на новый. Если этого не сделать, система выдаст предупреждение в логах.

Подробнее о шифровании секретов