Актуализация чарта по продовому .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>
232 lines
10 KiB
Smarty
232 lines
10 KiB
Smarty
{{/*
|
||
============================================================================
|
||
Общие хелперы чарта HRBox
|
||
============================================================================
|
||
|
||
Правило именования: все объекты называются "<имя чарта>-<компонент>"
|
||
(hrbox-web, hrbox-worker, ...). Имя чарта можно переопределить через
|
||
nameOverride, но по умолчанию оно равно "hrbox" — так же, как в чарте 2.x,
|
||
поэтому обновление 2.x -> 3.x не пересоздаёт объекты.
|
||
*/}}
|
||
|
||
{{/* Базовое имя релиза: "hrbox" или nameOverride. */}}
|
||
{{- define "hrbox.name" -}}
|
||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||
{{- end -}}
|
||
|
||
{{/* Имя чарта с версией — для лейбла helm.sh/chart. */}}
|
||
{{- define "hrbox.chart" -}}
|
||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||
{{- end -}}
|
||
|
||
{{/*
|
||
Полное имя объекта компонента.
|
||
|
||
Usage: {{ include "hrbox.component" (dict "ctx" . "name" "web") }} -> hrbox-web
|
||
*/}}
|
||
{{- define "hrbox.component" -}}
|
||
{{- printf "%s-%s" (include "hrbox.name" .ctx) .name | trunc 63 | trimSuffix "-" -}}
|
||
{{- end -}}
|
||
|
||
{{/*
|
||
Селектор пода. ВАЖНО: spec.selector в Deployment неизменяем, поэтому набор
|
||
лейблов здесь совпадает с чартом 2.x (один лейбл "service") и меняться не должен.
|
||
|
||
Usage: {{- include "hrbox.selectorLabels" (dict "ctx" . "name" "web") | nindent 6 }}
|
||
*/}}
|
||
{{- define "hrbox.selectorLabels" -}}
|
||
service: {{ include "hrbox.component" (dict "ctx" .ctx "name" .name) }}
|
||
{{- end -}}
|
||
|
||
{{/*
|
||
Лейблы объекта. Лейбл "app" сохранён из чарта 2.x — на него опираются
|
||
привычные команды вида "kubectl get pods -l app=worker".
|
||
|
||
Usage: {{- include "hrbox.labels" (dict "ctx" . "name" "web") | nindent 4 }}
|
||
*/}}
|
||
{{- define "hrbox.labels" -}}
|
||
app: {{ .name }}
|
||
app.kubernetes.io/name: {{ include "hrbox.name" .ctx }}
|
||
app.kubernetes.io/component: {{ .name }}
|
||
app.kubernetes.io/instance: {{ .ctx.Release.Name }}
|
||
app.kubernetes.io/managed-by: {{ .ctx.Release.Service }}
|
||
app.kubernetes.io/version: {{ .ctx.Chart.AppVersion | quote }}
|
||
helm.sh/chart: {{ include "hrbox.chart" .ctx }}
|
||
{{- end -}}
|
||
|
||
{{/*
|
||
Секреты для доступа к приватному Docker-реестру.
|
||
|
||
Usage: {{- include "hrbox.imagePullSecrets" . | nindent 6 }}
|
||
*/}}
|
||
{{- define "hrbox.imagePullSecrets" -}}
|
||
{{- if .Values.imagePullSecrets }}
|
||
imagePullSecrets:
|
||
{{- range .Values.imagePullSecrets }}
|
||
- name: {{ .name | quote }}
|
||
{{- end }}
|
||
{{- end }}
|
||
{{- end -}}
|
||
|
||
{{/*
|
||
Тег из ссылки на образ: "registry/repo:1.2.3" -> "1.2.3".
|
||
Двоеточие ищется только в последнем сегменте пути, чтобы не спутать тег
|
||
с портом реестра ("registry:5000/repo").
|
||
*/}}
|
||
{{- define "hrbox.imageTag" -}}
|
||
{{- $lastSegment := splitList "/" . | last -}}
|
||
{{- if contains ":" $lastSegment -}}
|
||
{{- splitList ":" $lastSegment | last -}}
|
||
{{- end -}}
|
||
{{- end -}}
|
||
|
||
{{/*
|
||
============================================================================
|
||
Секрет приложения
|
||
============================================================================
|
||
|
||
Чувствительные значения (пароли БД и SMTP, ключи шифрования, токены) не
|
||
попадают в env-блоки Deployment открытым текстом: чарт складывает их в один
|
||
Secret, а контейнеры читают его через secretKeyRef. Полный список ключей —
|
||
в README, раздел "Секреты".
|
||
|
||
secrets.existingSecret позволяет подставить Secret, созданный вне чарта
|
||
(например, из внешнего vault-оператора) — тогда чарт свой Secret не создаёт.
|
||
*/}}
|
||
{{/*
|
||
Адреса внутренних сервисов.
|
||
|
||
Сервисы релиза адресуются по именам, которые создаёт этот же чарт, поэтому
|
||
пустое значение в values резолвится в имя из hrbox.component: адреса не
|
||
разъезжаются при nameOverride и их не нужно править вручную. Непустое
|
||
значение используется как есть — для сервиса за пределами релиза.
|
||
*/}}
|
||
{{- define "hrbox.geonamesUrl" -}}
|
||
{{- .Values.app.geonames.url | default (printf "http://%s:8181" (include "hrbox.component" (dict "ctx" . "name" "geonames"))) -}}
|
||
{{- end -}}
|
||
|
||
{{- define "hrbox.goworkerUrl" -}}
|
||
{{- .Values.app.goworker.url | default (printf "http://%s:8686" (include "hrbox.component" (dict "ctx" . "name" "goworker"))) -}}
|
||
{{- end -}}
|
||
|
||
{{- define "hrbox.kedocaUrl" -}}
|
||
{{- .Values.app.kedoca.url | default (printf "http://%s:8558" (include "hrbox.component" (dict "ctx" . "name" "kedoca"))) -}}
|
||
{{- end -}}
|
||
|
||
{{- define "hrbox.redisHost" -}}
|
||
{{- .Values.app.redis.host | default (include "hrbox.component" (dict "ctx" . "name" "dragonfly")) -}}
|
||
{{- end -}}
|
||
|
||
{{- define "hrbox.natsUrl" -}}
|
||
{{- .Values.app.nats.url | default (printf "nats://%s:4222" (include "hrbox.component" (dict "ctx" . "name" "nats"))) -}}
|
||
{{- end -}}
|
||
|
||
{{- define "hrbox.secretName" -}}
|
||
{{- if .Values.secrets.existingSecret -}}
|
||
{{- .Values.secrets.existingSecret -}}
|
||
{{- else -}}
|
||
{{- include "hrbox.component" (dict "ctx" . "name" "secrets") -}}
|
||
{{- end -}}
|
||
{{- end -}}
|
||
|
||
{{/*
|
||
Одна переменная окружения из секрета приложения.
|
||
|
||
Usage: {{ include "hrbox.secretEnv" (dict "ctx" . "env" "POSTGRES_PASSWORD" "key" "postgres-password") }}
|
||
*/}}
|
||
{{- define "hrbox.secretEnv" -}}
|
||
- name: {{ .env }}
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: {{ include "hrbox.secretName" .ctx | quote }}
|
||
key: {{ .key | quote }}
|
||
{{- end -}}
|
||
|
||
{{/*
|
||
============================================================================
|
||
Nanabush Player
|
||
============================================================================
|
||
|
||
On-premise-топология Player'а отличается от облачной: выделенного поддомена
|
||
нет, поэтому Player живёт на основном домене HRBox под путём basePath
|
||
(по умолчанию /nanabush-player). Отсюда следуют три инварианта, которые
|
||
проверяет 00-validate.yaml:
|
||
|
||
* audience тикета = https://<ingress.host> (origin без пути)
|
||
* basePath = отдельная переменная, в aud не входит
|
||
* issuer тикета = https://<ingress.host>/lms/player
|
||
|
||
Подробности контракта — docs/nanabush-player-deployment.md в репозитории HRBox.
|
||
*/}}
|
||
|
||
{{- define "nanabushPlayer.host" -}}
|
||
{{- required "Для Nanabush Player нужен непустой ingress.host" .Values.ingress.host -}}
|
||
{{- end -}}
|
||
|
||
{{- define "nanabushPlayer.publicOrigin" -}}
|
||
{{- printf "https://%s" (include "nanabushPlayer.host" .) -}}
|
||
{{- end -}}
|
||
|
||
{{/*
|
||
Путь монтирования Player'а на основном домене. Пустое значение и "/" запрещены:
|
||
это отдало бы Player'у корень, занятый самим HRBox.
|
||
*/}}
|
||
{{- define "nanabushPlayer.basePath" -}}
|
||
{{- $path := .Values.app.nanabushPlayer.basePath | default "/nanabush-player" -}}
|
||
{{- $path | trimSuffix "/" -}}
|
||
{{- end -}}
|
||
|
||
{{- define "nanabushPlayer.issuer" -}}
|
||
{{- if .Values.app.nanabushPlayer.issuer -}}
|
||
{{- .Values.app.nanabushPlayer.issuer -}}
|
||
{{- else -}}
|
||
{{- printf "https://%s/lms/player" (include "nanabushPlayer.host" .) -}}
|
||
{{- end -}}
|
||
{{- end -}}
|
||
|
||
{{- define "nanabushPlayer.serviceName" -}}
|
||
{{- .Values.app.nanabushPlayer.service.name | default (include "hrbox.component" (dict "ctx" . "name" "nanabush-player")) -}}
|
||
{{- end -}}
|
||
|
||
{{/*
|
||
Хост обратного канала Player -> HRBox. Только внутрикластерное имя: по нему
|
||
Player забирает пакеты курсов и отправляет отчёты, и оно же попадает в
|
||
allowlist самого Player'а.
|
||
*/}}
|
||
{{- define "nanabushPlayer.backchannelHost" -}}
|
||
{{- .Values.app.nanabushPlayer.deployment.backchannel.host | default (include "hrbox.component" (dict "ctx" . "name" "web")) -}}
|
||
{{- end -}}
|
||
|
||
{{- define "nanabushPlayer.internalOrigin" -}}
|
||
{{- printf "http://%s" (include "nanabushPlayer.backchannelHost" .) -}}
|
||
{{- end -}}
|
||
|
||
{{/*
|
||
Версия Player'а берётся из тега образа, а не из отдельной настройки: тикет
|
||
не должен объявлять версию, отличную от той, что реально запущена в кластере.
|
||
*/}}
|
||
{{- define "nanabushPlayer.version" -}}
|
||
{{- $tag := include "hrbox.imageTag" .Values.image.nanabushPlayer -}}
|
||
{{- if not $tag -}}
|
||
{{- fail "image.nanabushPlayer должен содержать явный тег версии, например nanabush-player:1.0.11" -}}
|
||
{{- end -}}
|
||
{{- $tag -}}
|
||
{{- end -}}
|
||
|
||
{{- define "nanabushPlayer.secretName" -}}
|
||
{{- required "app.nanabushPlayer.deployment.existingSecret.name обязателен, когда Player включён" .Values.app.nanabushPlayer.deployment.existingSecret.name -}}
|
||
{{- end -}}
|
||
|
||
{{/* URL Redis, который чарт собирает из штатных настроек app.redis. */}}
|
||
{{- define "nanabushPlayer.redisUrl" -}}
|
||
{{- printf "redis://%s:%s/%d" (include "hrbox.redisHost" .) (.Values.app.redis.port | toString) (.Values.app.nanabushPlayer.deployment.redis.database | int) -}}
|
||
{{- end -}}
|
||
|
||
{{/*
|
||
Префикс ключей Redis. Namespace в префиксе разводит несколько релизов HRBox,
|
||
живущих на одном Dragonfly.
|
||
*/}}
|
||
{{- define "nanabushPlayer.redisKeyPrefix" -}}
|
||
{{- printf "hrbox:%s:%s" .Release.Namespace .Values.app.nanabushPlayer.deployment.redis.keyPrefixSuffix -}}
|
||
{{- end -}}
|