chart 3.0

This commit is contained in:
2026-09-05 19:07:31 +06:00
parent efc506e5de
commit 67786a0160
31 changed files with 348 additions and 773 deletions
-12
View File
@@ -1,16 +1,4 @@
{{- if not .Values.secrets.existingSecret }}
{{/*
Единый Secret с чувствительными настройками HRBox.
В чарте 2.x пароли и ключи подставлялись прямо в env-блоки Deployment,
поэтому любой, кто мог сделать `kubectl get deploy -o yaml`, видел пароль
базы и ключ шифрования. Здесь значения лежат в одном Secret, а контейнеры
читают их через secretKeyRef (см. hrbox.secretEnv в _helpers.tpl).
Если секретами управляет внешний инструмент, задайте secrets.existingSecret —
тогда чарт этот объект не создаёт и только ссылается на указанный. Набор
ключей должен совпадать с перечисленным ниже.
*/}}
---
apiVersion: v1
kind: Secret
@@ -1,21 +1,5 @@
{{- $cfg := .Values.app.nanabushPlayer.deployment }}
{{- if and $cfg.enabled $cfg.existingSecret.create }}
{{/*
Ключи Nanabush Player.
ticketHs256 читают обе стороны: HRBox подписывает им launch-тикет
(NANABUSH_PLAYER_HS256_SECRET в поде web), плеер этим же ключом тикет
проверяет (PLAYER_HS256_SECRET). Поэтому ротация — одно значение на обе
стороны, а не два независимых.
sessionHs256 принадлежит только плееру: им подписывается сессия учащегося
внутри плеера, HRBox её не читает.
При existingSecret.create: false этот объект не создаётся — оба потребителя
всё так же ссылаются на existingSecret.name, но Secret должен быть заведён
вне чарта. При смене владельца уже существующего Secret берите новое имя,
чтобы Helm не удалил внешний объект во время перехода.
*/}}
---
apiVersion: v1
kind: Secret
-19
View File
@@ -1,19 +1,3 @@
{{/*
============================================================================
Проверка values.yaml
============================================================================
Этот файл не создаёт ни одного объекта. Он выполняется первым и падает с
понятным сообщением, если конфигурация неполная или противоречивая, — до
того, как в кластере появятся поды, которые всё равно не заработают.
Проверяется три вещи:
1) ключи, переехавшие в версии 3.0 (подсказка вместо тихого игнора);
2) обязательные значения, без которых приложение не поднимется;
3) инварианты Nanabush Player.
*/}}
{{/* --- 1. Ключи из чарта 2.x ---------------------------------------------- */}}
{{- if .Values.app.image }}
{{- fail "app.image переехал в image.hrbox (см. CHANGELOG, миграция 2.x -> 3.0)" }}
{{- end }}
@@ -42,7 +26,6 @@
{{- fail "nats.image переехал в image.nats" }}
{{- end }}
{{/* --- 2. Обязательные значения ------------------------------------------- */}}
{{- if not .Values.ingress.host }}
{{- fail "Заполните ingress.host — домен, по которому открывается HRBox" }}
{{- end }}
@@ -81,7 +64,6 @@
{{- end }}
{{- end }}
{{/* --- 3. Внешние зависимости ---------------------------------------------- */}}
{{- if and (not .Values.dragonfly.enabled) (not .Values.app.redis.host) }}
{{- fail "dragonfly.enabled: false требует app.redis.host — иначе приложение обратится к сервису, которого нет в релизе" }}
{{- end }}
@@ -95,7 +77,6 @@
{{- end }}
{{- end }}
{{/* --- 4. Nanabush Player -------------------------------------------------- */}}
{{- $player := .Values.app.nanabushPlayer }}
{{- if and $player.enabled (not $player.deployment.enabled) }}
{{- fail "app.nanabushPlayer.enabled требует deployment.enabled: HRBox нельзя переключить на плеер, которого нет в кластере" }}
-9
View File
@@ -1,12 +1,4 @@
{{- if .Values.nats.enabled }}
{{/*
Конфигурация NATS JetStream.
Маршруты кластера строятся из служебных DNS-имён StatefulSet, поэтому домен
кластера берётся из cluster.domain — в чарте 2.x он был захардкожен здесь и
одновременно настраивался в values, из-за чего нестандартный домен ломал
сборку кластера.
*/}}
{{- $name := include "hrbox.component" (dict "ctx" . "name" "nats") -}}
---
apiVersion: v1
@@ -17,7 +9,6 @@ metadata:
{{- include "hrbox.labels" (dict "ctx" . "name" "nats") | nindent 4 }}
data:
nats.conf: |
# PID-файл, общий с перезагрузчиком конфигурации.
pid_file: "/var/run/nats/nats.pid"
###############
-8
View File
@@ -1,11 +1,3 @@
{{/*
Привязка мобильных приложений к домену инсталляции.
Android читает /.well-known/assetlinks.json, iOS — /.well-known/apple-app-site-association.
Без них ссылки из писем и уведомлений открываются в браузере, а не в приложении.
По умолчанию здесь идентификаторы штатных приложений HRBox; если у вас
собственная сборка, переопределите app.mobileApps в values.yaml.
*/}}
---
apiVersion: v1
kind: ConfigMap
-14
View File
@@ -1,9 +1,3 @@
{{/*
Конфигурация nginx в поде web. Отличия от чарта 2.x — набор location,
перенесённый из продового окружения: health-check для проб, потоковая
загрузка оргструктуры из 1С, длинные таймауты для AI-запросов, отдача
assetlinks мобильных приложений и корректные заголовки для service worker.
*/}}
---
apiVersion: v1
kind: ConfigMap
@@ -103,13 +97,11 @@ data:
deny all;
}
# Liveness: отвечает сам nginx, не дожидаясь PHP-FPM.
location = /healthz {
access_log off;
return 200 "ok\n";
}
# Readiness: короткая проверка, что PHP-FPM отвечает.
location = /health-check {
fastcgi_pass 127.0.0.1:9000;
fastcgi_connect_timeout 1s;
@@ -121,9 +113,6 @@ data:
fastcgi_param PATH_INFO /health-check;
}
# Загрузка оргструктуры из 1С. PHP читает тело запроса потоком и
# проксирует в GoWorker без полной буферизации, поэтому nginx
# тоже не должен буферизовать тело.
location = /api/v1/integration/commit {
client_max_body_size 500m;
fastcgi_request_buffering off;
@@ -138,7 +127,6 @@ data:
fastcgi_connect_timeout 60s;
}
# Привязка мобильных приложений к домену
location /.well-known/assetlinks.json {
default_type "application/json";
alias /var/www/assetlinks/assetlinks.json;
@@ -157,7 +145,6 @@ data:
access_log off;
}
# AI-запросы отвечают дольше обычных, им нужен свой таймаут.
location ^~ /ai/ {
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
@@ -184,7 +171,6 @@ data:
add_header X-Content-Type-Options "nosniff";
add_header Permissions-Policy "browsing-topics=()" always;
# Всё, что не является файлом, уходит в index.php
try_files $uri $uri/ /index.php?$args;
location ~* \.(js|css|png|jpg|gif|ico)$ {
-4
View File
@@ -1,8 +1,4 @@
{{- if .Values.app.tracing.enabled }}
{{/*
Конфигурация sidecar-коллектора OpenTelemetry в поде web.
Создаётся только при app.tracing.enabled.
*/}}
---
apiVersion: v1
kind: ConfigMap
-4
View File
@@ -1,7 +1,3 @@
{{/*
Скрипт init-контейнера джобы миграций: ждёт, пока PostgreSQL начнёт принимать
подключения. Без этого миграции падают, если база стартует медленнее подов.
*/}}
---
apiVersion: v1
kind: ConfigMap
-7
View File
@@ -1,12 +1,5 @@
{{- if .Values.dragonfly.enabled }}
{{- $name := include "hrbox.component" (dict "ctx" . "name" "dragonfly") -}}
{{/*
Redis-совместимый кеш: сессии, кеш приложения и очереди Nanabush Player.
Одна реплика и стратегия Recreate — намеренно: данные хранятся в памяти,
второй экземпляр не даёт ни отказоустойчивости, ни консистентности.
Селектор оставлен как в чарте 2.x.
*/}}
---
apiVersion: apps/v1
kind: Deployment
-12
View File
@@ -1,9 +1,5 @@
{{- if .Values.nats.enabled }}
{{- $name := include "hrbox.component" (dict "ctx" . "name" "nats") -}}
{{/*
Брокер сообщений. Селектор StatefulSet намеренно оставлен таким же, как в
чарте 2.x: он неизменяем, и его правка потребовала бы пересоздания объекта.
*/}}
---
apiVersion: apps/v1
kind: StatefulSet
@@ -30,8 +26,6 @@ spec:
name: {{ printf "%s-config" $name }}
- name: pid
emptyDir: {}
# Общее пространство процессов нужно перезагрузчику конфигурации:
# он посылает сигнал процессу nats-server из соседнего контейнера.
shareProcessNamespace: true
terminationGracePeriodSeconds: {{ .Values.nats.terminationGracePeriodSeconds }}
{{- include "hrbox.imagePullSecrets" . | nindent 6 }}
@@ -63,9 +57,6 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.namespace
# Адрес, который нода объявляет остальным участникам кластера.
# Сегмент svc обязателен: без него имя не резолвится и ноды
# не находят друг друга.
- name: CLUSTER_ADVERTISE
value: $(POD_NAME).{{ $name }}.$(POD_NAMESPACE).svc.{{ .Values.cluster.domain }}
{{- include "hrbox.resources" (dict "ctx" . "component" "nats") | indent 10 }}
@@ -91,8 +82,6 @@ spec:
initialDelaySeconds: 10
timeoutSeconds: 5
lifecycle:
# Перевод ноды в lame duck: она перестаёт принимать новые
# подключения и даёт клиентам время переподключиться к соседям.
preStop:
exec:
command:
@@ -140,7 +129,6 @@ metadata:
labels:
{{- include "hrbox.labels" (dict "ctx" . "name" "nats") | nindent 4 }}
spec:
# Headless: клиентам нужны адреса конкретных нод, а не общий VIP.
clusterIP: None
selector:
app.kubernetes.io/name: nats
-6
View File
@@ -1,10 +1,4 @@
{{- $replicas := .Values.app.replicas.web | int }}
{{/*
Бюджет прерываний для web.
Имеет смысл только начиная с двух реплик: при одной minAvailable округляется
до 1 и намертво блокирует drain ноды, ничего при этом не защищая.
*/}}
{{- if gt $replicas 1 }}
---
apiVersion: policy/v1
-12
View File
@@ -1,12 +1,4 @@
{{- $name := include "hrbox.component" (dict "ctx" . "name" "web") -}}
{{/*
Веб-под: PHP-FPM, nginx перед ним и экспортёр метрик FPM.
При app.tracing.enabled рядом поднимается коллектор OpenTelemetry.
Аннотации checksum перезапускают поды, когда меняется конфигурация nginx или
секрет приложения: без них правка ConfigMap остаётся незамеченной до
следующего рестарта.
*/}}
---
apiVersion: apps/v1
kind: Deployment
@@ -56,8 +48,6 @@ spec:
{{- end }}
{{- include "hrbox.resources" (dict "ctx" . "component" "app") | indent 10 }}
lifecycle:
# Пауза даёт ingress-контроллеру убрать под из балансировки,
# прежде чем FPM начнёт корректное завершение.
preStop:
exec:
command:
@@ -92,8 +82,6 @@ spec:
- sh
- '-c'
- sleep 15 && /usr/sbin/nginx -s quit
# /healthz отвечает сам nginx, /health-check проверяет,
# что за ним жив PHP-FPM.
livenessProbe:
httpGet:
path: /healthz
-4
View File
@@ -1,8 +1,4 @@
{{- $name := include "hrbox.component" (dict "ctx" . "name" "chatbox") -}}
{{/*
Chatbox — вебсокет-сервер чатов и real-time уведомлений.
До версии 2.0 назывался websocket; имена объектов не менялись с тех пор.
*/}}
---
apiVersion: apps/v1
kind: Deployment
-8
View File
@@ -1,12 +1,4 @@
{{- $name := include "hrbox.component" (dict "ctx" . "name" "worker") -}}
{{/*
Обработчик фоновых задач: конвертация файлов, рассылка почты и уведомлений,
генерация отчётов, обслуживание Nanabush Player.
Стратегия Recreate: воркеры разбирают задачи из общей очереди, и пересечение
старых и новых подов во время выката привело бы к двойной обработке.
Длинный terminationGracePeriodSeconds даёт закончить уже взятую задачу.
*/}}
---
apiVersion: apps/v1
kind: Deployment
-6
View File
@@ -1,10 +1,4 @@
{{- $name := include "hrbox.component" (dict "ctx" . "name" "conductor") -}}
{{/*
Планировщик задач по расписанию.
Строго одна реплика: два планировщика запустили бы каждую задачу дважды.
По той же причине стратегия Recreate, а не RollingUpdate.
*/}}
---
apiVersion: apps/v1
kind: Deployment
@@ -1,14 +1,5 @@
{{- if .Values.app.videoConverter.enabled }}
{{- $name := include "hrbox.component" (dict "ctx" . "name" "file-processor-video") -}}
{{/*
Конвертация видео.
Отдельный деплоймент, потому что профиль ресурсов у него другой на порядок:
несколько ядер, гигабайты памяти и десятки гигабайт временного диска на под.
Смешивать это с обычной обработкой файлов нельзя — либо ресурсы простаивают,
либо конвертация видео вытесняет всё остальное. Через nodeSelector и
tolerations пул выносится на выделенные ноды.
*/}}
---
apiVersion: apps/v1
kind: Deployment
-6
View File
@@ -1,10 +1,4 @@
{{- $name := include "hrbox.component" (dict "ctx" . "name" "file-processor") -}}
{{/*
Конвертация документов и обработка изображений.
Конвертация видео здесь всегда выключена: она требует принципиально другого
профиля ресурсов и живёт в отдельном деплойменте 09-file-processor-video.
*/}}
---
apiVersion: apps/v1
kind: Deployment
-3
View File
@@ -1,7 +1,4 @@
{{- $name := include "hrbox.component" (dict "ctx" . "name" "geonames") -}}
{{/*
Справочник городов, стран и часовых поясов.
*/}}
---
apiVersion: apps/v1
kind: Deployment
-7
View File
@@ -1,11 +1,4 @@
{{- $name := include "hrbox.component" (dict "ctx" . "name" "goworker") -}}
{{/*
Интеграции с мессенджерами, push-уведомления, синхронизация оргструктуры
с 1С и восстановление проекций Nanabush Player.
Метрики Prometheus отдаются на том же порту 8686 по пути /metrics, поэтому
аннотации сбора висят на Service, а не на поде.
*/}}
---
apiVersion: apps/v1
kind: Deployment
-8
View File
@@ -1,12 +1,4 @@
{{- $name := include "hrbox.component" (dict "ctx" . "name" "kedoca") -}}
{{/*
Сервис электронной подписи: КЭДО, МЧД, метки времени.
Умеет ГОСТ (через КриптоПро) и обычный OpenSSL — выбор в app.kedoca.engine.
app.kedoca.secretName подключает Secret с сертификатами удостоверяющего
центра. Без него сервис создаёт собственный корневой сертификат при первом
запуске — это годится для теста, но не для юридически значимого документооборота.
*/}}
---
apiVersion: apps/v1
kind: Deployment
-29
View File
@@ -2,22 +2,6 @@
{{- if $cfg.enabled }}
{{- $name := include "nanabushPlayer.serviceName" . -}}
{{- $secretName := include "nanabushPlayer.secretName" . -}}
{{/*
Nanabush Player — проигрыватель учебных материалов: SCORM 1.2 и 2004, cmi5,
xAPI, нативные курсы, тесты и эссе.
Как это работает:
* HRBox выпускает launch-тикет, подписанный общим ключом ticketHs256,
и отправляет браузер на https://<домен>{{ include "nanabushPlayer.basePath" . }}/start;
* плеер проверяет подпись, audience и issuer, заводит свою сессию;
* за пакетом курса и для отправки отчётов плеер ходит обратно в HRBox по
внутрикластерному адресу — только он и разрешён в allowlist;
* учебные события копятся в Redis Streams и досылаются форвардером,
поэтому короткая недоступность HRBox не теряет прогресс.
Ограничения on-premise описаны в values.yaml рядом с app.nanabushPlayer.
Полный контракт — docs/nanabush-player-deployment.md в репозитории HRBox.
*/}}
---
apiVersion: apps/v1
kind: Deployment
@@ -49,9 +33,6 @@ spec:
prometheus.io/path: "/metrics"
{{- end }}
spec:
# Плееру не нужен доступ к API Kubernetes, а исполняет он содержимое,
# загруженное пользователями, — поэтому токен не монтируется, процесс
# не root, корневая файловая система только на чтение.
automountServiceAccountToken: false
terminationGracePeriodSeconds: {{ $cfg.terminationGracePeriodSeconds }}
{{- include "hrbox.imagePullSecrets" . | nindent 6 }}
@@ -89,8 +70,6 @@ spec:
{{- else }}
value: "off"
{{- end }}
# Путь монтирования не входит в audience: audience — это origin
# браузера, иначе сломались бы проверки на стороне клиента.
- name: PLAYER_BASE_PATH
value: {{ include "nanabushPlayer.basePath" . | quote }}
- name: PLAYER_AUDIENCE
@@ -103,16 +82,12 @@ spec:
name: {{ $secretName | quote }}
key: {{ required "Нужно имя ключа ticketHs256 в секрете Nanabush Player" $cfg.existingSecret.keys.ticketHs256 | quote }}
{{- with $cfg.existingSecret.keys.ticketKeys }}
# Кольцо ключей: подпись проверяется ключом, выбранным по kid из
# тикета, поэтому во время ротации работают обе версии HRBox.
- name: PLAYER_TICKET_KEYS
valueFrom:
secretKeyRef:
name: {{ $secretName | quote }}
key: {{ . | quote }}
{{- with $cfg.ticket.keylessAcceptedUntil }}
# Только на первую раскатку: принимать тикеты без kid от версии
# HRBox, которая ещё не знает про кольцо ключей.
- name: PLAYER_TICKET_KEYLESS_UNTIL
value: {{ . | quote }}
{{- end }}
@@ -139,8 +114,6 @@ spec:
{{- end }}
- name: PLAYER_REDIS_KEY_PREFIX
value: {{ include "nanabushPlayer.redisKeyPrefix" . | quote }}
# Обратный канал: единственный разрешённый адрес — внутрикластерный
# HRBox. Так пакет курса не сможет заставить плеер сходить наружу.
- name: PLAYER_PACKAGE_FETCH_SCHEMES
value: {{ $cfg.backchannel.schemes | quote }}
- name: PLAYER_PACKAGE_FETCH_ALLOWLIST
@@ -222,8 +195,6 @@ spec:
type: ClusterIP
selector:
service: {{ $name }}
# Порт метрик наружу намеренно не публикуется: содержимое курсов приходит
# с того же origin и не должно читать эксплуатационные метрики.
ports:
- name: http
port: {{ .Values.app.nanabushPlayer.service.port }}
-18
View File
@@ -1,18 +1,5 @@
{{- if .Values.ingress.enabled }}
{{- $player := .Values.app.nanabushPlayer -}}
{{/*
Единая точка входа.
Все три маршрута живут на одном домене, потому что в on-premise выделенных
поддоменов под сервисы нет:
{{ include "nanabushPlayer.basePath" . }}/ -> плеер учебных материалов
/chatbox/ -> вебсокеты чата
/ -> само приложение
Длинные таймауты нужны вебсокетам и плееру: и то и другое держит соединение
открытым, пока пользователь работает.
*/}}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
@@ -21,12 +8,7 @@ metadata:
labels:
{{- include "hrbox.labels" (dict "ctx" . "name" "web") | nindent 4 }}
annotations:
# Аннотация класса устарела в пользу spec.ingressClassName ниже, но
# оставлена: контроллеры старше ingress-nginx 1.0 понимают только её.
# Когда заданы обе, современный контроллер использует ingressClassName.
kubernetes.io/ingress.class: {{ .Values.ingress.className | quote }}
# Аннотация NGINX Inc.; ingress-nginx её игнорирует, вебсокеты у него
# работают за счёт proxy-read-timeout выше.
nginx.org/websocket-services: {{ include "hrbox.component" (dict "ctx" . "name" "chatbox") | quote }}
nginx.ingress.kubernetes.io/proxy-body-size: {{ .Values.ingress.maxBodySize | quote }}
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
-9
View File
@@ -1,12 +1,3 @@
{{/*
Миграции базы данных.
Хук post-install/post-upgrade с весом 10: выполняется после того, как Helm
создал ConfigMap и Secret, но до джобы обновления кластера (вес 20).
Имя джобы содержит номер ревизии релиза, поэтому в истории видно, какой
выкат её запускал, а повторный upgrade не спотыкается об уже существующий
объект.
*/}}
---
apiVersion: batch/v1
kind: Job
@@ -1,9 +1,3 @@
{{/*
Обновление данных кластера после миграций: пересчёт справочников,
перерегистрация фоновых задач, обновление настроек арендаторов.
Вес 20 — строго после джобы миграций (вес 10).
*/}}
---
apiVersion: batch/v1
kind: Job
+16 -47
View File
@@ -1,18 +1,5 @@
{{/*
============================================================================
Переменные окружения 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
@@ -45,7 +32,7 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
{{- 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 }}
@@ -60,7 +47,7 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
value: ""
{{- end }}
# --- PostgreSQL -----------------------------------------------------------
# PostgreSQL
- name: POSTGRES_VHOST
value: {{ .Values.app.postgres.host | quote }}
- name: POSTGRES_PORT
@@ -73,7 +60,7 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
value: {{ .Values.app.postgres.citus | quote }}
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "POSTGRES_PASSWORD" "key" "postgres-password") | nindent 0 }}
# --- Redis / Dragonfly ----------------------------------------------------
# Redis / Dragonfly
- name: REDIS_HOST
value: {{ include "hrbox.redisHost" . | quote }}
- name: REDIS_PORT
@@ -81,13 +68,11 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
- name: REDIS_CONNECTION
value: {{ printf "tcp://%s:%s" (include "hrbox.redisHost" .) (.Values.app.redis.port | toString) | quote }}
# --- NATS -----------------------------------------------------------------
# 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 }}
@@ -95,7 +80,7 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
value: "1"
{{- end }}
# --- S3 -------------------------------------------------------------------
# S3
- name: S3_ENDPOINT
value: {{ .Values.app.s3.endpoint | quote }}
- name: S3_BUCKET
@@ -113,7 +98,7 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
{{- 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
@@ -136,7 +121,7 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
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
@@ -160,27 +145,27 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
- name: DOCCONV_MAX_PARALLEL_TASKS
value: {{ .Values.app.fileProcessor.docconvMaxParallelTasks | quote }}
# --- HRBox Hub ------------------------------------------------------------
# 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 ------------------------------------------------------
# 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) ------------------------------------------------
# Видеозвонки (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 -------------------------------------------------------------------
# AI
- name: AI_DOCS_INDEX_ENABLED
value: {{ .Values.app.ai.docsIndexEnabled | quote }}
- name: AI_SEMANTIC_INDEX_ENABLED
@@ -191,7 +176,7 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
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
@@ -211,7 +196,7 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
- name: GLAGOL_API_URL
value: {{ .Values.app.integrations.glagol.apiUrl | quote }}
# --- Sentry ---------------------------------------------------------------
# Sentry
- name: SENTRY_DSN
value: {{ .Values.app.sentry.dsn | quote }}
- name: SENTRY_DSN_LAUNCHPAD
@@ -223,7 +208,7 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
- name: SENTRY_RELEASE
value: {{ .Values.image.hrbox | quote }}
# --- Метаданные пода ------------------------------------------------------
# Метаданные пода
- name: POD_NAME
valueFrom:
fieldRef:
@@ -242,13 +227,6 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
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
@@ -291,10 +269,6 @@ audience тикета — это origin браузера без пути, а п
{{- end }}
{{- end -}}
{{/*
Ключ подписи launch-тикета. Живёт только в PHP-контейнерах, которые выпускают
тикеты: nginx и вспомогательным контейнерам он не нужен.
*/}}
{{- define "envs_nanabush_player_signing" -}}
{{- $cfg := .Values.app.nanabushPlayer.deployment }}
{{- if $cfg.enabled }}
@@ -304,9 +278,6 @@ audience тикета — это origin браузера без пути, а п
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:
@@ -316,7 +287,6 @@ audience тикета — это origin браузера без пути, а п
{{- end }}
{{- end -}}
{{/* Криптографические настройки сервиса электронной подписи. */}}
{{- define "envs_kedoca" }}
- name: ROOT_CA_PASS
value: {{ .Values.app.kedoca.rootCaPass | quote }}
@@ -328,7 +298,6 @@ audience тикета — это origin браузера без пути, а п
value: {{ .Values.app.kedoca.pkeyopt | quote }}
{{- end }}
{{/* OpenTelemetry — только когда app.tracing.enabled. */}}
{{- define "envs_tracing" }}
- name: OTEL_PHP_AUTOLOAD_ENABLED
value: "true"
-101
View File
@@ -1,49 +1,19 @@
{{/*
============================================================================
Общие хелперы чарта 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 }}
@@ -54,11 +24,6 @@ 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:
@@ -68,11 +33,6 @@ imagePullSecrets:
{{- end }}
{{- end -}}
{{/*
Тег из ссылки на образ: "registry/repo:1.2.3" -> "1.2.3".
Двоеточие ищется только в последнем сегменте пути, чтобы не спутать тег
с портом реестра ("registry:5000/repo").
*/}}
{{- define "hrbox.imageTag" -}}
{{- $lastSegment := splitList "/" . | last -}}
{{- if contains ":" $lastSegment -}}
@@ -80,27 +40,6 @@ imagePullSecrets:
{{- 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 -}}
@@ -129,11 +68,6 @@ secrets.existingSecret позволяет подставить Secret, созд
{{- end -}}
{{- end -}}
{{/*
Одна переменная окружения из секрета приложения.
Usage: {{ include "hrbox.secretEnv" (dict "ctx" . "env" "POSTGRES_PASSWORD" "key" "postgres-password") }}
*/}}
{{- define "hrbox.secretEnv" -}}
- name: {{ .env }}
valueFrom:
@@ -142,23 +76,6 @@ Usage: {{ include "hrbox.secretEnv" (dict "ctx" . "env" "POSTGRES_PASSWORD" "key
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 -}}
@@ -167,10 +84,6 @@ On-premise-топология Player'а отличается от облачно
{{- printf "https://%s" (include "nanabushPlayer.host" .) -}}
{{- end -}}
{{/*
Путь монтирования Player'а на основном домене. Пустое значение и "/" запрещены:
это отдало бы Player'у корень, занятый самим HRBox.
*/}}
{{- define "nanabushPlayer.basePath" -}}
{{- $path := .Values.app.nanabushPlayer.basePath | default "/nanabush-player" -}}
{{- $path | trimSuffix "/" -}}
@@ -188,11 +101,6 @@ On-premise-топология Player'а отличается от облачно
{{- .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 -}}
@@ -201,10 +109,6 @@ allowlist самого Player'а.
{{- printf "http://%s" (include "nanabushPlayer.backchannelHost" .) -}}
{{- end -}}
{{/*
Версия Player'а берётся из тега образа, а не из отдельной настройки: тикет
не должен объявлять версию, отличную от той, что реально запущена в кластере.
*/}}
{{- define "nanabushPlayer.version" -}}
{{- $tag := include "hrbox.imageTag" .Values.image.nanabushPlayer -}}
{{- if not $tag -}}
@@ -217,15 +121,10 @@ allowlist самого Player'а.
{{- 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 -}}
-13
View File
@@ -1,16 +1,3 @@
{{/*
============================================================================
resources: для контейнера
============================================================================
В чарте 2.x на каждый компонент был отдельный define из восьми одинаковых
строк. Здесь один хелпер, который читает resources.<компонент> из values.yaml.
Незаданные поля просто не рендерятся, поэтому компоненту можно указать,
например, только requests.
Usage:
{{- include "hrbox.resources" (dict "ctx" . "component" "app") | indent 10 }}
*/}}
{{- define "hrbox.resources" -}}
{{- $r := index .ctx.Values.resources .component -}}
{{- if $r }}