--- # ============================================================================ # HRBox — конфигурация on-premise установки # ============================================================================ # # Минимум, который нужно заполнить перед первым деплоем: # # ingress.host домен инсталляции # app.defaultTenantHostname тот же домен # app.postgres.* подключение к PostgreSQL # app.s3.* S3-совместимое хранилище # app.smtp.* почта # app.hub.token токен HRBox Hub (выдаёт HRBox) # secrets.* три сгенерированных ключа # app.chatbox.wrappingKey ключ шифрования чатов # app.nanabushPlayer.keys.* два ключа плеера курсов # # Чарт проверяет их на этапе рендера и падает с понятной ошибкой, если # что-то не заполнено, — до того, как в кластере появятся поды. # # Команды генерации ключей перечислены рядом с каждым полем и целиком — # в README, раздел «Секреты». # ============================================================================ # Переопределение базового имени объектов. По умолчанию — имя чарта (hrbox), # то есть hrbox-web, hrbox-worker и так далее. Менять на работающей установке # нельзя: selector у Deployment неизменяем. nameOverride: "" # ============================================================================ # Образы # ============================================================================ # Все образы собраны в одном месте: обновление версии сервиса — это правка # одной строки здесь, а не поиск по шаблонам. image: # Основное приложение (PHP-FPM, nginx, worker, conductor-задачи, миграции). # Доступ к реестру выдают сотрудники HRBox. hrbox: "cr.yandex/crphnph9c2s776j32sjd/hrbox:latest" # Чат и вебсокеты chatbox: "cr.yandex/crphnph9c2s776j32sjd/hrbox-chatbox:5.18" # Интеграции с мессенджерами, пуши, синхронизация оргструктуры goworker: "cr.yandex/crphnph9c2s776j32sjd/hrbox-goworker:3.21.2" # Электронная подпись (КЭДО, МЧД) kedoca: "cr.yandex/crphnph9c2s776j32sjd/hrbox-kedoca:1.0.6" # Справочник городов, стран и часовых поясов geonames: "cr.yandex/crphnph9c2s776j32sjd/hrbox-geonames:3.3" # Конвертация документов и обработка изображений fileProcessor: "cr.yandex/crphnph9c2s776j32sjd/hrbox-file-processor:1.4.6" # Планировщик задач по расписанию conductor: "cr.yandex/crphnph9c2s776j32sjd/hrbox-conductor:2.2.0" # Плеер учебных материалов (SCORM, cmi5, xAPI, нативные курсы). # Тег обязателен и не может быть latest: из него выводится версия плеера, # которую HRBox кладёт в launch-тикет. nanabushPlayer: "cr.yandex/crphnph9c2s776j32sjd/nanabush-player:1.0.11" # Инфраструктура dragonfly: "cr.yandex/crpnn6fi85p3dauha6nc/dragonflydb:1.15.1" nats: "nats:2.10" natsConfigReloader: "natsio/nats-server-config-reloader:0.6.2" phpFpmExporter: "cr.yandex/crpnn6fi85p3dauha6nc/php-fpm_exporter:latest" # Используется только init-контейнером джобы миграций (ждёт готовности БД) postgresClient: "postgres:14-alpine" # Используется только при app.tracing.enabled otelCollector: "otel/opentelemetry-collector:0.109.0" pullPolicy: IfNotPresent # Секреты доступа к приватному Docker-реестру. # Создаются отдельно, см. README, шаг 1. imagePullSecrets: - name: regsecret # ============================================================================ # Приложение # ============================================================================ app: # Основной домен инсталляции. Должен совпадать с ingress.host. defaultTenantHostname: "hrbox.example.com" # Имя инстанса — попадает в логи и метрики, помогает различать установки. instanceName: "onprem" # Режим одного арендатора. "1" — вся установка обслуживает одну компанию. singleTenant: "0" # Frontend 2: "true" — включён (по умолчанию), "false" — старый интерфейс. front2: "true" # Отдельный домен авторизации. Для on-premise почти всегда пусто. authHost: "" # "0" — production, "1" — отладка. В production всегда "0". debug: "0" # Принудительный https во всех сгенерированных ссылках. forceHttps: "true" # Количество реплик. # web 2-10, по числу пользователей # worker 2-5, фоновые задачи # chatbox 2-6, real-time # остальные обычно хватает 1-2 replicas: web: 2 worker: 2 chatbox: 2 geonames: 1 goworker: 2 kedoca: 1 fileProcessor: 1 fileProcessorVideo: 1 # Своя политика конфиденциальности и правила использования. # При enabled: false приложение показывает ссылки HRBox. customPolicy: enabled: false # privacyUrl: "https://example.com/privacy" # termsUrl: "https://example.com/terms" # --- PostgreSQL ----------------------------------------------------------- # Требуется PostgreSQL 14+. Для отказоустойчивости настройте репликацию. postgres: host: "postgresql" port: "5432" database: "hrbox" user: "hrbox" # Пароль попадает в Secret чарта, а не в env-блок Deployment. password: "" # "true", если база работает на расширении Citus (шардирование). citus: "false" # --- Redis / Dragonfly ---------------------------------------------------- # Хранит сессии, кеш и очереди плеера курсов. Потеря данных не критична, # но разлогинивает пользователей и сбрасывает незавершённые события плеера. # # Пусто — используется Dragonfly из этого же релиза. Заполняйте, только # если Redis внешний (тогда обычно dragonfly.enabled: false). redis: host: "" port: "6379" # --- NATS JetStream ------------------------------------------------------- # Пусто — NATS из этого же релиза. # Внешний кластер: nats://node1:4222,nats://node2:4222,nats://node3:4222 nats: url: "" # --- S3 ------------------------------------------------------------------- # Подходят AWS S3, MinIO, Yandex Object Storage, VK Cloud Storage. s3: # MinIO: http://minio:9000 # Yandex: https://storage.yandexcloud.net # VK: https://hb.vkcloud-storage.ru endpoint: "https://storage.example.com" bucket: "hrbox" key: "" secret: "" region: "us-east-1" version: "latest" # "true" для MinIO и self-hosted S3, "false" для AWS S3 pathStyle: "true" multipart: "true" prefix: "" # --- Почта ---------------------------------------------------------------- smtp: host: "smtp.example.com" # 25 — без шифрования, 587 — STARTTLS, 465 — SSL/TLS port: "587" user: "noreply@example.com" password: "" from: "noreply@example.com" fromHost: "example.com" # "", "tls" или "ssl" securityType: "tls" sslAllowSelfSigned: "true" sslVerifyPeer: "false" # --- Мониторинг ошибок ---------------------------------------------------- sentry: dsn: "" environment: "production" # Отдельные DSN для подсистем. Пусто — используется общий dsn. launchpadDsn: "" conductorDsn: "" # У этих двух общего fallback нет: пусто означает «не отправлять». goworkerDsn: "" chatboxDsn: "" # --- Внутренние сервисы --------------------------------------------------- # Пустой url означает сервис из этого же релиза: адрес собирается из имени, # которое создаёт чарт. Заполняйте, только если вынесли сервис наружу. geonames: url: "" goworker: url: "" # Минимальный интервал между push-уведомлениями одному пользователю pushMinInterval: "5m" kedoca: url: "" # Пароль корневого сертификата, который сервис создаёт при первом запуске rootCaPass: "hrbox" # "gost" (ГОСТ, КриптоПро) или "openssl" engine: "gost" # "gost2012_256" для ГОСТ, "rsa" для OpenSSL algorithm: "gost2012_256" # "paramset:A" для ГОСТ, "rsa_keygen_bits:2048" для RSA pkeyopt: "paramset:A" # Служба меток времени tspUrl: "http://qs.cryptopro.ru/tsp/tsp.srf" # Kubernetes Secret с сертификатами УЦ. Если задан — монтируется в /ca-cert. secretName: "" fileProcessor: # Сколько документов конвертировать одновременно в одном поде docconvMaxParallelTasks: "1" # Сколько изображений ресайзить одновременно (пул конвертации видео) imageResizeMaxParallel: "20" # --- Конвертация видео ---------------------------------------------------- # Отдельный пул подов: конвертация видео требует много CPU и диска и # выносится на выделенные ноды, чтобы не мешать остальным задачам. videoConverter: enabled: false # Внутренний адрес HRBox, по которому конвертер забирает и отдаёт файлы. # Пусто — берётся http://<релиз>-web. internalUrl: "" # Куда планировать поды конвертера. Пусто — без ограничений. nodeSelector: {} # role: converter-dedicated tolerations: [] # - key: dedicated # operator: Equal # value: video-converter # effect: NoSchedule # --- Чат ------------------------------------------------------------------ chatbox: # Часть ключа асимметричного шифрования чатов, 32 символа. # Генерация: openssl rand -hex 16 wrappingKey: "" # --- Видеозвонки ---------------------------------------------------------- livekit: url: "" apiKey: "" apiSecret: "" # --- Nanabush Player ------------------------------------------------------ # Плеер учебных материалов: SCORM 1.2/2004, cmi5, xAPI, нативные курсы, # тесты и эссе. Полное описание контракта — docs/nanabush-player-deployment.md # в репозитории HRBox. # # В облаке плеер живёт на отдельном поддомене. В on-premise выделенного # поддомена нет, поэтому плеер монтируется на основной домен под путём # basePath. Практическое следствие: cookie HRBox видны содержимому курсов # (один origin). Если для сторонних SCORM-пакетов нужна изоляция — заводите # отдельный поддомен и обращайтесь в HRBox за облачной схемой. nanabushPlayer: # Отдавать ли учебные материалы через плеер. false — старый проигрыватель. enabled: true # Путь монтирования на основном домене. Пустой и "/" запрещены: корень # занят самим HRBox. basePath: "/nanabush-player" # Issuer launch-тикета. Пусто — https:///lms/player. issuer: "" contractVersion: "v0-current" # Ключи плеера. Оба обязательны и должны отличаться друг от друга. # Генерация каждого: openssl rand -base64 48 keys: ticketHs256: "" sessionHs256: "" # Необязательное кольцо ключей для ротации без простоя: # "kid1:секрет1,kid2:секрет2", текущий ключ подписи — первым. # Секрет не должен содержать запятую (используйте base64url). ticketKeys: "" # Доля запусков, уходящих в новый плеер. 100 — все. rollout: percent: 100 # Разрешить откат на старый проигрыватель, если плеер недоступен legacyFallback: true allowedContentTypes: - document - presentation - video - audio - scorm - cmi5 - xapi - course - native - native_quiz - native_essay # "*" — все арендаторы, включая будущих allowedTenants: - "*" service: # Пусто — <релиз>-nanabush-player name: "" port: 8094 # Публиковать ли путь плеера на основном Ingress. # Выключать имеет смысл только при аварийном откате. ingress: enabled: true deployment: # Создавать ли Deployment и Service плеера. enabled: true replicas: 1 terminationGracePeriodSeconds: 120 # Образ плеера должен уметь работать под путём (а не только в корне # домена). Если ставите старый образ без этой поддержки — переключите # в false, и чарт остановит рендер с объяснением вместо неработающего # плеера в кластере. binaryCapabilities: basePath: true # Secret с ключами плеера. create: false — Secret создаётся вне чарта # (например, внешним vault-оператором), чарт только ссылается на него. existingSecret: create: true name: "hrbox-nanabush-player" keys: ticketHs256: player-hs256-secret sessionHs256: player-session-hs256-secret redisUrl: redis-url ticketKeys: "" ticket: # Время жизни launch-тикета, секунды ttlSeconds: 300 # Время жизни учётных данных обратного канала: сессия плеера + 2 минуты # на расхождение часов credentialTtlSeconds: 28920 maxLifetime: "5m" sessionTtl: "8h" # Только на время первой раскатки кольца ключей: до какого момента # (RFC3339) принимать тикеты без kid. Пусто — не принимать. keylessAcceptedUntil: "" redis: # false — URL собирается из app.redis. # true — полный redis:// или rediss:// URL читается из внешнего # Secret (нужно для ACL, пароля или TLS) и требует # existingSecret.create: false. urlFromExistingSecret: false database: 0 # Итоговый префикс: hrbox:: — разводит несколько # релизов HRBox на одном Dragonfly. keyPrefixSuffix: "nanabush-player" backchannel: # Внутрикластерный адрес HRBox. Пусто — <релиз>-web. host: "" schemes: "http" allowPrivateIps: true packageFetchMaxBytes: "5242880" # Транспорт должен вмещать самый большой поддерживаемый медиафайл packageContentMaxBytes: "2147483648" scormPackageMaxBytes: "1073741824" # Пусто — ограничение по числу файлов в SCORM-пакете берётся из # умолчаний приложения (4000) scormPackageMaxFiles: "" packageFetchTimeout: "15s" # Таймаут покрывает всю передачу, включая отдачу байтов браузеру # учащегося, поэтому упирается в скорость его канала. Двух минут # не хватало на крупное видео. packageStreamTimeout: "20m" reportTimeout: "30s" # Очередь отправки учебных событий в HRBox. forwarder: queueSize: "1000" workers: "4" maxAttempts: "5" initialBackoff: "1s" maxBackoff: "30s" perAttemptTimeout: "30s" deadLetterSize: "256" claimIdle: "5m" pollInterval: "1s" rateLimitEventsPerMinute: "600" rateLimitBatchesPerMinute: "120" rateLimitPayloadBytesPerMinute: "8388608" log: level: info format: json # Метрики отдаются на отдельном порту, который не публикуется наружу: # содержимое курсов не должно читать эксплуатационные метрики. metrics: enabled: true port: 9090 probes: readiness: path: /readyz initialDelaySeconds: 5 periodSeconds: 5 timeoutSeconds: 2 failureThreshold: 6 liveness: path: /healthz initialDelaySeconds: 20 periodSeconds: 20 timeoutSeconds: 2 failureThreshold: 3 # --- Фоновые задачи ------------------------------------------------------- # Формат: "топик:количество-воркеров" launchpad: topics: "launcher:1,file-processor:1,image-processor:1,send-mail:1,send-im:1,send-bell:1,send-push:1,backup:1,cleaning:1" sms: senderName: "HRBOX" # --- Внешние интеграции --------------------------------------------------- integrations: telegram: # Прямой API Telegram; для установок без доступа к нему укажите прокси apiUrl: "https://api.telegram.org/bot" google: enabled: "false" # Client ID публичный (уходит в браузер), secret — в Secret чарта clientId: "692956564858-ccapt35khk7tmadl17b3879ht2cropp6.apps.googleusercontent.com" clientSecret: "" glagol: partnerId: "ab230ee1-6946-43b9-8kfa-447beb8348b0" apiUrl: "https://api.glagol.online/glagol-api" # Привязка мобильных приложений к домену: без неё ссылки из писем и пушей # открываются в браузере вместо приложения. По умолчанию — штатные # приложения HRBox; меняйте, только если у вас собственная сборка. mobileApps: android: - packageName: "io.hrbox.hrboxapp" sha256CertFingerprints: - "DE:75:B2:CA:CB:50:96:02:8D:E1:07:4F:CE:E9:92:1C:4C:ED:87:B0:64:12:1A:69:27:7B:D2:B5:1A:23:31:70" apple: appIds: - "DX67FD7GQJ.io.hrbox.app" yandex: clientId: "" clientPassword: "" slack: clientId: "" clientSecret: "" verificationToken: "" # --- HRBox Hub ------------------------------------------------------------ # Лицензирование и общие сервисы. Токен выдают сотрудники HRBox. hub: url: "https://hub.hrbox.io" token: "" # --- AI ------------------------------------------------------------------- ai: docsIndexEnabled: "true" semanticIndexEnabled: "true" semanticIndexUseBatch: "true" yandex: folderId: "" apiKey: "" # --- Трассировка ---------------------------------------------------------- # Включает OpenTelemetry в PHP и sidecar-коллектор в поде web. tracing: enabled: false exporterUrl: "http://localhost:4318" # Куда коллектор пересылает трейсы (Tempo, Jaeger) tempoUrl: "" # --- Безопасность --------------------------------------------------------- security: # "true" разрешает встроенному iframe полный доступ к родительскому окну. # Для production рекомендуется "false". iframeFullAccess: "false" # ============================================================================ # Секреты приложения # ============================================================================ # Эти значения вместе с паролями из app.* складываются в один Kubernetes # Secret, а контейнеры читают его через secretKeyRef. secrets: # Имя Secret, созданного вне чарта. Если задано — чарт свой Secret не # создаёт и берёт все ключи из указанного. Список ключей — в README. existingSecret: "" # Защита cookie от подделки, 32 символа. # Генерация: openssl rand -hex 16 cookieValidationKey: "" # Шифрование данных: пароли интеграций (S3, ADFS и другие). # ВАЖНО: без этого ключа данные не расшифровать. Не теряйте его. # Генерация: openssl rand -base64 48 encryptionKey: "" # Аутентификация вызовов между микросервисами релиза. # Генерация: openssl rand -base64 48 servicesInternalSecret: "" # ============================================================================ # Ingress # ============================================================================ ingress: enabled: true # Обычно "nginx" или "traefik" className: "nginx" # Домен инсталляции. Wildcard (*.hrbox.company.com) — для мультиарендности. host: "hrbox.example.com" # Дополнительные аннотации ingress-контроллера annotations: {} # Максимальный размер загружаемого файла на общих путях. # Загрузка оргструктуры из 1С идёт потоком и имеет собственный лимит. maxBodySize: "10m" tls: enabled: true # kubectl create secret tls hrbox-tls --cert=cert.pem --key=key.pem # либо выпуск через cert-manager secretName: "hrbox-tls" # ============================================================================ # Кластер # ============================================================================ cluster: # Домен служебных имён Kubernetes. Меняйте, только если он нестандартный. domain: "cluster.local" # ============================================================================ # Ресурсы # ============================================================================ # Значения близки к продовым. Незаданные поля не рендерятся, поэтому # компоненту можно оставить только requests. resources: # PHP-FPM: HTTP-запросы, API, веб-интерфейс app: requests: cpu: "1" memory: "2Gi" ephemeralStorage: "64Mi" limits: cpu: "2" memory: "2Gi" ephemeralStorage: "2Gi" # nginx в поде web: проксирует запросы в PHP-FPM nginx: requests: cpu: "0.1" memory: "256Mi" ephemeralStorage: "64Mi" limits: cpu: "0.5" memory: "256Mi" ephemeralStorage: "512Mi" # Фоновые задачи: конвертация файлов, почта, отчёты worker: requests: cpu: "0.6" memory: "640Mi" ephemeralStorage: "4Gi" limits: cpu: "2" memory: "4Gi" ephemeralStorage: "8Gi" # Планировщик задач по расписанию conductor: requests: cpu: "0.25" memory: "128Mi" ephemeralStorage: "64Mi" limits: cpu: "0.7" memory: "384Mi" ephemeralStorage: "64Mi" chatbox: requests: cpu: "0.3" memory: "96Mi" ephemeralStorage: "128Mi" limits: cpu: "1" memory: "256Mi" ephemeralStorage: "256Mi" geonames: requests: cpu: "0.1" memory: "196Mi" ephemeralStorage: "64Mi" limits: cpu: "0.5" memory: "256Mi" ephemeralStorage: "64Mi" goworker: requests: cpu: "0.1" memory: "196Mi" ephemeralStorage: "64Mi" limits: cpu: "0.5" memory: "256Mi" ephemeralStorage: "64Mi" kedoca: requests: cpu: "0.1" memory: "196Mi" ephemeralStorage: "64Mi" limits: cpu: "1" memory: "256Mi" ephemeralStorage: "64Mi" fileProcessor: requests: cpu: "0.5" memory: "512Mi" ephemeralStorage: "2Gi" limits: cpu: "1" memory: "1Gi" ephemeralStorage: "2Gi" # Конвертация видео: тяжёлый профиль, отдельные ноды fileProcessorVideo: requests: cpu: "4" memory: "4Gi" ephemeralStorage: "40Gi" limits: cpu: "8" memory: "8Gi" ephemeralStorage: "44Gi" nanabushPlayer: requests: cpu: "0.1" memory: "192Mi" limits: memory: "512Mi" dragonfly: requests: cpu: "0.1" memory: "256Mi" limits: cpu: "1" memory: "1Gi" nats: requests: cpu: "0.1" memory: "256Mi" limits: cpu: "1" memory: "2Gi" # Разовые задачи: миграции, обновление кластера jobs: requests: cpu: "0.5" memory: "1Gi" ephemeralStorage: "64Mi" limits: cpu: "2" memory: "4Gi" ephemeralStorage: "256Mi" # ============================================================================ # NATS JetStream # ============================================================================ nats: # Обязателен для работы HRBox. Выключайте только если ставите NATS отдельно # и указали его адрес в app.nats.url. enabled: true # Для отказоустойчивости — 3 или 5. Должно совпадать с cluster.replicas. replicas: 3 jetstream: enabled: true # Хранение в памяти — для небольших установок memStorage: enabled: true size: "2Gi" # Хранение на диске — для production fileStorage: enabled: false size: "4Gi" storageDirectory: "/data" # Для JetStream нужен быстрый диск storageClassName: "fast-ssd" cluster: enabled: true # Должно совпадать с nats.replicas replicas: 3 # Автоматическая перезагрузка конфигурации без рестарта сервера reloader: enabled: true terminationGracePeriodSeconds: 120 # ============================================================================ # Dragonfly (Redis-совместимый кеш) # ============================================================================ dragonfly: # false — если Redis разворачивается отдельно; тогда укажите его в app.redis. enabled: true # Ограничение памяти. Раскомментируйте при необходимости. # maxmemory: "256M"