Актуализация чарта по продовому .helm из HRBOX. Nanabush Player перенесён из прода и упрощён под one-release-топологию on-premise: без карт env/ci_dc, но с сохранёнными инвариантами (audience = https://<host>, basePath отдельно от aud, allowlist обратного канала только на внутрикластерный web, метрики на непубликуемом порту). Выделенного поддомена в on-premise нет, поэтому плеер монтируется на основной домен под /nanabush-player. Три переключателя для аварийного отката сохранены. Из прода также перенесены: пул конвертации видео, PodDisruptionBudget для web, OpenTelemetry-сайдкар, assetlinks, набор location в nginx (/healthz, /health-check, потоковый /api/v1/integration/commit, /ai/, sw.js, шрифты). Версии образов подтянуты к продовым. Приведение чарта в порядок: все образы в блоке image, imagePullSecrets в настройках, девять одинаковых define ресурсов заменены одним хелпером, удалено ~100 строк мёртвого кода в _helpers.tpl, пароли и ключи уехали в Secret и читаются через secretKeyRef, добавлены 00-validate.yaml и NOTES.txt. Исправлено в 2.x: - SERVICES_INTERNAL_SECRET имел захардкоженное значение по умолчанию, то есть все установки, где его не заполнили, работали на одном секрете межсервисной аутентификации; - cluster.domain игнорировался: маршруты кластера NATS были захардкожены на cluster.local; - CLUSTER_ADVERTISE без сегмента svc — ноды NATS объявляли соседям недостижимый адрес; - nats.replicas и nats.cluster.replicas задавались независимо, при расхождении часть нод не входила в кластер; - пробы web проверяли только TCP-порт 9000, поэтому под с неработающим PHP считался готовым; - внутренние URL были захардкожены строками hrbox-* и молча ломались при nameOverride. Имена объектов и селекторы Deployment не менялись — обновление 2.x -> 3.0 не пересоздаёт объекты. Переехавшие ключи values.yaml чарт распознаёт и останавливает установку с подсказкой; порядок перехода — в CHANGELOG.md. Проверено: helm lint чистый; отрендерены 4 конфигурации (дефолт, всё включено, плеер и инфра выключены, nameOverride); структурная проверка рендера без замечаний; 20 негативных сценариев срабатывают с ожидаемыми сообщениями; реалистичный values.yaml из 2.x последовательно ловится всеми шестью guard'ами. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
348 lines
14 KiB
Smarty
348 lines
14 KiB
Smarty
{{/*
|
||
============================================================================
|
||
Переменные окружения HRBox
|
||
============================================================================
|
||
|
||
envs_all включается во все контейнеры, которым нужен конфиг приложения:
|
||
web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
|
||
и джобы миграций. Один общий блок проще расходящихся наборов, и именно так
|
||
устроено продовое окружение.
|
||
|
||
Чувствительные значения приходят через secretKeyRef из секрета приложения
|
||
(00-app-secret.yaml), а не открытым текстом в спеке пода.
|
||
*/}}
|
||
{{- define "envs_all" }}
|
||
# --- Приложение -----------------------------------------------------------
|
||
- name: INSTANCE_NAME
|
||
value: {{ .Values.app.instanceName | quote }}
|
||
- name: DEFAULT_TENANT_HOSTNAME
|
||
value: {{ .Values.app.defaultTenantHostname | quote }}
|
||
- name: APP_ENV
|
||
value: "prod"
|
||
- name: APP_PORT
|
||
value: "80"
|
||
- name: YII_DEBUG
|
||
value: {{ .Values.app.debug | quote }}
|
||
- name: YII_TRACE_LEVEL
|
||
value: "0"
|
||
- name: AUTH_HOST
|
||
value: {{ .Values.app.authHost | quote }}
|
||
- name: SINGLE_TENANT
|
||
value: {{ .Values.app.singleTenant | quote }}
|
||
- name: FORCE_HTTPS
|
||
value: {{ .Values.app.forceHttps | quote }}
|
||
- name: ENABLE_FRONTEND
|
||
value: {{ .Values.app.front2 | quote }}
|
||
- name: LAUNCHPAD_TOPICS
|
||
value: {{ .Values.app.launchpad.topics | quote }}
|
||
- name: SMS_SENDER_NAME
|
||
value: {{ .Values.app.sms.senderName | quote }}
|
||
- name: IFRAME_FULL_ACCESS
|
||
value: {{ .Values.app.security.iframeFullAccess | quote }}
|
||
- name: LDAPTLS_REQCERT
|
||
value: "never"
|
||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "APP_COOKIE_VALIDATION_KEY" "key" "cookie-validation-key") | nindent 0 }}
|
||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "APP_ENCRYPTION_KEY" "key" "encryption-key") | nindent 0 }}
|
||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "SERVICES_INTERNAL_SECRET" "key" "services-internal-secret") | nindent 0 }}
|
||
|
||
# --- Своя политика конфиденциальности -------------------------------------
|
||
- name: ALLOW_CUSTOM_POLICY_URLS
|
||
value: {{ .Values.app.customPolicy.enabled | quote }}
|
||
{{- if .Values.app.customPolicy.enabled }}
|
||
- name: CUSTOM_PRIVACY_POLICY_URL
|
||
value: {{ .Values.app.customPolicy.privacyUrl | default "https://hrbox.io/policy" | quote }}
|
||
- name: CUSTOM_TERMS_URL
|
||
value: {{ .Values.app.customPolicy.termsUrl | default "https://hrbox.io/terms" | quote }}
|
||
{{- else }}
|
||
- name: CUSTOM_PRIVACY_POLICY_URL
|
||
value: ""
|
||
- name: CUSTOM_TERMS_URL
|
||
value: ""
|
||
{{- end }}
|
||
|
||
# --- PostgreSQL -----------------------------------------------------------
|
||
- name: POSTGRES_VHOST
|
||
value: {{ .Values.app.postgres.host | quote }}
|
||
- name: POSTGRES_PORT
|
||
value: {{ .Values.app.postgres.port | quote }}
|
||
- name: POSTGRES_DB
|
||
value: {{ .Values.app.postgres.database | quote }}
|
||
- name: POSTGRES_USER
|
||
value: {{ .Values.app.postgres.user | quote }}
|
||
- name: POSTGRES_CITUS
|
||
value: {{ .Values.app.postgres.citus | quote }}
|
||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "POSTGRES_PASSWORD" "key" "postgres-password") | nindent 0 }}
|
||
|
||
# --- Redis / Dragonfly ----------------------------------------------------
|
||
- name: REDIS_HOST
|
||
value: {{ include "hrbox.redisHost" . | quote }}
|
||
- name: REDIS_PORT
|
||
value: {{ .Values.app.redis.port | quote }}
|
||
- name: REDIS_CONNECTION
|
||
value: {{ printf "tcp://%s:%s" (include "hrbox.redisHost" .) (.Values.app.redis.port | toString) | quote }}
|
||
|
||
# --- NATS -----------------------------------------------------------------
|
||
- name: BROKER
|
||
value: "nats"
|
||
- name: NATS_URL
|
||
value: {{ include "hrbox.natsUrl" . | quote }}
|
||
# Число реплик JetStream-стримов должно совпадать с размером кластера NATS,
|
||
# иначе стрим создаётся в одном экземпляре и теряется вместе со своей нодой.
|
||
- name: NATS_STREAM_REPLICAS
|
||
{{- if and .Values.nats.enabled .Values.nats.cluster.enabled }}
|
||
value: {{ .Values.nats.cluster.replicas | quote }}
|
||
{{- else }}
|
||
value: "1"
|
||
{{- end }}
|
||
|
||
# --- S3 -------------------------------------------------------------------
|
||
- name: S3_ENDPOINT
|
||
value: {{ .Values.app.s3.endpoint | quote }}
|
||
- name: S3_BUCKET
|
||
value: {{ .Values.app.s3.bucket | quote }}
|
||
- name: S3_PREFIX
|
||
value: {{ .Values.app.s3.prefix | quote }}
|
||
- name: S3_REGION
|
||
value: {{ .Values.app.s3.region | quote }}
|
||
- name: S3_VERSION
|
||
value: {{ .Values.app.s3.version | quote }}
|
||
- name: S3_PATH_STYLE
|
||
value: {{ .Values.app.s3.pathStyle | quote }}
|
||
- name: S3_MULTIPART
|
||
value: {{ .Values.app.s3.multipart | quote }}
|
||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "S3_KEY" "key" "s3-key") | nindent 0 }}
|
||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "S3_SECRET" "key" "s3-secret") | nindent 0 }}
|
||
|
||
# --- Почта ----------------------------------------------------------------
|
||
- name: SENDER_ENV
|
||
value: "PROD"
|
||
- name: SENDER_DEV_EMAIL
|
||
value: ""
|
||
- name: SMTP_HOST
|
||
value: {{ .Values.app.smtp.host | quote }}
|
||
- name: SMTP_PORT
|
||
value: {{ .Values.app.smtp.port | quote }}
|
||
- name: SMTP_USERNAME
|
||
value: {{ .Values.app.smtp.user | quote }}
|
||
- name: SMTP_FROM
|
||
value: {{ .Values.app.smtp.from | quote }}
|
||
- name: SMTP_FROM_HOST
|
||
value: {{ .Values.app.smtp.fromHost | quote }}
|
||
- name: SMTP_SECURITY_TYPE
|
||
value: {{ .Values.app.smtp.securityType | quote }}
|
||
- name: SMTP_SSL_ALLOW_SELF_SIGNED
|
||
value: {{ .Values.app.smtp.sslAllowSelfSigned | quote }}
|
||
- name: SMTP_SSL_VERIFY_PEER
|
||
value: {{ .Values.app.smtp.sslVerifyPeer | quote }}
|
||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "SMTP_PASSWORD" "key" "smtp-password") | nindent 0 }}
|
||
|
||
# --- Внутренние сервисы ---------------------------------------------------
|
||
- name: GEONAMES_URL
|
||
value: {{ include "hrbox.geonamesUrl" . | quote }}
|
||
- name: GOWORKER_URL
|
||
value: {{ include "hrbox.goworkerUrl" . | quote }}
|
||
- name: GOWORKER_PUSH_MIN_INTERVAL
|
||
value: {{ .Values.app.goworker.pushMinInterval | quote }}
|
||
- name: GOWORKER_SENTRY_DSN
|
||
value: {{ .Values.app.sentry.goworkerDsn | quote }}
|
||
- name: KEDOCA_URL
|
||
value: {{ include "hrbox.kedocaUrl" . | quote }}
|
||
- name: TSP_URL
|
||
value: {{ .Values.app.kedoca.tspUrl | quote }}
|
||
- name: APP_INTERNAL_URL
|
||
value: {{ .Values.app.videoConverter.internalUrl | default (printf "http://%s" (include "hrbox.component" (dict "ctx" . "name" "web"))) | quote }}
|
||
- name: CONDUCTOR_TOPIC_CONDUCTOR
|
||
value: "conductor"
|
||
- name: CONDUCTOR_TOPIC_LAUNCHER
|
||
value: "launcher"
|
||
- name: PYTHONUNBUFFERED
|
||
value: "1"
|
||
- name: DOCCONV_MAX_PARALLEL_TASKS
|
||
value: {{ .Values.app.fileProcessor.docconvMaxParallelTasks | quote }}
|
||
|
||
# --- HRBox Hub ------------------------------------------------------------
|
||
- name: HUB_URL
|
||
value: {{ .Values.app.hub.url | quote }}
|
||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "HUB_TOKEN" "key" "hub-token") | nindent 0 }}
|
||
|
||
# --- Nanabush Player ------------------------------------------------------
|
||
{{- include "envs_nanabush_player" . }}
|
||
|
||
# --- Чат ------------------------------------------------------------------
|
||
- name: CHATBOX_SENTRY_DSN
|
||
value: {{ .Values.app.sentry.chatboxDsn | quote }}
|
||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "CHATBOX_WRAPPING_KEY" "key" "chatbox-wrapping-key") | nindent 0 }}
|
||
|
||
# --- Видеозвонки (LiveKit) ------------------------------------------------
|
||
- name: LIVEKIT_URL
|
||
value: {{ .Values.app.livekit.url | quote }}
|
||
- name: LIVEKIT_API_KEY
|
||
value: {{ .Values.app.livekit.apiKey | quote }}
|
||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "LIVEKIT_API_SECRET" "key" "livekit-api-secret") | nindent 0 }}
|
||
|
||
# --- AI -------------------------------------------------------------------
|
||
- name: AI_DOCS_INDEX_ENABLED
|
||
value: {{ .Values.app.ai.docsIndexEnabled | quote }}
|
||
- name: AI_SEMANTIC_INDEX_ENABLED
|
||
value: {{ .Values.app.ai.semanticIndexEnabled | quote }}
|
||
- name: AI_SEMANTIC_INDEX_USE_BATCH
|
||
value: {{ .Values.app.ai.semanticIndexUseBatch | quote }}
|
||
- name: YANDEX_CLOUD_AI_FOLDER_ID
|
||
value: {{ .Values.app.ai.yandex.folderId | quote }}
|
||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "YANDEX_CLOUD_AI_API_KEY" "key" "yandex-ai-api-key") | nindent 0 }}
|
||
|
||
# --- Внешние интеграции ---------------------------------------------------
|
||
- name: TELEGRAM_API_URL
|
||
value: {{ .Values.app.integrations.telegram.apiUrl | quote }}
|
||
- name: AUTH_GOOGLE_ENABLED
|
||
value: {{ .Values.app.integrations.google.enabled | quote }}
|
||
- name: GOOGLE_CLIENT_ID
|
||
value: {{ .Values.app.integrations.google.clientId | quote }}
|
||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "GOOGLE_CLIENT_SECRET" "key" "google-client-secret") | nindent 0 }}
|
||
- name: YANDEX_CLIENT_ID
|
||
value: {{ .Values.app.yandex.clientId | quote }}
|
||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "YANDEX_CLIENT_PASSWORD" "key" "yandex-client-password") | nindent 0 }}
|
||
- name: SLACK_APP_CLIENT_ID
|
||
value: {{ .Values.app.slack.clientId | quote }}
|
||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "SLACK_APP_CLIENT_SECRET" "key" "slack-client-secret") | nindent 0 }}
|
||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "SLACK_APP_VERIFICATION_TOKEN" "key" "slack-verification-token") | nindent 0 }}
|
||
- name: GLAGOL_PARTNER_ID
|
||
value: {{ .Values.app.integrations.glagol.partnerId | quote }}
|
||
- name: GLAGOL_API_URL
|
||
value: {{ .Values.app.integrations.glagol.apiUrl | quote }}
|
||
|
||
# --- Sentry ---------------------------------------------------------------
|
||
- name: SENTRY_DSN
|
||
value: {{ .Values.app.sentry.dsn | quote }}
|
||
- name: SENTRY_DSN_LAUNCHPAD
|
||
value: {{ .Values.app.sentry.launchpadDsn | default .Values.app.sentry.dsn | quote }}
|
||
- name: SENTRY_DSN_CONDUCTOR
|
||
value: {{ .Values.app.sentry.conductorDsn | default .Values.app.sentry.dsn | quote }}
|
||
- name: SENTRY_ENVIRONMENT
|
||
value: {{ .Values.app.sentry.environment | quote }}
|
||
- name: SENTRY_RELEASE
|
||
value: {{ .Values.image.hrbox | quote }}
|
||
|
||
# --- Метаданные пода ------------------------------------------------------
|
||
- name: POD_NAME
|
||
valueFrom:
|
||
fieldRef:
|
||
fieldPath: metadata.name
|
||
- name: POD_NAMESPACE
|
||
valueFrom:
|
||
fieldRef:
|
||
fieldPath: metadata.namespace
|
||
- name: POD_IP
|
||
valueFrom:
|
||
fieldRef:
|
||
fieldPath: status.podIP
|
||
- name: NODE_NAME
|
||
valueFrom:
|
||
fieldRef:
|
||
fieldPath: spec.nodeName
|
||
{{- end }}
|
||
|
||
{{/*
|
||
Настройки Nanabush Player на стороне HRBox.
|
||
|
||
NANABUSH_PLAYER_AUDIENCE и NANABUSH_PLAYER_PUBLIC_ORIGIN всегда равны:
|
||
audience тикета — это origin браузера без пути, а путь монтирования едет
|
||
отдельной переменной NANABUSH_PLAYER_BASE_PATH.
|
||
*/}}
|
||
{{- define "envs_nanabush_player" -}}
|
||
{{- $player := .Values.app.nanabushPlayer }}
|
||
- name: NANABUSH_PLAYER_ENABLED
|
||
value: {{ $player.enabled | quote }}
|
||
{{- if $player.deployment.enabled }}
|
||
- name: NANABUSH_PLAYER_PUBLIC_ORIGIN
|
||
value: {{ include "nanabushPlayer.publicOrigin" . | quote }}
|
||
- name: NANABUSH_PLAYER_AUDIENCE
|
||
value: {{ include "nanabushPlayer.publicOrigin" . | quote }}
|
||
- name: NANABUSH_PLAYER_BASE_PATH
|
||
value: {{ include "nanabushPlayer.basePath" . | quote }}
|
||
- name: NANABUSH_PLAYER_INTERNAL_ORIGIN
|
||
value: {{ include "nanabushPlayer.internalOrigin" . | quote }}
|
||
- name: NANABUSH_PLAYER_ISSUER
|
||
value: {{ include "nanabushPlayer.issuer" . | quote }}
|
||
- name: NANABUSH_PLAYER_CONTRACT_VERSION
|
||
value: {{ $player.contractVersion | quote }}
|
||
- name: NANABUSH_PLAYER_PLAYER_VERSION
|
||
value: {{ include "nanabushPlayer.version" . | quote }}
|
||
- name: NANABUSH_PLAYER_TICKET_TTL_SECONDS
|
||
value: {{ $player.deployment.ticket.ttlSeconds | quote }}
|
||
- name: NANABUSH_PLAYER_SESSION_TTL_SECONDS
|
||
value: {{ $player.deployment.ticket.credentialTtlSeconds | quote }}
|
||
- name: NANABUSH_PLAYER_PACKAGE_CONTENT_MAX_BYTES
|
||
value: {{ $player.deployment.backchannel.packageContentMaxBytes | quote }}
|
||
- name: NANABUSH_PLAYER_SCORM_PACKAGE_MAX_BYTES
|
||
value: {{ $player.deployment.backchannel.scormPackageMaxBytes | quote }}
|
||
{{- with $player.deployment.backchannel.scormPackageMaxFiles }}
|
||
- name: NANABUSH_PLAYER_SCORM_PACKAGE_MAX_FILES
|
||
value: {{ . | quote }}
|
||
{{- end }}
|
||
- name: NANABUSH_PLAYER_LEGACY_FALLBACK
|
||
value: {{ $player.rollout.legacyFallback | quote }}
|
||
- name: NANABUSH_PLAYER_ALLOWED_CONTENT_TYPES
|
||
value: {{ join "," $player.rollout.allowedContentTypes | quote }}
|
||
- name: NANABUSH_PLAYER_ALLOWED_TENANTS
|
||
value: {{ join "," $player.rollout.allowedTenants | quote }}
|
||
- name: NANABUSH_PLAYER_ROLLOUT_PERCENT
|
||
value: {{ $player.rollout.percent | quote }}
|
||
{{- end }}
|
||
{{- end -}}
|
||
|
||
{{/*
|
||
Ключ подписи launch-тикета. Живёт только в PHP-контейнерах, которые выпускают
|
||
тикеты: nginx и вспомогательным контейнерам он не нужен.
|
||
*/}}
|
||
{{- define "envs_nanabush_player_signing" -}}
|
||
{{- $cfg := .Values.app.nanabushPlayer.deployment }}
|
||
{{- if $cfg.enabled }}
|
||
- name: NANABUSH_PLAYER_HS256_SECRET
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: {{ include "nanabushPlayer.secretName" . | quote }}
|
||
key: {{ required "Нужно имя ключа ticketHs256 в секрете Nanabush Player" $cfg.existingSecret.keys.ticketHs256 | quote }}
|
||
{{- with $cfg.existingSecret.keys.ticketKeys }}
|
||
# Кольцо ключей launch-тикета: HRBox подписывает первым ключом, Player
|
||
# принимает все. Тот же ключ секрета читает и сам Player, поэтому ротация —
|
||
# это одно значение на обе стороны.
|
||
- name: NANABUSH_PLAYER_TICKET_KEYS
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: {{ include "nanabushPlayer.secretName" $ | quote }}
|
||
key: {{ . | quote }}
|
||
{{- end }}
|
||
{{- end }}
|
||
{{- end -}}
|
||
|
||
{{/* Криптографические настройки сервиса электронной подписи. */}}
|
||
{{- define "envs_kedoca" }}
|
||
- name: ROOT_CA_PASS
|
||
value: {{ .Values.app.kedoca.rootCaPass | quote }}
|
||
- name: KEDO_ENGINE
|
||
value: {{ .Values.app.kedoca.engine | quote }}
|
||
- name: KEDO_ALGORITHM
|
||
value: {{ .Values.app.kedoca.algorithm | quote }}
|
||
- name: KEDO_PKEYOPT
|
||
value: {{ .Values.app.kedoca.pkeyopt | quote }}
|
||
{{- end }}
|
||
|
||
{{/* OpenTelemetry — только когда app.tracing.enabled. */}}
|
||
{{- define "envs_tracing" }}
|
||
- name: OTEL_PHP_AUTOLOAD_ENABLED
|
||
value: "true"
|
||
- name: OTEL_EXPORTER_OTLP_ENDPOINT
|
||
value: {{ .Values.app.tracing.exporterUrl | quote }}
|
||
- name: OTEL_SERVICE_NAME
|
||
value: "hrbox-app"
|
||
- name: OTEL_TRACES_EXPORTER
|
||
value: "otlp"
|
||
- name: OTEL_EXPORTER_OTLP_PROTOCOL
|
||
value: "http/protobuf"
|
||
- name: OTEL_PROPAGATORS
|
||
value: "baggage,tracecontext"
|
||
- name: OTEL_LOG_LEVEL
|
||
value: "info"
|
||
{{- end }}
|