chart 3.0
This commit is contained in:
@@ -3,10 +3,7 @@ name: hrbox
|
|||||||
description: HRBox — HR-платформа для on-premise установки
|
description: HRBox — HR-платформа для on-premise установки
|
||||||
type: application
|
type: application
|
||||||
|
|
||||||
# Версия чарта. Увеличивается при каждом изменении чарта.
|
|
||||||
version: 3.0.0
|
version: 3.0.0
|
||||||
|
|
||||||
# Версия приложения. Совпадает с линейкой образов HRBox.
|
|
||||||
appVersion: "3.1.0"
|
appVersion: "3.1.0"
|
||||||
|
|
||||||
keywords:
|
keywords:
|
||||||
@@ -19,7 +16,6 @@ keywords:
|
|||||||
home: https://hrbox.io
|
home: https://hrbox.io
|
||||||
|
|
||||||
annotations:
|
annotations:
|
||||||
# Компоненты, которые разворачивает чарт
|
|
||||||
hrbox.io/components: >-
|
hrbox.io/components: >-
|
||||||
web, worker, conductor, chatbox, goworker, kedoca, geonames,
|
web, worker, conductor, chatbox, goworker, kedoca, geonames,
|
||||||
file-processor, nanabush-player, dragonfly, nats
|
file-processor, nanabush-player, dragonfly, nats
|
||||||
|
|||||||
@@ -1,16 +1,4 @@
|
|||||||
{{- if not .Values.secrets.existingSecret }}
|
{{- 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
|
apiVersion: v1
|
||||||
kind: Secret
|
kind: Secret
|
||||||
|
|||||||
@@ -1,21 +1,5 @@
|
|||||||
{{- $cfg := .Values.app.nanabushPlayer.deployment }}
|
{{- $cfg := .Values.app.nanabushPlayer.deployment }}
|
||||||
{{- if and $cfg.enabled $cfg.existingSecret.create }}
|
{{- 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
|
apiVersion: v1
|
||||||
kind: Secret
|
kind: Secret
|
||||||
|
|||||||
@@ -1,19 +1,3 @@
|
|||||||
{{/*
|
|
||||||
============================================================================
|
|
||||||
Проверка values.yaml
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
Этот файл не создаёт ни одного объекта. Он выполняется первым и падает с
|
|
||||||
понятным сообщением, если конфигурация неполная или противоречивая, — до
|
|
||||||
того, как в кластере появятся поды, которые всё равно не заработают.
|
|
||||||
|
|
||||||
Проверяется три вещи:
|
|
||||||
1) ключи, переехавшие в версии 3.0 (подсказка вместо тихого игнора);
|
|
||||||
2) обязательные значения, без которых приложение не поднимется;
|
|
||||||
3) инварианты Nanabush Player.
|
|
||||||
*/}}
|
|
||||||
|
|
||||||
{{/* --- 1. Ключи из чарта 2.x ---------------------------------------------- */}}
|
|
||||||
{{- if .Values.app.image }}
|
{{- if .Values.app.image }}
|
||||||
{{- fail "app.image переехал в image.hrbox (см. CHANGELOG, миграция 2.x -> 3.0)" }}
|
{{- fail "app.image переехал в image.hrbox (см. CHANGELOG, миграция 2.x -> 3.0)" }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
@@ -42,7 +26,6 @@
|
|||||||
{{- fail "nats.image переехал в image.nats" }}
|
{{- fail "nats.image переехал в image.nats" }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{/* --- 2. Обязательные значения ------------------------------------------- */}}
|
|
||||||
{{- if not .Values.ingress.host }}
|
{{- if not .Values.ingress.host }}
|
||||||
{{- fail "Заполните ingress.host — домен, по которому открывается HRBox" }}
|
{{- fail "Заполните ingress.host — домен, по которому открывается HRBox" }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
@@ -81,7 +64,6 @@
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{/* --- 3. Внешние зависимости ---------------------------------------------- */}}
|
|
||||||
{{- if and (not .Values.dragonfly.enabled) (not .Values.app.redis.host) }}
|
{{- if and (not .Values.dragonfly.enabled) (not .Values.app.redis.host) }}
|
||||||
{{- fail "dragonfly.enabled: false требует app.redis.host — иначе приложение обратится к сервису, которого нет в релизе" }}
|
{{- fail "dragonfly.enabled: false требует app.redis.host — иначе приложение обратится к сервису, которого нет в релизе" }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
@@ -95,7 +77,6 @@
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{/* --- 4. Nanabush Player -------------------------------------------------- */}}
|
|
||||||
{{- $player := .Values.app.nanabushPlayer }}
|
{{- $player := .Values.app.nanabushPlayer }}
|
||||||
{{- if and $player.enabled (not $player.deployment.enabled) }}
|
{{- if and $player.enabled (not $player.deployment.enabled) }}
|
||||||
{{- fail "app.nanabushPlayer.enabled требует deployment.enabled: HRBox нельзя переключить на плеер, которого нет в кластере" }}
|
{{- fail "app.nanabushPlayer.enabled требует deployment.enabled: HRBox нельзя переключить на плеер, которого нет в кластере" }}
|
||||||
|
|||||||
@@ -1,12 +1,4 @@
|
|||||||
{{- if .Values.nats.enabled }}
|
{{- if .Values.nats.enabled }}
|
||||||
{{/*
|
|
||||||
Конфигурация NATS JetStream.
|
|
||||||
|
|
||||||
Маршруты кластера строятся из служебных DNS-имён StatefulSet, поэтому домен
|
|
||||||
кластера берётся из cluster.domain — в чарте 2.x он был захардкожен здесь и
|
|
||||||
одновременно настраивался в values, из-за чего нестандартный домен ломал
|
|
||||||
сборку кластера.
|
|
||||||
*/}}
|
|
||||||
{{- $name := include "hrbox.component" (dict "ctx" . "name" "nats") -}}
|
{{- $name := include "hrbox.component" (dict "ctx" . "name" "nats") -}}
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
@@ -17,7 +9,6 @@ metadata:
|
|||||||
{{- include "hrbox.labels" (dict "ctx" . "name" "nats") | nindent 4 }}
|
{{- include "hrbox.labels" (dict "ctx" . "name" "nats") | nindent 4 }}
|
||||||
data:
|
data:
|
||||||
nats.conf: |
|
nats.conf: |
|
||||||
# PID-файл, общий с перезагрузчиком конфигурации.
|
|
||||||
pid_file: "/var/run/nats/nats.pid"
|
pid_file: "/var/run/nats/nats.pid"
|
||||||
|
|
||||||
###############
|
###############
|
||||||
|
|||||||
@@ -1,11 +1,3 @@
|
|||||||
{{/*
|
|
||||||
Привязка мобильных приложений к домену инсталляции.
|
|
||||||
|
|
||||||
Android читает /.well-known/assetlinks.json, iOS — /.well-known/apple-app-site-association.
|
|
||||||
Без них ссылки из писем и уведомлений открываются в браузере, а не в приложении.
|
|
||||||
По умолчанию здесь идентификаторы штатных приложений HRBox; если у вас
|
|
||||||
собственная сборка, переопределите app.mobileApps в values.yaml.
|
|
||||||
*/}}
|
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
|
|||||||
@@ -1,9 +1,3 @@
|
|||||||
{{/*
|
|
||||||
Конфигурация nginx в поде web. Отличия от чарта 2.x — набор location,
|
|
||||||
перенесённый из продового окружения: health-check для проб, потоковая
|
|
||||||
загрузка оргструктуры из 1С, длинные таймауты для AI-запросов, отдача
|
|
||||||
assetlinks мобильных приложений и корректные заголовки для service worker.
|
|
||||||
*/}}
|
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
@@ -103,13 +97,11 @@ data:
|
|||||||
deny all;
|
deny all;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Liveness: отвечает сам nginx, не дожидаясь PHP-FPM.
|
|
||||||
location = /healthz {
|
location = /healthz {
|
||||||
access_log off;
|
access_log off;
|
||||||
return 200 "ok\n";
|
return 200 "ok\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
# Readiness: короткая проверка, что PHP-FPM отвечает.
|
|
||||||
location = /health-check {
|
location = /health-check {
|
||||||
fastcgi_pass 127.0.0.1:9000;
|
fastcgi_pass 127.0.0.1:9000;
|
||||||
fastcgi_connect_timeout 1s;
|
fastcgi_connect_timeout 1s;
|
||||||
@@ -121,9 +113,6 @@ data:
|
|||||||
fastcgi_param PATH_INFO /health-check;
|
fastcgi_param PATH_INFO /health-check;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Загрузка оргструктуры из 1С. PHP читает тело запроса потоком и
|
|
||||||
# проксирует в GoWorker без полной буферизации, поэтому nginx
|
|
||||||
# тоже не должен буферизовать тело.
|
|
||||||
location = /api/v1/integration/commit {
|
location = /api/v1/integration/commit {
|
||||||
client_max_body_size 500m;
|
client_max_body_size 500m;
|
||||||
fastcgi_request_buffering off;
|
fastcgi_request_buffering off;
|
||||||
@@ -138,7 +127,6 @@ data:
|
|||||||
fastcgi_connect_timeout 60s;
|
fastcgi_connect_timeout 60s;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Привязка мобильных приложений к домену
|
|
||||||
location /.well-known/assetlinks.json {
|
location /.well-known/assetlinks.json {
|
||||||
default_type "application/json";
|
default_type "application/json";
|
||||||
alias /var/www/assetlinks/assetlinks.json;
|
alias /var/www/assetlinks/assetlinks.json;
|
||||||
@@ -157,7 +145,6 @@ data:
|
|||||||
access_log off;
|
access_log off;
|
||||||
}
|
}
|
||||||
|
|
||||||
# AI-запросы отвечают дольше обычных, им нужен свой таймаут.
|
|
||||||
location ^~ /ai/ {
|
location ^~ /ai/ {
|
||||||
|
|
||||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
|
||||||
@@ -184,7 +171,6 @@ data:
|
|||||||
add_header X-Content-Type-Options "nosniff";
|
add_header X-Content-Type-Options "nosniff";
|
||||||
add_header Permissions-Policy "browsing-topics=()" always;
|
add_header Permissions-Policy "browsing-topics=()" always;
|
||||||
|
|
||||||
# Всё, что не является файлом, уходит в index.php
|
|
||||||
try_files $uri $uri/ /index.php?$args;
|
try_files $uri $uri/ /index.php?$args;
|
||||||
|
|
||||||
location ~* \.(js|css|png|jpg|gif|ico)$ {
|
location ~* \.(js|css|png|jpg|gif|ico)$ {
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
{{- if .Values.app.tracing.enabled }}
|
{{- if .Values.app.tracing.enabled }}
|
||||||
{{/*
|
|
||||||
Конфигурация sidecar-коллектора OpenTelemetry в поде web.
|
|
||||||
Создаётся только при app.tracing.enabled.
|
|
||||||
*/}}
|
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
{{/*
|
|
||||||
Скрипт init-контейнера джобы миграций: ждёт, пока PostgreSQL начнёт принимать
|
|
||||||
подключения. Без этого миграции падают, если база стартует медленнее подов.
|
|
||||||
*/}}
|
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
|
|||||||
@@ -1,12 +1,5 @@
|
|||||||
{{- if .Values.dragonfly.enabled }}
|
{{- if .Values.dragonfly.enabled }}
|
||||||
{{- $name := include "hrbox.component" (dict "ctx" . "name" "dragonfly") -}}
|
{{- $name := include "hrbox.component" (dict "ctx" . "name" "dragonfly") -}}
|
||||||
{{/*
|
|
||||||
Redis-совместимый кеш: сессии, кеш приложения и очереди Nanabush Player.
|
|
||||||
|
|
||||||
Одна реплика и стратегия Recreate — намеренно: данные хранятся в памяти,
|
|
||||||
второй экземпляр не даёт ни отказоустойчивости, ни консистентности.
|
|
||||||
Селектор оставлен как в чарте 2.x.
|
|
||||||
*/}}
|
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
{{- if .Values.nats.enabled }}
|
{{- if .Values.nats.enabled }}
|
||||||
{{- $name := include "hrbox.component" (dict "ctx" . "name" "nats") -}}
|
{{- $name := include "hrbox.component" (dict "ctx" . "name" "nats") -}}
|
||||||
{{/*
|
|
||||||
Брокер сообщений. Селектор StatefulSet намеренно оставлен таким же, как в
|
|
||||||
чарте 2.x: он неизменяем, и его правка потребовала бы пересоздания объекта.
|
|
||||||
*/}}
|
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: StatefulSet
|
kind: StatefulSet
|
||||||
@@ -30,8 +26,6 @@ spec:
|
|||||||
name: {{ printf "%s-config" $name }}
|
name: {{ printf "%s-config" $name }}
|
||||||
- name: pid
|
- name: pid
|
||||||
emptyDir: {}
|
emptyDir: {}
|
||||||
# Общее пространство процессов нужно перезагрузчику конфигурации:
|
|
||||||
# он посылает сигнал процессу nats-server из соседнего контейнера.
|
|
||||||
shareProcessNamespace: true
|
shareProcessNamespace: true
|
||||||
terminationGracePeriodSeconds: {{ .Values.nats.terminationGracePeriodSeconds }}
|
terminationGracePeriodSeconds: {{ .Values.nats.terminationGracePeriodSeconds }}
|
||||||
{{- include "hrbox.imagePullSecrets" . | nindent 6 }}
|
{{- include "hrbox.imagePullSecrets" . | nindent 6 }}
|
||||||
@@ -63,9 +57,6 @@ spec:
|
|||||||
valueFrom:
|
valueFrom:
|
||||||
fieldRef:
|
fieldRef:
|
||||||
fieldPath: metadata.namespace
|
fieldPath: metadata.namespace
|
||||||
# Адрес, который нода объявляет остальным участникам кластера.
|
|
||||||
# Сегмент svc обязателен: без него имя не резолвится и ноды
|
|
||||||
# не находят друг друга.
|
|
||||||
- name: CLUSTER_ADVERTISE
|
- name: CLUSTER_ADVERTISE
|
||||||
value: $(POD_NAME).{{ $name }}.$(POD_NAMESPACE).svc.{{ .Values.cluster.domain }}
|
value: $(POD_NAME).{{ $name }}.$(POD_NAMESPACE).svc.{{ .Values.cluster.domain }}
|
||||||
{{- include "hrbox.resources" (dict "ctx" . "component" "nats") | indent 10 }}
|
{{- include "hrbox.resources" (dict "ctx" . "component" "nats") | indent 10 }}
|
||||||
@@ -91,8 +82,6 @@ spec:
|
|||||||
initialDelaySeconds: 10
|
initialDelaySeconds: 10
|
||||||
timeoutSeconds: 5
|
timeoutSeconds: 5
|
||||||
lifecycle:
|
lifecycle:
|
||||||
# Перевод ноды в lame duck: она перестаёт принимать новые
|
|
||||||
# подключения и даёт клиентам время переподключиться к соседям.
|
|
||||||
preStop:
|
preStop:
|
||||||
exec:
|
exec:
|
||||||
command:
|
command:
|
||||||
@@ -140,7 +129,6 @@ metadata:
|
|||||||
labels:
|
labels:
|
||||||
{{- include "hrbox.labels" (dict "ctx" . "name" "nats") | nindent 4 }}
|
{{- include "hrbox.labels" (dict "ctx" . "name" "nats") | nindent 4 }}
|
||||||
spec:
|
spec:
|
||||||
# Headless: клиентам нужны адреса конкретных нод, а не общий VIP.
|
|
||||||
clusterIP: None
|
clusterIP: None
|
||||||
selector:
|
selector:
|
||||||
app.kubernetes.io/name: nats
|
app.kubernetes.io/name: nats
|
||||||
|
|||||||
@@ -1,10 +1,4 @@
|
|||||||
{{- $replicas := .Values.app.replicas.web | int }}
|
{{- $replicas := .Values.app.replicas.web | int }}
|
||||||
{{/*
|
|
||||||
Бюджет прерываний для web.
|
|
||||||
|
|
||||||
Имеет смысл только начиная с двух реплик: при одной minAvailable округляется
|
|
||||||
до 1 и намертво блокирует drain ноды, ничего при этом не защищая.
|
|
||||||
*/}}
|
|
||||||
{{- if gt $replicas 1 }}
|
{{- if gt $replicas 1 }}
|
||||||
---
|
---
|
||||||
apiVersion: policy/v1
|
apiVersion: policy/v1
|
||||||
|
|||||||
@@ -1,12 +1,4 @@
|
|||||||
{{- $name := include "hrbox.component" (dict "ctx" . "name" "web") -}}
|
{{- $name := include "hrbox.component" (dict "ctx" . "name" "web") -}}
|
||||||
{{/*
|
|
||||||
Веб-под: PHP-FPM, nginx перед ним и экспортёр метрик FPM.
|
|
||||||
При app.tracing.enabled рядом поднимается коллектор OpenTelemetry.
|
|
||||||
|
|
||||||
Аннотации checksum перезапускают поды, когда меняется конфигурация nginx или
|
|
||||||
секрет приложения: без них правка ConfigMap остаётся незамеченной до
|
|
||||||
следующего рестарта.
|
|
||||||
*/}}
|
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
@@ -56,8 +48,6 @@ spec:
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
{{- include "hrbox.resources" (dict "ctx" . "component" "app") | indent 10 }}
|
{{- include "hrbox.resources" (dict "ctx" . "component" "app") | indent 10 }}
|
||||||
lifecycle:
|
lifecycle:
|
||||||
# Пауза даёт ingress-контроллеру убрать под из балансировки,
|
|
||||||
# прежде чем FPM начнёт корректное завершение.
|
|
||||||
preStop:
|
preStop:
|
||||||
exec:
|
exec:
|
||||||
command:
|
command:
|
||||||
@@ -92,8 +82,6 @@ spec:
|
|||||||
- sh
|
- sh
|
||||||
- '-c'
|
- '-c'
|
||||||
- sleep 15 && /usr/sbin/nginx -s quit
|
- sleep 15 && /usr/sbin/nginx -s quit
|
||||||
# /healthz отвечает сам nginx, /health-check проверяет,
|
|
||||||
# что за ним жив PHP-FPM.
|
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /healthz
|
path: /healthz
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
{{- $name := include "hrbox.component" (dict "ctx" . "name" "chatbox") -}}
|
{{- $name := include "hrbox.component" (dict "ctx" . "name" "chatbox") -}}
|
||||||
{{/*
|
|
||||||
Chatbox — вебсокет-сервер чатов и real-time уведомлений.
|
|
||||||
До версии 2.0 назывался websocket; имена объектов не менялись с тех пор.
|
|
||||||
*/}}
|
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
|
|||||||
@@ -1,12 +1,4 @@
|
|||||||
{{- $name := include "hrbox.component" (dict "ctx" . "name" "worker") -}}
|
{{- $name := include "hrbox.component" (dict "ctx" . "name" "worker") -}}
|
||||||
{{/*
|
|
||||||
Обработчик фоновых задач: конвертация файлов, рассылка почты и уведомлений,
|
|
||||||
генерация отчётов, обслуживание Nanabush Player.
|
|
||||||
|
|
||||||
Стратегия Recreate: воркеры разбирают задачи из общей очереди, и пересечение
|
|
||||||
старых и новых подов во время выката привело бы к двойной обработке.
|
|
||||||
Длинный terminationGracePeriodSeconds даёт закончить уже взятую задачу.
|
|
||||||
*/}}
|
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
|
|||||||
@@ -1,10 +1,4 @@
|
|||||||
{{- $name := include "hrbox.component" (dict "ctx" . "name" "conductor") -}}
|
{{- $name := include "hrbox.component" (dict "ctx" . "name" "conductor") -}}
|
||||||
{{/*
|
|
||||||
Планировщик задач по расписанию.
|
|
||||||
|
|
||||||
Строго одна реплика: два планировщика запустили бы каждую задачу дважды.
|
|
||||||
По той же причине стратегия Recreate, а не RollingUpdate.
|
|
||||||
*/}}
|
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
|
|||||||
@@ -1,14 +1,5 @@
|
|||||||
{{- if .Values.app.videoConverter.enabled }}
|
{{- if .Values.app.videoConverter.enabled }}
|
||||||
{{- $name := include "hrbox.component" (dict "ctx" . "name" "file-processor-video") -}}
|
{{- $name := include "hrbox.component" (dict "ctx" . "name" "file-processor-video") -}}
|
||||||
{{/*
|
|
||||||
Конвертация видео.
|
|
||||||
|
|
||||||
Отдельный деплоймент, потому что профиль ресурсов у него другой на порядок:
|
|
||||||
несколько ядер, гигабайты памяти и десятки гигабайт временного диска на под.
|
|
||||||
Смешивать это с обычной обработкой файлов нельзя — либо ресурсы простаивают,
|
|
||||||
либо конвертация видео вытесняет всё остальное. Через nodeSelector и
|
|
||||||
tolerations пул выносится на выделенные ноды.
|
|
||||||
*/}}
|
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
|
|||||||
@@ -1,10 +1,4 @@
|
|||||||
{{- $name := include "hrbox.component" (dict "ctx" . "name" "file-processor") -}}
|
{{- $name := include "hrbox.component" (dict "ctx" . "name" "file-processor") -}}
|
||||||
{{/*
|
|
||||||
Конвертация документов и обработка изображений.
|
|
||||||
|
|
||||||
Конвертация видео здесь всегда выключена: она требует принципиально другого
|
|
||||||
профиля ресурсов и живёт в отдельном деплойменте 09-file-processor-video.
|
|
||||||
*/}}
|
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
{{- $name := include "hrbox.component" (dict "ctx" . "name" "geonames") -}}
|
{{- $name := include "hrbox.component" (dict "ctx" . "name" "geonames") -}}
|
||||||
{{/*
|
|
||||||
Справочник городов, стран и часовых поясов.
|
|
||||||
*/}}
|
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
|
|||||||
@@ -1,11 +1,4 @@
|
|||||||
{{- $name := include "hrbox.component" (dict "ctx" . "name" "goworker") -}}
|
{{- $name := include "hrbox.component" (dict "ctx" . "name" "goworker") -}}
|
||||||
{{/*
|
|
||||||
Интеграции с мессенджерами, push-уведомления, синхронизация оргструктуры
|
|
||||||
с 1С и восстановление проекций Nanabush Player.
|
|
||||||
|
|
||||||
Метрики Prometheus отдаются на том же порту 8686 по пути /metrics, поэтому
|
|
||||||
аннотации сбора висят на Service, а не на поде.
|
|
||||||
*/}}
|
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
|
|||||||
@@ -1,12 +1,4 @@
|
|||||||
{{- $name := include "hrbox.component" (dict "ctx" . "name" "kedoca") -}}
|
{{- $name := include "hrbox.component" (dict "ctx" . "name" "kedoca") -}}
|
||||||
{{/*
|
|
||||||
Сервис электронной подписи: КЭДО, МЧД, метки времени.
|
|
||||||
Умеет ГОСТ (через КриптоПро) и обычный OpenSSL — выбор в app.kedoca.engine.
|
|
||||||
|
|
||||||
app.kedoca.secretName подключает Secret с сертификатами удостоверяющего
|
|
||||||
центра. Без него сервис создаёт собственный корневой сертификат при первом
|
|
||||||
запуске — это годится для теста, но не для юридически значимого документооборота.
|
|
||||||
*/}}
|
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
|
|||||||
@@ -2,22 +2,6 @@
|
|||||||
{{- if $cfg.enabled }}
|
{{- if $cfg.enabled }}
|
||||||
{{- $name := include "nanabushPlayer.serviceName" . -}}
|
{{- $name := include "nanabushPlayer.serviceName" . -}}
|
||||||
{{- $secretName := include "nanabushPlayer.secretName" . -}}
|
{{- $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
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
@@ -49,9 +33,6 @@ spec:
|
|||||||
prometheus.io/path: "/metrics"
|
prometheus.io/path: "/metrics"
|
||||||
{{- end }}
|
{{- end }}
|
||||||
spec:
|
spec:
|
||||||
# Плееру не нужен доступ к API Kubernetes, а исполняет он содержимое,
|
|
||||||
# загруженное пользователями, — поэтому токен не монтируется, процесс
|
|
||||||
# не root, корневая файловая система только на чтение.
|
|
||||||
automountServiceAccountToken: false
|
automountServiceAccountToken: false
|
||||||
terminationGracePeriodSeconds: {{ $cfg.terminationGracePeriodSeconds }}
|
terminationGracePeriodSeconds: {{ $cfg.terminationGracePeriodSeconds }}
|
||||||
{{- include "hrbox.imagePullSecrets" . | nindent 6 }}
|
{{- include "hrbox.imagePullSecrets" . | nindent 6 }}
|
||||||
@@ -89,8 +70,6 @@ spec:
|
|||||||
{{- else }}
|
{{- else }}
|
||||||
value: "off"
|
value: "off"
|
||||||
{{- end }}
|
{{- end }}
|
||||||
# Путь монтирования не входит в audience: audience — это origin
|
|
||||||
# браузера, иначе сломались бы проверки на стороне клиента.
|
|
||||||
- name: PLAYER_BASE_PATH
|
- name: PLAYER_BASE_PATH
|
||||||
value: {{ include "nanabushPlayer.basePath" . | quote }}
|
value: {{ include "nanabushPlayer.basePath" . | quote }}
|
||||||
- name: PLAYER_AUDIENCE
|
- name: PLAYER_AUDIENCE
|
||||||
@@ -103,16 +82,12 @@ spec:
|
|||||||
name: {{ $secretName | quote }}
|
name: {{ $secretName | quote }}
|
||||||
key: {{ required "Нужно имя ключа ticketHs256 в секрете Nanabush Player" $cfg.existingSecret.keys.ticketHs256 | quote }}
|
key: {{ required "Нужно имя ключа ticketHs256 в секрете Nanabush Player" $cfg.existingSecret.keys.ticketHs256 | quote }}
|
||||||
{{- with $cfg.existingSecret.keys.ticketKeys }}
|
{{- with $cfg.existingSecret.keys.ticketKeys }}
|
||||||
# Кольцо ключей: подпись проверяется ключом, выбранным по kid из
|
|
||||||
# тикета, поэтому во время ротации работают обе версии HRBox.
|
|
||||||
- name: PLAYER_TICKET_KEYS
|
- name: PLAYER_TICKET_KEYS
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: {{ $secretName | quote }}
|
name: {{ $secretName | quote }}
|
||||||
key: {{ . | quote }}
|
key: {{ . | quote }}
|
||||||
{{- with $cfg.ticket.keylessAcceptedUntil }}
|
{{- with $cfg.ticket.keylessAcceptedUntil }}
|
||||||
# Только на первую раскатку: принимать тикеты без kid от версии
|
|
||||||
# HRBox, которая ещё не знает про кольцо ключей.
|
|
||||||
- name: PLAYER_TICKET_KEYLESS_UNTIL
|
- name: PLAYER_TICKET_KEYLESS_UNTIL
|
||||||
value: {{ . | quote }}
|
value: {{ . | quote }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
@@ -139,8 +114,6 @@ spec:
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
- name: PLAYER_REDIS_KEY_PREFIX
|
- name: PLAYER_REDIS_KEY_PREFIX
|
||||||
value: {{ include "nanabushPlayer.redisKeyPrefix" . | quote }}
|
value: {{ include "nanabushPlayer.redisKeyPrefix" . | quote }}
|
||||||
# Обратный канал: единственный разрешённый адрес — внутрикластерный
|
|
||||||
# HRBox. Так пакет курса не сможет заставить плеер сходить наружу.
|
|
||||||
- name: PLAYER_PACKAGE_FETCH_SCHEMES
|
- name: PLAYER_PACKAGE_FETCH_SCHEMES
|
||||||
value: {{ $cfg.backchannel.schemes | quote }}
|
value: {{ $cfg.backchannel.schemes | quote }}
|
||||||
- name: PLAYER_PACKAGE_FETCH_ALLOWLIST
|
- name: PLAYER_PACKAGE_FETCH_ALLOWLIST
|
||||||
@@ -222,8 +195,6 @@ spec:
|
|||||||
type: ClusterIP
|
type: ClusterIP
|
||||||
selector:
|
selector:
|
||||||
service: {{ $name }}
|
service: {{ $name }}
|
||||||
# Порт метрик наружу намеренно не публикуется: содержимое курсов приходит
|
|
||||||
# с того же origin и не должно читать эксплуатационные метрики.
|
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
port: {{ .Values.app.nanabushPlayer.service.port }}
|
port: {{ .Values.app.nanabushPlayer.service.port }}
|
||||||
|
|||||||
@@ -1,18 +1,5 @@
|
|||||||
{{- if .Values.ingress.enabled }}
|
{{- if .Values.ingress.enabled }}
|
||||||
{{- $player := .Values.app.nanabushPlayer -}}
|
{{- $player := .Values.app.nanabushPlayer -}}
|
||||||
{{/*
|
|
||||||
Единая точка входа.
|
|
||||||
|
|
||||||
Все три маршрута живут на одном домене, потому что в on-premise выделенных
|
|
||||||
поддоменов под сервисы нет:
|
|
||||||
|
|
||||||
{{ include "nanabushPlayer.basePath" . }}/ -> плеер учебных материалов
|
|
||||||
/chatbox/ -> вебсокеты чата
|
|
||||||
/ -> само приложение
|
|
||||||
|
|
||||||
Длинные таймауты нужны вебсокетам и плееру: и то и другое держит соединение
|
|
||||||
открытым, пока пользователь работает.
|
|
||||||
*/}}
|
|
||||||
---
|
---
|
||||||
apiVersion: networking.k8s.io/v1
|
apiVersion: networking.k8s.io/v1
|
||||||
kind: Ingress
|
kind: Ingress
|
||||||
@@ -21,12 +8,7 @@ metadata:
|
|||||||
labels:
|
labels:
|
||||||
{{- include "hrbox.labels" (dict "ctx" . "name" "web") | nindent 4 }}
|
{{- include "hrbox.labels" (dict "ctx" . "name" "web") | nindent 4 }}
|
||||||
annotations:
|
annotations:
|
||||||
# Аннотация класса устарела в пользу spec.ingressClassName ниже, но
|
|
||||||
# оставлена: контроллеры старше ingress-nginx 1.0 понимают только её.
|
|
||||||
# Когда заданы обе, современный контроллер использует ingressClassName.
|
|
||||||
kubernetes.io/ingress.class: {{ .Values.ingress.className | quote }}
|
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.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-body-size: {{ .Values.ingress.maxBodySize | quote }}
|
||||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
||||||
|
|||||||
@@ -1,12 +1,3 @@
|
|||||||
{{/*
|
|
||||||
Миграции базы данных.
|
|
||||||
|
|
||||||
Хук post-install/post-upgrade с весом 10: выполняется после того, как Helm
|
|
||||||
создал ConfigMap и Secret, но до джобы обновления кластера (вес 20).
|
|
||||||
Имя джобы содержит номер ревизии релиза, поэтому в истории видно, какой
|
|
||||||
выкат её запускал, а повторный upgrade не спотыкается об уже существующий
|
|
||||||
объект.
|
|
||||||
*/}}
|
|
||||||
---
|
---
|
||||||
apiVersion: batch/v1
|
apiVersion: batch/v1
|
||||||
kind: Job
|
kind: Job
|
||||||
|
|||||||
@@ -1,9 +1,3 @@
|
|||||||
{{/*
|
|
||||||
Обновление данных кластера после миграций: пересчёт справочников,
|
|
||||||
перерегистрация фоновых задач, обновление настроек арендаторов.
|
|
||||||
|
|
||||||
Вес 20 — строго после джобы миграций (вес 10).
|
|
||||||
*/}}
|
|
||||||
---
|
---
|
||||||
apiVersion: batch/v1
|
apiVersion: batch/v1
|
||||||
kind: Job
|
kind: Job
|
||||||
|
|||||||
+16
-47
@@ -1,18 +1,5 @@
|
|||||||
{{/*
|
|
||||||
============================================================================
|
|
||||||
Переменные окружения HRBox
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
envs_all включается во все контейнеры, которым нужен конфиг приложения:
|
|
||||||
web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
|
|
||||||
и джобы миграций. Один общий блок проще расходящихся наборов, и именно так
|
|
||||||
устроено продовое окружение.
|
|
||||||
|
|
||||||
Чувствительные значения приходят через secretKeyRef из секрета приложения
|
|
||||||
(00-app-secret.yaml), а не открытым текстом в спеке пода.
|
|
||||||
*/}}
|
|
||||||
{{- define "envs_all" }}
|
{{- define "envs_all" }}
|
||||||
# --- Приложение -----------------------------------------------------------
|
# Приложение
|
||||||
- name: INSTANCE_NAME
|
- name: INSTANCE_NAME
|
||||||
value: {{ .Values.app.instanceName | quote }}
|
value: {{ .Values.app.instanceName | quote }}
|
||||||
- name: DEFAULT_TENANT_HOSTNAME
|
- 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" "APP_ENCRYPTION_KEY" "key" "encryption-key") | nindent 0 }}
|
||||||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "SERVICES_INTERNAL_SECRET" "key" "services-internal-secret") | nindent 0 }}
|
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "SERVICES_INTERNAL_SECRET" "key" "services-internal-secret") | nindent 0 }}
|
||||||
|
|
||||||
# --- Своя политика конфиденциальности -------------------------------------
|
# Своя политика конфиденциальности
|
||||||
- name: ALLOW_CUSTOM_POLICY_URLS
|
- name: ALLOW_CUSTOM_POLICY_URLS
|
||||||
value: {{ .Values.app.customPolicy.enabled | quote }}
|
value: {{ .Values.app.customPolicy.enabled | quote }}
|
||||||
{{- if .Values.app.customPolicy.enabled }}
|
{{- if .Values.app.customPolicy.enabled }}
|
||||||
@@ -60,7 +47,7 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
|
|||||||
value: ""
|
value: ""
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
# --- PostgreSQL -----------------------------------------------------------
|
# PostgreSQL
|
||||||
- name: POSTGRES_VHOST
|
- name: POSTGRES_VHOST
|
||||||
value: {{ .Values.app.postgres.host | quote }}
|
value: {{ .Values.app.postgres.host | quote }}
|
||||||
- name: POSTGRES_PORT
|
- name: POSTGRES_PORT
|
||||||
@@ -73,7 +60,7 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
|
|||||||
value: {{ .Values.app.postgres.citus | quote }}
|
value: {{ .Values.app.postgres.citus | quote }}
|
||||||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "POSTGRES_PASSWORD" "key" "postgres-password") | nindent 0 }}
|
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "POSTGRES_PASSWORD" "key" "postgres-password") | nindent 0 }}
|
||||||
|
|
||||||
# --- Redis / Dragonfly ----------------------------------------------------
|
# Redis / Dragonfly
|
||||||
- name: REDIS_HOST
|
- name: REDIS_HOST
|
||||||
value: {{ include "hrbox.redisHost" . | quote }}
|
value: {{ include "hrbox.redisHost" . | quote }}
|
||||||
- name: REDIS_PORT
|
- name: REDIS_PORT
|
||||||
@@ -81,13 +68,11 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
|
|||||||
- name: REDIS_CONNECTION
|
- name: REDIS_CONNECTION
|
||||||
value: {{ printf "tcp://%s:%s" (include "hrbox.redisHost" .) (.Values.app.redis.port | toString) | quote }}
|
value: {{ printf "tcp://%s:%s" (include "hrbox.redisHost" .) (.Values.app.redis.port | toString) | quote }}
|
||||||
|
|
||||||
# --- NATS -----------------------------------------------------------------
|
# NATS
|
||||||
- name: BROKER
|
- name: BROKER
|
||||||
value: "nats"
|
value: "nats"
|
||||||
- name: NATS_URL
|
- name: NATS_URL
|
||||||
value: {{ include "hrbox.natsUrl" . | quote }}
|
value: {{ include "hrbox.natsUrl" . | quote }}
|
||||||
# Число реплик JetStream-стримов должно совпадать с размером кластера NATS,
|
|
||||||
# иначе стрим создаётся в одном экземпляре и теряется вместе со своей нодой.
|
|
||||||
- name: NATS_STREAM_REPLICAS
|
- name: NATS_STREAM_REPLICAS
|
||||||
{{- if and .Values.nats.enabled .Values.nats.cluster.enabled }}
|
{{- if and .Values.nats.enabled .Values.nats.cluster.enabled }}
|
||||||
value: {{ .Values.nats.cluster.replicas | quote }}
|
value: {{ .Values.nats.cluster.replicas | quote }}
|
||||||
@@ -95,7 +80,7 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
|
|||||||
value: "1"
|
value: "1"
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
# --- S3 -------------------------------------------------------------------
|
# S3
|
||||||
- name: S3_ENDPOINT
|
- name: S3_ENDPOINT
|
||||||
value: {{ .Values.app.s3.endpoint | quote }}
|
value: {{ .Values.app.s3.endpoint | quote }}
|
||||||
- name: S3_BUCKET
|
- 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_KEY" "key" "s3-key") | nindent 0 }}
|
||||||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "S3_SECRET" "key" "s3-secret") | nindent 0 }}
|
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "S3_SECRET" "key" "s3-secret") | nindent 0 }}
|
||||||
|
|
||||||
# --- Почта ----------------------------------------------------------------
|
# Почта
|
||||||
- name: SENDER_ENV
|
- name: SENDER_ENV
|
||||||
value: "PROD"
|
value: "PROD"
|
||||||
- name: SENDER_DEV_EMAIL
|
- name: SENDER_DEV_EMAIL
|
||||||
@@ -136,7 +121,7 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
|
|||||||
value: {{ .Values.app.smtp.sslVerifyPeer | quote }}
|
value: {{ .Values.app.smtp.sslVerifyPeer | quote }}
|
||||||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "SMTP_PASSWORD" "key" "smtp-password") | nindent 0 }}
|
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "SMTP_PASSWORD" "key" "smtp-password") | nindent 0 }}
|
||||||
|
|
||||||
# --- Внутренние сервисы ---------------------------------------------------
|
# Внутренние сервисы
|
||||||
- name: GEONAMES_URL
|
- name: GEONAMES_URL
|
||||||
value: {{ include "hrbox.geonamesUrl" . | quote }}
|
value: {{ include "hrbox.geonamesUrl" . | quote }}
|
||||||
- name: GOWORKER_URL
|
- name: GOWORKER_URL
|
||||||
@@ -160,27 +145,27 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
|
|||||||
- name: DOCCONV_MAX_PARALLEL_TASKS
|
- name: DOCCONV_MAX_PARALLEL_TASKS
|
||||||
value: {{ .Values.app.fileProcessor.docconvMaxParallelTasks | quote }}
|
value: {{ .Values.app.fileProcessor.docconvMaxParallelTasks | quote }}
|
||||||
|
|
||||||
# --- HRBox Hub ------------------------------------------------------------
|
# HRBox Hub
|
||||||
- name: HUB_URL
|
- name: HUB_URL
|
||||||
value: {{ .Values.app.hub.url | quote }}
|
value: {{ .Values.app.hub.url | quote }}
|
||||||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "HUB_TOKEN" "key" "hub-token") | nindent 0 }}
|
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "HUB_TOKEN" "key" "hub-token") | nindent 0 }}
|
||||||
|
|
||||||
# --- Nanabush Player ------------------------------------------------------
|
# Nanabush Player
|
||||||
{{- include "envs_nanabush_player" . }}
|
{{- include "envs_nanabush_player" . }}
|
||||||
|
|
||||||
# --- Чат ------------------------------------------------------------------
|
# Чат
|
||||||
- name: CHATBOX_SENTRY_DSN
|
- name: CHATBOX_SENTRY_DSN
|
||||||
value: {{ .Values.app.sentry.chatboxDsn | quote }}
|
value: {{ .Values.app.sentry.chatboxDsn | quote }}
|
||||||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "CHATBOX_WRAPPING_KEY" "key" "chatbox-wrapping-key") | nindent 0 }}
|
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "CHATBOX_WRAPPING_KEY" "key" "chatbox-wrapping-key") | nindent 0 }}
|
||||||
|
|
||||||
# --- Видеозвонки (LiveKit) ------------------------------------------------
|
# Видеозвонки (LiveKit)
|
||||||
- name: LIVEKIT_URL
|
- name: LIVEKIT_URL
|
||||||
value: {{ .Values.app.livekit.url | quote }}
|
value: {{ .Values.app.livekit.url | quote }}
|
||||||
- name: LIVEKIT_API_KEY
|
- name: LIVEKIT_API_KEY
|
||||||
value: {{ .Values.app.livekit.apiKey | quote }}
|
value: {{ .Values.app.livekit.apiKey | quote }}
|
||||||
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "LIVEKIT_API_SECRET" "key" "livekit-api-secret") | nindent 0 }}
|
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "LIVEKIT_API_SECRET" "key" "livekit-api-secret") | nindent 0 }}
|
||||||
|
|
||||||
# --- AI -------------------------------------------------------------------
|
# AI
|
||||||
- name: AI_DOCS_INDEX_ENABLED
|
- name: AI_DOCS_INDEX_ENABLED
|
||||||
value: {{ .Values.app.ai.docsIndexEnabled | quote }}
|
value: {{ .Values.app.ai.docsIndexEnabled | quote }}
|
||||||
- name: AI_SEMANTIC_INDEX_ENABLED
|
- 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 }}
|
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 }}
|
{{- include "hrbox.secretEnv" (dict "ctx" . "env" "YANDEX_CLOUD_AI_API_KEY" "key" "yandex-ai-api-key") | nindent 0 }}
|
||||||
|
|
||||||
# --- Внешние интеграции ---------------------------------------------------
|
# Внешние интеграции
|
||||||
- name: TELEGRAM_API_URL
|
- name: TELEGRAM_API_URL
|
||||||
value: {{ .Values.app.integrations.telegram.apiUrl | quote }}
|
value: {{ .Values.app.integrations.telegram.apiUrl | quote }}
|
||||||
- name: AUTH_GOOGLE_ENABLED
|
- name: AUTH_GOOGLE_ENABLED
|
||||||
@@ -211,7 +196,7 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
|
|||||||
- name: GLAGOL_API_URL
|
- name: GLAGOL_API_URL
|
||||||
value: {{ .Values.app.integrations.glagol.apiUrl | quote }}
|
value: {{ .Values.app.integrations.glagol.apiUrl | quote }}
|
||||||
|
|
||||||
# --- Sentry ---------------------------------------------------------------
|
# Sentry
|
||||||
- name: SENTRY_DSN
|
- name: SENTRY_DSN
|
||||||
value: {{ .Values.app.sentry.dsn | quote }}
|
value: {{ .Values.app.sentry.dsn | quote }}
|
||||||
- name: SENTRY_DSN_LAUNCHPAD
|
- name: SENTRY_DSN_LAUNCHPAD
|
||||||
@@ -223,7 +208,7 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
|
|||||||
- name: SENTRY_RELEASE
|
- name: SENTRY_RELEASE
|
||||||
value: {{ .Values.image.hrbox | quote }}
|
value: {{ .Values.image.hrbox | quote }}
|
||||||
|
|
||||||
# --- Метаданные пода ------------------------------------------------------
|
# Метаданные пода
|
||||||
- name: POD_NAME
|
- name: POD_NAME
|
||||||
valueFrom:
|
valueFrom:
|
||||||
fieldRef:
|
fieldRef:
|
||||||
@@ -242,13 +227,6 @@ web, worker, conductor, chatbox, goworker, kedoca, file-processor, geonames
|
|||||||
fieldPath: spec.nodeName
|
fieldPath: spec.nodeName
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{/*
|
|
||||||
Настройки Nanabush Player на стороне HRBox.
|
|
||||||
|
|
||||||
NANABUSH_PLAYER_AUDIENCE и NANABUSH_PLAYER_PUBLIC_ORIGIN всегда равны:
|
|
||||||
audience тикета — это origin браузера без пути, а путь монтирования едет
|
|
||||||
отдельной переменной NANABUSH_PLAYER_BASE_PATH.
|
|
||||||
*/}}
|
|
||||||
{{- define "envs_nanabush_player" -}}
|
{{- define "envs_nanabush_player" -}}
|
||||||
{{- $player := .Values.app.nanabushPlayer }}
|
{{- $player := .Values.app.nanabushPlayer }}
|
||||||
- name: NANABUSH_PLAYER_ENABLED
|
- name: NANABUSH_PLAYER_ENABLED
|
||||||
@@ -291,10 +269,6 @@ audience тикета — это origin браузера без пути, а п
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/*
|
|
||||||
Ключ подписи launch-тикета. Живёт только в PHP-контейнерах, которые выпускают
|
|
||||||
тикеты: nginx и вспомогательным контейнерам он не нужен.
|
|
||||||
*/}}
|
|
||||||
{{- define "envs_nanabush_player_signing" -}}
|
{{- define "envs_nanabush_player_signing" -}}
|
||||||
{{- $cfg := .Values.app.nanabushPlayer.deployment }}
|
{{- $cfg := .Values.app.nanabushPlayer.deployment }}
|
||||||
{{- if $cfg.enabled }}
|
{{- if $cfg.enabled }}
|
||||||
@@ -304,9 +278,6 @@ audience тикета — это origin браузера без пути, а п
|
|||||||
name: {{ include "nanabushPlayer.secretName" . | quote }}
|
name: {{ include "nanabushPlayer.secretName" . | quote }}
|
||||||
key: {{ required "Нужно имя ключа ticketHs256 в секрете Nanabush Player" $cfg.existingSecret.keys.ticketHs256 | quote }}
|
key: {{ required "Нужно имя ключа ticketHs256 в секрете Nanabush Player" $cfg.existingSecret.keys.ticketHs256 | quote }}
|
||||||
{{- with $cfg.existingSecret.keys.ticketKeys }}
|
{{- with $cfg.existingSecret.keys.ticketKeys }}
|
||||||
# Кольцо ключей launch-тикета: HRBox подписывает первым ключом, Player
|
|
||||||
# принимает все. Тот же ключ секрета читает и сам Player, поэтому ротация —
|
|
||||||
# это одно значение на обе стороны.
|
|
||||||
- name: NANABUSH_PLAYER_TICKET_KEYS
|
- name: NANABUSH_PLAYER_TICKET_KEYS
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
@@ -316,7 +287,6 @@ audience тикета — это origin браузера без пути, а п
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/* Криптографические настройки сервиса электронной подписи. */}}
|
|
||||||
{{- define "envs_kedoca" }}
|
{{- define "envs_kedoca" }}
|
||||||
- name: ROOT_CA_PASS
|
- name: ROOT_CA_PASS
|
||||||
value: {{ .Values.app.kedoca.rootCaPass | quote }}
|
value: {{ .Values.app.kedoca.rootCaPass | quote }}
|
||||||
@@ -328,7 +298,6 @@ audience тикета — это origin браузера без пути, а п
|
|||||||
value: {{ .Values.app.kedoca.pkeyopt | quote }}
|
value: {{ .Values.app.kedoca.pkeyopt | quote }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{/* OpenTelemetry — только когда app.tracing.enabled. */}}
|
|
||||||
{{- define "envs_tracing" }}
|
{{- define "envs_tracing" }}
|
||||||
- name: OTEL_PHP_AUTOLOAD_ENABLED
|
- name: OTEL_PHP_AUTOLOAD_ENABLED
|
||||||
value: "true"
|
value: "true"
|
||||||
|
|||||||
@@ -1,49 +1,19 @@
|
|||||||
{{/*
|
|
||||||
============================================================================
|
|
||||||
Общие хелперы чарта HRBox
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
Правило именования: все объекты называются "<имя чарта>-<компонент>"
|
|
||||||
(hrbox-web, hrbox-worker, ...). Имя чарта можно переопределить через
|
|
||||||
nameOverride, но по умолчанию оно равно "hrbox" — так же, как в чарте 2.x,
|
|
||||||
поэтому обновление 2.x -> 3.x не пересоздаёт объекты.
|
|
||||||
*/}}
|
|
||||||
|
|
||||||
{{/* Базовое имя релиза: "hrbox" или nameOverride. */}}
|
|
||||||
{{- define "hrbox.name" -}}
|
{{- define "hrbox.name" -}}
|
||||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/* Имя чарта с версией — для лейбла helm.sh/chart. */}}
|
|
||||||
{{- define "hrbox.chart" -}}
|
{{- define "hrbox.chart" -}}
|
||||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/*
|
|
||||||
Полное имя объекта компонента.
|
|
||||||
|
|
||||||
Usage: {{ include "hrbox.component" (dict "ctx" . "name" "web") }} -> hrbox-web
|
|
||||||
*/}}
|
|
||||||
{{- define "hrbox.component" -}}
|
{{- define "hrbox.component" -}}
|
||||||
{{- printf "%s-%s" (include "hrbox.name" .ctx) .name | trunc 63 | trimSuffix "-" -}}
|
{{- printf "%s-%s" (include "hrbox.name" .ctx) .name | trunc 63 | trimSuffix "-" -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/*
|
|
||||||
Селектор пода. ВАЖНО: spec.selector в Deployment неизменяем, поэтому набор
|
|
||||||
лейблов здесь совпадает с чартом 2.x (один лейбл "service") и меняться не должен.
|
|
||||||
|
|
||||||
Usage: {{- include "hrbox.selectorLabels" (dict "ctx" . "name" "web") | nindent 6 }}
|
|
||||||
*/}}
|
|
||||||
{{- define "hrbox.selectorLabels" -}}
|
{{- define "hrbox.selectorLabels" -}}
|
||||||
service: {{ include "hrbox.component" (dict "ctx" .ctx "name" .name) }}
|
service: {{ include "hrbox.component" (dict "ctx" .ctx "name" .name) }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/*
|
|
||||||
Лейблы объекта. Лейбл "app" сохранён из чарта 2.x — на него опираются
|
|
||||||
привычные команды вида "kubectl get pods -l app=worker".
|
|
||||||
|
|
||||||
Usage: {{- include "hrbox.labels" (dict "ctx" . "name" "web") | nindent 4 }}
|
|
||||||
*/}}
|
|
||||||
{{- define "hrbox.labels" -}}
|
{{- define "hrbox.labels" -}}
|
||||||
app: {{ .name }}
|
app: {{ .name }}
|
||||||
app.kubernetes.io/name: {{ include "hrbox.name" .ctx }}
|
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 }}
|
helm.sh/chart: {{ include "hrbox.chart" .ctx }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/*
|
|
||||||
Секреты для доступа к приватному Docker-реестру.
|
|
||||||
|
|
||||||
Usage: {{- include "hrbox.imagePullSecrets" . | nindent 6 }}
|
|
||||||
*/}}
|
|
||||||
{{- define "hrbox.imagePullSecrets" -}}
|
{{- define "hrbox.imagePullSecrets" -}}
|
||||||
{{- if .Values.imagePullSecrets }}
|
{{- if .Values.imagePullSecrets }}
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
@@ -68,11 +33,6 @@ imagePullSecrets:
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/*
|
|
||||||
Тег из ссылки на образ: "registry/repo:1.2.3" -> "1.2.3".
|
|
||||||
Двоеточие ищется только в последнем сегменте пути, чтобы не спутать тег
|
|
||||||
с портом реестра ("registry:5000/repo").
|
|
||||||
*/}}
|
|
||||||
{{- define "hrbox.imageTag" -}}
|
{{- define "hrbox.imageTag" -}}
|
||||||
{{- $lastSegment := splitList "/" . | last -}}
|
{{- $lastSegment := splitList "/" . | last -}}
|
||||||
{{- if contains ":" $lastSegment -}}
|
{{- if contains ":" $lastSegment -}}
|
||||||
@@ -80,27 +40,6 @@ imagePullSecrets:
|
|||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/*
|
|
||||||
============================================================================
|
|
||||||
Секрет приложения
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
Чувствительные значения (пароли БД и SMTP, ключи шифрования, токены) не
|
|
||||||
попадают в env-блоки Deployment открытым текстом: чарт складывает их в один
|
|
||||||
Secret, а контейнеры читают его через secretKeyRef. Полный список ключей —
|
|
||||||
в README, раздел "Секреты".
|
|
||||||
|
|
||||||
secrets.existingSecret позволяет подставить Secret, созданный вне чарта
|
|
||||||
(например, из внешнего vault-оператора) — тогда чарт свой Secret не создаёт.
|
|
||||||
*/}}
|
|
||||||
{{/*
|
|
||||||
Адреса внутренних сервисов.
|
|
||||||
|
|
||||||
Сервисы релиза адресуются по именам, которые создаёт этот же чарт, поэтому
|
|
||||||
пустое значение в values резолвится в имя из hrbox.component: адреса не
|
|
||||||
разъезжаются при nameOverride и их не нужно править вручную. Непустое
|
|
||||||
значение используется как есть — для сервиса за пределами релиза.
|
|
||||||
*/}}
|
|
||||||
{{- define "hrbox.geonamesUrl" -}}
|
{{- define "hrbox.geonamesUrl" -}}
|
||||||
{{- .Values.app.geonames.url | default (printf "http://%s:8181" (include "hrbox.component" (dict "ctx" . "name" "geonames"))) -}}
|
{{- .Values.app.geonames.url | default (printf "http://%s:8181" (include "hrbox.component" (dict "ctx" . "name" "geonames"))) -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
@@ -129,11 +68,6 @@ secrets.existingSecret позволяет подставить Secret, созд
|
|||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/*
|
|
||||||
Одна переменная окружения из секрета приложения.
|
|
||||||
|
|
||||||
Usage: {{ include "hrbox.secretEnv" (dict "ctx" . "env" "POSTGRES_PASSWORD" "key" "postgres-password") }}
|
|
||||||
*/}}
|
|
||||||
{{- define "hrbox.secretEnv" -}}
|
{{- define "hrbox.secretEnv" -}}
|
||||||
- name: {{ .env }}
|
- name: {{ .env }}
|
||||||
valueFrom:
|
valueFrom:
|
||||||
@@ -142,23 +76,6 @@ Usage: {{ include "hrbox.secretEnv" (dict "ctx" . "env" "POSTGRES_PASSWORD" "key
|
|||||||
key: {{ .key | quote }}
|
key: {{ .key | quote }}
|
||||||
{{- end -}}
|
{{- 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" -}}
|
{{- define "nanabushPlayer.host" -}}
|
||||||
{{- required "Для Nanabush Player нужен непустой ingress.host" .Values.ingress.host -}}
|
{{- required "Для Nanabush Player нужен непустой ingress.host" .Values.ingress.host -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
@@ -167,10 +84,6 @@ On-premise-топология Player'а отличается от облачно
|
|||||||
{{- printf "https://%s" (include "nanabushPlayer.host" .) -}}
|
{{- printf "https://%s" (include "nanabushPlayer.host" .) -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/*
|
|
||||||
Путь монтирования Player'а на основном домене. Пустое значение и "/" запрещены:
|
|
||||||
это отдало бы Player'у корень, занятый самим HRBox.
|
|
||||||
*/}}
|
|
||||||
{{- define "nanabushPlayer.basePath" -}}
|
{{- define "nanabushPlayer.basePath" -}}
|
||||||
{{- $path := .Values.app.nanabushPlayer.basePath | default "/nanabush-player" -}}
|
{{- $path := .Values.app.nanabushPlayer.basePath | default "/nanabush-player" -}}
|
||||||
{{- $path | trimSuffix "/" -}}
|
{{- $path | trimSuffix "/" -}}
|
||||||
@@ -188,11 +101,6 @@ On-premise-топология Player'а отличается от облачно
|
|||||||
{{- .Values.app.nanabushPlayer.service.name | default (include "hrbox.component" (dict "ctx" . "name" "nanabush-player")) -}}
|
{{- .Values.app.nanabushPlayer.service.name | default (include "hrbox.component" (dict "ctx" . "name" "nanabush-player")) -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/*
|
|
||||||
Хост обратного канала Player -> HRBox. Только внутрикластерное имя: по нему
|
|
||||||
Player забирает пакеты курсов и отправляет отчёты, и оно же попадает в
|
|
||||||
allowlist самого Player'а.
|
|
||||||
*/}}
|
|
||||||
{{- define "nanabushPlayer.backchannelHost" -}}
|
{{- define "nanabushPlayer.backchannelHost" -}}
|
||||||
{{- .Values.app.nanabushPlayer.deployment.backchannel.host | default (include "hrbox.component" (dict "ctx" . "name" "web")) -}}
|
{{- .Values.app.nanabushPlayer.deployment.backchannel.host | default (include "hrbox.component" (dict "ctx" . "name" "web")) -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
@@ -201,10 +109,6 @@ allowlist самого Player'а.
|
|||||||
{{- printf "http://%s" (include "nanabushPlayer.backchannelHost" .) -}}
|
{{- printf "http://%s" (include "nanabushPlayer.backchannelHost" .) -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/*
|
|
||||||
Версия Player'а берётся из тега образа, а не из отдельной настройки: тикет
|
|
||||||
не должен объявлять версию, отличную от той, что реально запущена в кластере.
|
|
||||||
*/}}
|
|
||||||
{{- define "nanabushPlayer.version" -}}
|
{{- define "nanabushPlayer.version" -}}
|
||||||
{{- $tag := include "hrbox.imageTag" .Values.image.nanabushPlayer -}}
|
{{- $tag := include "hrbox.imageTag" .Values.image.nanabushPlayer -}}
|
||||||
{{- if not $tag -}}
|
{{- if not $tag -}}
|
||||||
@@ -217,15 +121,10 @@ allowlist самого Player'а.
|
|||||||
{{- required "app.nanabushPlayer.deployment.existingSecret.name обязателен, когда Player включён" .Values.app.nanabushPlayer.deployment.existingSecret.name -}}
|
{{- required "app.nanabushPlayer.deployment.existingSecret.name обязателен, когда Player включён" .Values.app.nanabushPlayer.deployment.existingSecret.name -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/* URL Redis, который чарт собирает из штатных настроек app.redis. */}}
|
|
||||||
{{- define "nanabushPlayer.redisUrl" -}}
|
{{- define "nanabushPlayer.redisUrl" -}}
|
||||||
{{- printf "redis://%s:%s/%d" (include "hrbox.redisHost" .) (.Values.app.redis.port | toString) (.Values.app.nanabushPlayer.deployment.redis.database | int) -}}
|
{{- printf "redis://%s:%s/%d" (include "hrbox.redisHost" .) (.Values.app.redis.port | toString) (.Values.app.nanabushPlayer.deployment.redis.database | int) -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/*
|
|
||||||
Префикс ключей Redis. Namespace в префиксе разводит несколько релизов HRBox,
|
|
||||||
живущих на одном Dragonfly.
|
|
||||||
*/}}
|
|
||||||
{{- define "nanabushPlayer.redisKeyPrefix" -}}
|
{{- define "nanabushPlayer.redisKeyPrefix" -}}
|
||||||
{{- printf "hrbox:%s:%s" .Release.Namespace .Values.app.nanabushPlayer.deployment.redis.keyPrefixSuffix -}}
|
{{- printf "hrbox:%s:%s" .Release.Namespace .Values.app.nanabushPlayer.deployment.redis.keyPrefixSuffix -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|||||||
@@ -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" -}}
|
{{- define "hrbox.resources" -}}
|
||||||
{{- $r := index .ctx.Values.resources .component -}}
|
{{- $r := index .ctx.Values.resources .component -}}
|
||||||
{{- if $r }}
|
{{- if $r }}
|
||||||
|
|||||||
+166
-203
@@ -1,57 +1,44 @@
|
|||||||
---
|
---
|
||||||
# ============================================================================
|
# Конфигурация HRBox для установки в своём кластере.
|
||||||
# HRBox — конфигурация on-premise установки
|
|
||||||
# ============================================================================
|
|
||||||
#
|
#
|
||||||
# Минимум, который нужно заполнить перед первым деплоем:
|
# Заполните перед первой установкой:
|
||||||
|
# ingress.host домен, по которому будет открываться HRBox
|
||||||
|
# app.defaultTenantHostname тот же домен
|
||||||
|
# app.postgres.* подключение к PostgreSQL
|
||||||
|
# app.s3.* хранилище файлов
|
||||||
|
# app.smtp.* почта
|
||||||
|
# app.hub.token токен HRBox Hub, выдают сотрудники HRBox
|
||||||
|
# secrets.* три ключа, генерируются openssl
|
||||||
|
# app.chatbox.wrappingKey ключ шифрования чатов
|
||||||
|
# app.nanabushPlayer.keys.* два ключа плеера курсов
|
||||||
#
|
#
|
||||||
# ingress.host домен инсталляции
|
# Если что-то из этого не заполнено, helm остановится и напишет, чего не
|
||||||
# app.defaultTenantHostname тот же домен
|
# хватает. Команды генерации ключей — в README, раздел «Секреты».
|
||||||
# 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 и т.д.
|
||||||
# то есть hrbox-web, hrbox-worker и так далее. Менять на работающей установке
|
# На уже работающей установке менять нельзя.
|
||||||
# нельзя: selector у Deployment неизменяем.
|
|
||||||
nameOverride: ""
|
nameOverride: ""
|
||||||
|
|
||||||
# ============================================================================
|
# --- Образы ---------------------------------------------------------------
|
||||||
# Образы
|
|
||||||
# ============================================================================
|
|
||||||
# Все образы собраны в одном месте: обновление версии сервиса — это правка
|
|
||||||
# одной строки здесь, а не поиск по шаблонам.
|
|
||||||
image:
|
image:
|
||||||
# Основное приложение (PHP-FPM, nginx, worker, conductor-задачи, миграции).
|
# Приложение: PHP-FPM, nginx, worker, миграции.
|
||||||
# Доступ к реестру выдают сотрудники HRBox.
|
# Доступ к реестру выдают сотрудники HRBox.
|
||||||
hrbox: "cr.yandex/crphnph9c2s776j32sjd/hrbox:latest"
|
hrbox: "cr.yandex/crphnph9c2s776j32sjd/hrbox:latest"
|
||||||
|
|
||||||
# Чат и вебсокеты
|
# Чат и вебсокеты
|
||||||
chatbox: "cr.yandex/crphnph9c2s776j32sjd/hrbox-chatbox:5.18"
|
chatbox: "cr.yandex/crphnph9c2s776j32sjd/hrbox-chatbox:5.18"
|
||||||
# Интеграции с мессенджерами, пуши, синхронизация оргструктуры
|
# Мессенджеры, пуши, синхронизация оргструктуры
|
||||||
goworker: "cr.yandex/crphnph9c2s776j32sjd/hrbox-goworker:3.21.2"
|
goworker: "cr.yandex/crphnph9c2s776j32sjd/hrbox-goworker:3.21.2"
|
||||||
# Электронная подпись (КЭДО, МЧД)
|
# Электронная подпись: КЭДО, МЧД
|
||||||
kedoca: "cr.yandex/crphnph9c2s776j32sjd/hrbox-kedoca:1.0.6"
|
kedoca: "cr.yandex/crphnph9c2s776j32sjd/hrbox-kedoca:1.0.6"
|
||||||
# Справочник городов, стран и часовых поясов
|
# Справочник городов, стран, часовых поясов
|
||||||
geonames: "cr.yandex/crphnph9c2s776j32sjd/hrbox-geonames:3.3"
|
geonames: "cr.yandex/crphnph9c2s776j32sjd/hrbox-geonames:3.3"
|
||||||
# Конвертация документов и обработка изображений
|
# Конвертация документов и изображений
|
||||||
fileProcessor: "cr.yandex/crphnph9c2s776j32sjd/hrbox-file-processor:1.4.6"
|
fileProcessor: "cr.yandex/crphnph9c2s776j32sjd/hrbox-file-processor:1.4.6"
|
||||||
# Планировщик задач по расписанию
|
# Планировщик задач по расписанию
|
||||||
conductor: "cr.yandex/crphnph9c2s776j32sjd/hrbox-conductor:2.2.0"
|
conductor: "cr.yandex/crphnph9c2s776j32sjd/hrbox-conductor:2.2.0"
|
||||||
# Плеер учебных материалов (SCORM, cmi5, xAPI, нативные курсы).
|
# Плеер курсов. Нужен конкретный тег, latest не подходит:
|
||||||
# Тег обязателен и не может быть latest: из него выводится версия плеера,
|
# из тега берётся версия плеера.
|
||||||
# которую HRBox кладёт в launch-тикет.
|
|
||||||
nanabushPlayer: "cr.yandex/crphnph9c2s776j32sjd/nanabush-player:1.0.11"
|
nanabushPlayer: "cr.yandex/crphnph9c2s776j32sjd/nanabush-player:1.0.11"
|
||||||
|
|
||||||
# Инфраструктура
|
# Инфраструктура
|
||||||
@@ -59,48 +46,43 @@ image:
|
|||||||
nats: "nats:2.10"
|
nats: "nats:2.10"
|
||||||
natsConfigReloader: "natsio/nats-server-config-reloader:0.6.2"
|
natsConfigReloader: "natsio/nats-server-config-reloader:0.6.2"
|
||||||
phpFpmExporter: "cr.yandex/crpnn6fi85p3dauha6nc/php-fpm_exporter:latest"
|
phpFpmExporter: "cr.yandex/crpnn6fi85p3dauha6nc/php-fpm_exporter:latest"
|
||||||
# Используется только init-контейнером джобы миграций (ждёт готовности БД)
|
# Только для джобы миграций: ждёт готовности базы
|
||||||
postgresClient: "postgres:14-alpine"
|
postgresClient: "postgres:14-alpine"
|
||||||
# Используется только при app.tracing.enabled
|
# Только при app.tracing.enabled
|
||||||
otelCollector: "otel/opentelemetry-collector:0.109.0"
|
otelCollector: "otel/opentelemetry-collector:0.109.0"
|
||||||
|
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
# Секреты доступа к приватному Docker-реестру.
|
# Secret с доступом к реестру образов. Создаётся отдельно, см. README, шаг 1.
|
||||||
# Создаются отдельно, см. README, шаг 1.
|
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
- name: regsecret
|
- name: regsecret
|
||||||
|
|
||||||
# ============================================================================
|
# --- Приложение -----------------------------------------------------------
|
||||||
# Приложение
|
|
||||||
# ============================================================================
|
|
||||||
app:
|
app:
|
||||||
# Основной домен инсталляции. Должен совпадать с ingress.host.
|
# Домен установки. Должен совпадать с ingress.host.
|
||||||
defaultTenantHostname: "hrbox.example.com"
|
defaultTenantHostname: "hrbox.example.com"
|
||||||
|
|
||||||
# Имя инстанса — попадает в логи и метрики, помогает различать установки.
|
# Имя установки, видно в логах и метриках
|
||||||
instanceName: "onprem"
|
instanceName: "onprem"
|
||||||
|
|
||||||
# Режим одного арендатора. "1" — вся установка обслуживает одну компанию.
|
# "1" — установка обслуживает одну компанию
|
||||||
singleTenant: "0"
|
singleTenant: "0"
|
||||||
|
|
||||||
# Frontend 2: "true" — включён (по умолчанию), "false" — старый интерфейс.
|
# "true" — новый интерфейс, "false" — старый
|
||||||
front2: "true"
|
front2: "true"
|
||||||
|
|
||||||
# Отдельный домен авторизации. Для on-premise почти всегда пусто.
|
# Отдельный домен авторизации. Для on-premise обычно пусто.
|
||||||
authHost: ""
|
authHost: ""
|
||||||
|
|
||||||
# "0" — production, "1" — отладка. В production всегда "0".
|
# "0" — production, "1" — отладка
|
||||||
debug: "0"
|
debug: "0"
|
||||||
|
|
||||||
# Принудительный https во всех сгенерированных ссылках.
|
# Подставлять https во всех ссылках, которые генерирует приложение
|
||||||
forceHttps: "true"
|
forceHttps: "true"
|
||||||
|
|
||||||
# Количество реплик.
|
# Число подов каждого сервиса.
|
||||||
# web 2-10, по числу пользователей
|
# web — по числу пользователей, worker — по объёму фоновых задач,
|
||||||
# worker 2-5, фоновые задачи
|
# chatbox — по числу открытых вкладок, остальным обычно хватает 1-2.
|
||||||
# chatbox 2-6, real-time
|
|
||||||
# остальные обычно хватает 1-2
|
|
||||||
replicas:
|
replicas:
|
||||||
web: 2
|
web: 2
|
||||||
worker: 2
|
worker: 2
|
||||||
@@ -111,43 +93,41 @@ app:
|
|||||||
fileProcessor: 1
|
fileProcessor: 1
|
||||||
fileProcessorVideo: 1
|
fileProcessorVideo: 1
|
||||||
|
|
||||||
# Своя политика конфиденциальности и правила использования.
|
# Свои ссылки на политику конфиденциальности и правила использования.
|
||||||
# При enabled: false приложение показывает ссылки HRBox.
|
# false — показываются ссылки HRBox.
|
||||||
customPolicy:
|
customPolicy:
|
||||||
enabled: false
|
enabled: false
|
||||||
# privacyUrl: "https://example.com/privacy"
|
# privacyUrl: "https://example.com/privacy"
|
||||||
# termsUrl: "https://example.com/terms"
|
# termsUrl: "https://example.com/terms"
|
||||||
|
|
||||||
# --- PostgreSQL -----------------------------------------------------------
|
# --- PostgreSQL ---------------------------------------------------------
|
||||||
# Требуется PostgreSQL 14+. Для отказоустойчивости настройте репликацию.
|
# Нужен PostgreSQL 14 или новее. Чарт базу не разворачивает.
|
||||||
postgres:
|
postgres:
|
||||||
host: "postgresql"
|
host: "postgresql"
|
||||||
port: "5432"
|
port: "5432"
|
||||||
database: "hrbox"
|
database: "hrbox"
|
||||||
user: "hrbox"
|
user: "hrbox"
|
||||||
# Пароль попадает в Secret чарта, а не в env-блок Deployment.
|
# Попадает в Secret, в спеке подов пароля нет
|
||||||
password: ""
|
password: ""
|
||||||
# "true", если база работает на расширении Citus (шардирование).
|
# "true", если база на Citus (шардирование)
|
||||||
citus: "false"
|
citus: "false"
|
||||||
|
|
||||||
# --- Redis / Dragonfly ----------------------------------------------------
|
# --- Redis / Dragonfly --------------------------------------------------
|
||||||
# Хранит сессии, кеш и очереди плеера курсов. Потеря данных не критична,
|
# Сессии, кеш и очереди плеера курсов.
|
||||||
# но разлогинивает пользователей и сбрасывает незавершённые события плеера.
|
# Пусто — используется Dragonfly из этого же релиза.
|
||||||
#
|
# Адрес указывают, если Redis внешний (тогда обычно dragonfly.enabled: false).
|
||||||
# Пусто — используется Dragonfly из этого же релиза. Заполняйте, только
|
|
||||||
# если Redis внешний (тогда обычно dragonfly.enabled: false).
|
|
||||||
redis:
|
redis:
|
||||||
host: ""
|
host: ""
|
||||||
port: "6379"
|
port: "6379"
|
||||||
|
|
||||||
# --- NATS JetStream -------------------------------------------------------
|
# --- NATS ---------------------------------------------------------------
|
||||||
# Пусто — NATS из этого же релиза.
|
# Пусто — используется NATS из этого же релиза.
|
||||||
# Внешний кластер: nats://node1:4222,nats://node2:4222,nats://node3:4222
|
# Внешний кластер: nats://node1:4222,nats://node2:4222,nats://node3:4222
|
||||||
nats:
|
nats:
|
||||||
url: ""
|
url: ""
|
||||||
|
|
||||||
# --- S3 -------------------------------------------------------------------
|
# --- S3 -----------------------------------------------------------------
|
||||||
# Подходят AWS S3, MinIO, Yandex Object Storage, VK Cloud Storage.
|
# Подойдёт AWS S3, MinIO, Yandex Object Storage, VK Cloud Storage.
|
||||||
s3:
|
s3:
|
||||||
# MinIO: http://minio:9000
|
# MinIO: http://minio:9000
|
||||||
# Yandex: https://storage.yandexcloud.net
|
# Yandex: https://storage.yandexcloud.net
|
||||||
@@ -158,12 +138,12 @@ app:
|
|||||||
secret: ""
|
secret: ""
|
||||||
region: "us-east-1"
|
region: "us-east-1"
|
||||||
version: "latest"
|
version: "latest"
|
||||||
# "true" для MinIO и self-hosted S3, "false" для AWS S3
|
# "true" для MinIO и своего S3, "false" для AWS S3
|
||||||
pathStyle: "true"
|
pathStyle: "true"
|
||||||
multipart: "true"
|
multipart: "true"
|
||||||
prefix: ""
|
prefix: ""
|
||||||
|
|
||||||
# --- Почта ----------------------------------------------------------------
|
# --- Почта --------------------------------------------------------------
|
||||||
smtp:
|
smtp:
|
||||||
host: "smtp.example.com"
|
host: "smtp.example.com"
|
||||||
# 25 — без шифрования, 587 — STARTTLS, 465 — SSL/TLS
|
# 25 — без шифрования, 587 — STARTTLS, 465 — SSL/TLS
|
||||||
@@ -177,33 +157,33 @@ app:
|
|||||||
sslAllowSelfSigned: "true"
|
sslAllowSelfSigned: "true"
|
||||||
sslVerifyPeer: "false"
|
sslVerifyPeer: "false"
|
||||||
|
|
||||||
# --- Мониторинг ошибок ----------------------------------------------------
|
# --- Sentry -------------------------------------------------------------
|
||||||
sentry:
|
sentry:
|
||||||
dsn: ""
|
dsn: ""
|
||||||
environment: "production"
|
environment: "production"
|
||||||
# Отдельные DSN для подсистем. Пусто — используется общий dsn.
|
# Пусто — используется общий dsn
|
||||||
launchpadDsn: ""
|
launchpadDsn: ""
|
||||||
conductorDsn: ""
|
conductorDsn: ""
|
||||||
# У этих двух общего fallback нет: пусто означает «не отправлять».
|
# Здесь пусто означает «не отправлять»
|
||||||
goworkerDsn: ""
|
goworkerDsn: ""
|
||||||
chatboxDsn: ""
|
chatboxDsn: ""
|
||||||
|
|
||||||
# --- Внутренние сервисы ---------------------------------------------------
|
# --- Внутренние сервисы -------------------------------------------------
|
||||||
# Пустой url означает сервис из этого же релиза: адрес собирается из имени,
|
# Пустой url — сервис берётся из этого же релиза.
|
||||||
# которое создаёт чарт. Заполняйте, только если вынесли сервис наружу.
|
# Заполняют, если сервис вынесен наружу.
|
||||||
geonames:
|
geonames:
|
||||||
url: ""
|
url: ""
|
||||||
|
|
||||||
goworker:
|
goworker:
|
||||||
url: ""
|
url: ""
|
||||||
# Минимальный интервал между push-уведомлениями одному пользователю
|
# Не чаще одного push одному пользователю за этот интервал
|
||||||
pushMinInterval: "5m"
|
pushMinInterval: "5m"
|
||||||
|
|
||||||
kedoca:
|
kedoca:
|
||||||
url: ""
|
url: ""
|
||||||
# Пароль корневого сертификата, который сервис создаёт при первом запуске
|
# Пароль корневого сертификата, который сервис создаёт при первом запуске
|
||||||
rootCaPass: "hrbox"
|
rootCaPass: "hrbox"
|
||||||
# "gost" (ГОСТ, КриптоПро) или "openssl"
|
# "gost" (КриптоПро) или "openssl"
|
||||||
engine: "gost"
|
engine: "gost"
|
||||||
# "gost2012_256" для ГОСТ, "rsa" для OpenSSL
|
# "gost2012_256" для ГОСТ, "rsa" для OpenSSL
|
||||||
algorithm: "gost2012_256"
|
algorithm: "gost2012_256"
|
||||||
@@ -211,81 +191,79 @@ app:
|
|||||||
pkeyopt: "paramset:A"
|
pkeyopt: "paramset:A"
|
||||||
# Служба меток времени
|
# Служба меток времени
|
||||||
tspUrl: "http://qs.cryptopro.ru/tsp/tsp.srf"
|
tspUrl: "http://qs.cryptopro.ru/tsp/tsp.srf"
|
||||||
# Kubernetes Secret с сертификатами УЦ. Если задан — монтируется в /ca-cert.
|
# Secret с сертификатами УЦ. Если задан, монтируется в /ca-cert.
|
||||||
secretName: ""
|
secretName: ""
|
||||||
|
|
||||||
fileProcessor:
|
fileProcessor:
|
||||||
# Сколько документов конвертировать одновременно в одном поде
|
# Сколько документов конвертировать одновременно в одном поде
|
||||||
docconvMaxParallelTasks: "1"
|
docconvMaxParallelTasks: "1"
|
||||||
# Сколько изображений ресайзить одновременно (пул конвертации видео)
|
# Сколько изображений обрабатывать одновременно в поде конвертации видео
|
||||||
imageResizeMaxParallel: "20"
|
imageResizeMaxParallel: "20"
|
||||||
|
|
||||||
# --- Конвертация видео ----------------------------------------------------
|
# --- Конвертация видео --------------------------------------------------
|
||||||
# Отдельный пул подов: конвертация видео требует много CPU и диска и
|
# Отдельные поды: видео требует много CPU и диска, поэтому его выносят
|
||||||
# выносится на выделенные ноды, чтобы не мешать остальным задачам.
|
# на выделенные ноды.
|
||||||
videoConverter:
|
videoConverter:
|
||||||
enabled: false
|
enabled: false
|
||||||
# Внутренний адрес HRBox, по которому конвертер забирает и отдаёт файлы.
|
# Внутренний адрес HRBox, откуда конвертер берёт и куда отдаёт файлы.
|
||||||
# Пусто — берётся http://<релиз>-web.
|
# Пусто — http://<релиз>-web.
|
||||||
internalUrl: ""
|
internalUrl: ""
|
||||||
# Куда планировать поды конвертера. Пусто — без ограничений.
|
# На каких нодах запускать. Пусто — на любых.
|
||||||
|
# Пример: role: converter-dedicated
|
||||||
nodeSelector: {}
|
nodeSelector: {}
|
||||||
# role: converter-dedicated
|
# Пример:
|
||||||
tolerations: []
|
|
||||||
# - key: dedicated
|
# - key: dedicated
|
||||||
# operator: Equal
|
# operator: Equal
|
||||||
# value: video-converter
|
# value: video-converter
|
||||||
# effect: NoSchedule
|
# effect: NoSchedule
|
||||||
|
tolerations: []
|
||||||
|
|
||||||
# --- Чат ------------------------------------------------------------------
|
# --- Чат ----------------------------------------------------------------
|
||||||
chatbox:
|
chatbox:
|
||||||
# Часть ключа асимметричного шифрования чатов, 32 символа.
|
# Часть ключа шифрования чатов, 32 символа.
|
||||||
# Генерация: openssl rand -hex 16
|
# Генерация: openssl rand -hex 16
|
||||||
wrappingKey: ""
|
wrappingKey: ""
|
||||||
|
|
||||||
# --- Видеозвонки ----------------------------------------------------------
|
# --- Видеозвонки --------------------------------------------------------
|
||||||
livekit:
|
livekit:
|
||||||
url: ""
|
url: ""
|
||||||
apiKey: ""
|
apiKey: ""
|
||||||
apiSecret: ""
|
apiSecret: ""
|
||||||
|
|
||||||
# --- Nanabush Player ------------------------------------------------------
|
# --- Nanabush Player ----------------------------------------------------
|
||||||
# Плеер учебных материалов: SCORM 1.2/2004, cmi5, xAPI, нативные курсы,
|
# Плеер учебных материалов: SCORM 1.2 и 2004, cmi5, xAPI, нативные курсы,
|
||||||
# тесты и эссе. Полное описание контракта — docs/nanabush-player-deployment.md
|
# тесты и эссе.
|
||||||
# в репозитории HRBox.
|
|
||||||
#
|
#
|
||||||
# В облаке плеер живёт на отдельном поддомене. В on-premise выделенного
|
# В облаке плеер стоит на отдельном поддомене, в on-premise поддомена нет,
|
||||||
# поддомена нет, поэтому плеер монтируется на основной домен под путём
|
# поэтому он живёт на основном домене по пути basePath. Домен общий, значит
|
||||||
# basePath. Практическое следствие: cookie HRBox видны содержимому курсов
|
# cookie HRBox доступны содержимому курсов. Если нужна изоляция сторонних
|
||||||
# (один origin). Если для сторонних SCORM-пакетов нужна изоляция — заводите
|
# SCORM-пакетов, обратитесь в HRBox за схемой с отдельным поддоменом.
|
||||||
# отдельный поддомен и обращайтесь в HRBox за облачной схемой.
|
|
||||||
nanabushPlayer:
|
nanabushPlayer:
|
||||||
# Отдавать ли учебные материалы через плеер. false — старый проигрыватель.
|
# false — материалы открываются старым проигрывателем
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
||||||
# Путь монтирования на основном домене. Пустой и "/" запрещены: корень
|
# Путь на основном домене. Корень "/" занят самим HRBox.
|
||||||
# занят самим HRBox.
|
|
||||||
basePath: "/nanabush-player"
|
basePath: "/nanabush-player"
|
||||||
|
|
||||||
# Issuer launch-тикета. Пусто — https://<ingress.host>/lms/player.
|
# Issuer launch-тикета. Пусто — https://<ingress.host>/lms/player
|
||||||
issuer: ""
|
issuer: ""
|
||||||
|
|
||||||
contractVersion: "v0-current"
|
contractVersion: "v0-current"
|
||||||
|
|
||||||
# Ключи плеера. Оба обязательны и должны отличаться друг от друга.
|
# Оба ключа обязательны и должны быть разными.
|
||||||
# Генерация каждого: openssl rand -base64 48
|
# Генерация каждого: openssl rand -base64 48
|
||||||
keys:
|
keys:
|
||||||
ticketHs256: ""
|
ticketHs256: ""
|
||||||
sessionHs256: ""
|
sessionHs256: ""
|
||||||
# Необязательное кольцо ключей для ротации без простоя:
|
# Набор ключей для ротации без простоя, необязательный:
|
||||||
# "kid1:секрет1,kid2:секрет2", текущий ключ подписи — первым.
|
# "kid1:секрет1,kid2:секрет2". Первым идёт ключ, которым подписывают
|
||||||
# Секрет не должен содержать запятую (используйте base64url).
|
# сейчас. Запятая внутри секрета недопустима, используйте base64url.
|
||||||
ticketKeys: ""
|
ticketKeys: ""
|
||||||
|
|
||||||
# Доля запусков, уходящих в новый плеер. 100 — все.
|
|
||||||
rollout:
|
rollout:
|
||||||
|
# Какая доля запусков идёт в новый плеер. 100 — все.
|
||||||
percent: 100
|
percent: 100
|
||||||
# Разрешить откат на старый проигрыватель, если плеер недоступен
|
# Открывать материал старым проигрывателем, если плеер не ответил
|
||||||
legacyFallback: true
|
legacyFallback: true
|
||||||
allowedContentTypes:
|
allowedContentTypes:
|
||||||
- document
|
- document
|
||||||
@@ -299,7 +277,7 @@ app:
|
|||||||
- native
|
- native
|
||||||
- native_quiz
|
- native_quiz
|
||||||
- native_essay
|
- native_essay
|
||||||
# "*" — все арендаторы, включая будущих
|
# "*" — все компании, включая новые
|
||||||
allowedTenants:
|
allowedTenants:
|
||||||
- "*"
|
- "*"
|
||||||
|
|
||||||
@@ -308,26 +286,25 @@ app:
|
|||||||
name: ""
|
name: ""
|
||||||
port: 8094
|
port: 8094
|
||||||
|
|
||||||
# Публиковать ли путь плеера на основном Ingress.
|
# Публиковать ли путь плеера на общем Ingress.
|
||||||
# Выключать имеет смысл только при аварийном откате.
|
# Выключают только при откате.
|
||||||
ingress:
|
ingress:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
||||||
deployment:
|
deployment:
|
||||||
# Создавать ли Deployment и Service плеера.
|
# Создавать ли Deployment и Service плеера
|
||||||
enabled: true
|
enabled: true
|
||||||
replicas: 1
|
replicas: 1
|
||||||
terminationGracePeriodSeconds: 120
|
terminationGracePeriodSeconds: 120
|
||||||
|
|
||||||
# Образ плеера должен уметь работать под путём (а не только в корне
|
# Умеет ли образ плеера работать не в корне домена, а по пути.
|
||||||
# домена). Если ставите старый образ без этой поддержки — переключите
|
# Со старым образом без такой поддержки поставьте false — чарт
|
||||||
# в false, и чарт остановит рендер с объяснением вместо неработающего
|
# остановит установку вместо того, чтобы развернуть нерабочий плеер.
|
||||||
# плеера в кластере.
|
|
||||||
binaryCapabilities:
|
binaryCapabilities:
|
||||||
basePath: true
|
basePath: true
|
||||||
|
|
||||||
# Secret с ключами плеера. create: false — Secret создаётся вне чарта
|
# Secret с ключами плеера.
|
||||||
# (например, внешним vault-оператором), чарт только ссылается на него.
|
# create: false — Secret заводят вне чарта, чарт только ссылается.
|
||||||
existingSecret:
|
existingSecret:
|
||||||
create: true
|
create: true
|
||||||
name: "hrbox-nanabush-player"
|
name: "hrbox-nanabush-player"
|
||||||
@@ -338,48 +315,46 @@ app:
|
|||||||
ticketKeys: ""
|
ticketKeys: ""
|
||||||
|
|
||||||
ticket:
|
ticket:
|
||||||
# Время жизни launch-тикета, секунды
|
# Сколько живёт launch-тикет, секунды
|
||||||
ttlSeconds: 300
|
ttlSeconds: 300
|
||||||
# Время жизни учётных данных обратного канала: сессия плеера + 2 минуты
|
# Сколько живут учётные данные обратного канала: сессия плеера плюс
|
||||||
# на расхождение часов
|
# 2 минуты на расхождение часов
|
||||||
credentialTtlSeconds: 28920
|
credentialTtlSeconds: 28920
|
||||||
maxLifetime: "5m"
|
maxLifetime: "5m"
|
||||||
sessionTtl: "8h"
|
sessionTtl: "8h"
|
||||||
# Только на время первой раскатки кольца ключей: до какого момента
|
# Нужно только при первом переходе на набор ключей: до какого момента
|
||||||
# (RFC3339) принимать тикеты без kid. Пусто — не принимать.
|
# (RFC3339) принимать тикеты без kid. Пусто — не принимать.
|
||||||
keylessAcceptedUntil: ""
|
keylessAcceptedUntil: ""
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
# false — URL собирается из app.redis.
|
# false — адрес собирается из app.redis.
|
||||||
# true — полный redis:// или rediss:// URL читается из внешнего
|
# true — полный redis:// или rediss:// URL берётся из внешнего Secret
|
||||||
# Secret (нужно для ACL, пароля или TLS) и требует
|
# (нужно для пароля, ACL или TLS), требует existingSecret.create: false
|
||||||
# existingSecret.create: false.
|
|
||||||
urlFromExistingSecret: false
|
urlFromExistingSecret: false
|
||||||
database: 0
|
database: 0
|
||||||
# Итоговый префикс: hrbox:<namespace>:<suffix> — разводит несколько
|
# Полный префикс: hrbox:<namespace>:<суффикс>.
|
||||||
# релизов HRBox на одном Dragonfly.
|
# Разделяет несколько установок HRBox на одном Redis.
|
||||||
keyPrefixSuffix: "nanabush-player"
|
keyPrefixSuffix: "nanabush-player"
|
||||||
|
|
||||||
|
# Обращения плеера обратно в HRBox: за пакетом курса и с отчётами
|
||||||
backchannel:
|
backchannel:
|
||||||
# Внутрикластерный адрес HRBox. Пусто — <релиз>-web.
|
# Внутренний адрес HRBox. Пусто — <релиз>-web.
|
||||||
host: ""
|
host: ""
|
||||||
schemes: "http"
|
schemes: "http"
|
||||||
allowPrivateIps: true
|
allowPrivateIps: true
|
||||||
packageFetchMaxBytes: "5242880"
|
packageFetchMaxBytes: "5242880"
|
||||||
# Транспорт должен вмещать самый большой поддерживаемый медиафайл
|
# Должно вмещать самый большой медиафайл курса
|
||||||
packageContentMaxBytes: "2147483648"
|
packageContentMaxBytes: "2147483648"
|
||||||
scormPackageMaxBytes: "1073741824"
|
scormPackageMaxBytes: "1073741824"
|
||||||
# Пусто — ограничение по числу файлов в SCORM-пакете берётся из
|
# Пусто — берётся значение приложения (4000 файлов)
|
||||||
# умолчаний приложения (4000)
|
|
||||||
scormPackageMaxFiles: ""
|
scormPackageMaxFiles: ""
|
||||||
packageFetchTimeout: "15s"
|
packageFetchTimeout: "15s"
|
||||||
# Таймаут покрывает всю передачу, включая отдачу байтов браузеру
|
# Считается до конца передачи файла в браузер учащегося, поэтому
|
||||||
# учащегося, поэтому упирается в скорость его канала. Двух минут
|
# зависит от скорости его интернета
|
||||||
# не хватало на крупное видео.
|
|
||||||
packageStreamTimeout: "20m"
|
packageStreamTimeout: "20m"
|
||||||
reportTimeout: "30s"
|
reportTimeout: "30s"
|
||||||
|
|
||||||
# Очередь отправки учебных событий в HRBox.
|
# Очередь отправки учебных событий в HRBox
|
||||||
forwarder:
|
forwarder:
|
||||||
queueSize: "1000"
|
queueSize: "1000"
|
||||||
workers: "4"
|
workers: "4"
|
||||||
@@ -398,8 +373,7 @@ app:
|
|||||||
level: info
|
level: info
|
||||||
format: json
|
format: json
|
||||||
|
|
||||||
# Метрики отдаются на отдельном порту, который не публикуется наружу:
|
# Метрики отдаются на отдельном порту и наружу не публикуются
|
||||||
# содержимое курсов не должно читать эксплуатационные метрики.
|
|
||||||
metrics:
|
metrics:
|
||||||
enabled: true
|
enabled: true
|
||||||
port: 9090
|
port: 9090
|
||||||
@@ -418,22 +392,22 @@ app:
|
|||||||
timeoutSeconds: 2
|
timeoutSeconds: 2
|
||||||
failureThreshold: 3
|
failureThreshold: 3
|
||||||
|
|
||||||
# --- Фоновые задачи -------------------------------------------------------
|
# --- Фоновые задачи -----------------------------------------------------
|
||||||
# Формат: "топик:количество-воркеров"
|
# Формат: "очередь:сколько воркеров"
|
||||||
launchpad:
|
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"
|
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:
|
sms:
|
||||||
senderName: "HRBOX"
|
senderName: "HRBOX"
|
||||||
|
|
||||||
# --- Внешние интеграции ---------------------------------------------------
|
# --- Внешние интеграции -------------------------------------------------
|
||||||
integrations:
|
integrations:
|
||||||
telegram:
|
telegram:
|
||||||
# Прямой API Telegram; для установок без доступа к нему укажите прокси
|
# Если прямого доступа к Telegram нет, укажите адрес прокси
|
||||||
apiUrl: "https://api.telegram.org/bot"
|
apiUrl: "https://api.telegram.org/bot"
|
||||||
google:
|
google:
|
||||||
enabled: "false"
|
enabled: "false"
|
||||||
# Client ID публичный (уходит в браузер), secret — в Secret чарта
|
# clientId уходит в браузер, clientSecret попадает в Secret
|
||||||
clientId: "692956564858-ccapt35khk7tmadl17b3879ht2cropp6.apps.googleusercontent.com"
|
clientId: "692956564858-ccapt35khk7tmadl17b3879ht2cropp6.apps.googleusercontent.com"
|
||||||
clientSecret: ""
|
clientSecret: ""
|
||||||
glagol:
|
glagol:
|
||||||
@@ -441,8 +415,8 @@ app:
|
|||||||
apiUrl: "https://api.glagol.online/glagol-api"
|
apiUrl: "https://api.glagol.online/glagol-api"
|
||||||
|
|
||||||
# Привязка мобильных приложений к домену: без неё ссылки из писем и пушей
|
# Привязка мобильных приложений к домену: без неё ссылки из писем и пушей
|
||||||
# открываются в браузере вместо приложения. По умолчанию — штатные
|
# открываются в браузере, а не в приложении. По умолчанию указаны
|
||||||
# приложения HRBox; меняйте, только если у вас собственная сборка.
|
# приложения HRBox, меняйте только для своей сборки.
|
||||||
mobileApps:
|
mobileApps:
|
||||||
android:
|
android:
|
||||||
- packageName: "io.hrbox.hrboxapp"
|
- packageName: "io.hrbox.hrboxapp"
|
||||||
@@ -461,13 +435,13 @@ app:
|
|||||||
clientSecret: ""
|
clientSecret: ""
|
||||||
verificationToken: ""
|
verificationToken: ""
|
||||||
|
|
||||||
# --- HRBox Hub ------------------------------------------------------------
|
# --- HRBox Hub ----------------------------------------------------------
|
||||||
# Лицензирование и общие сервисы. Токен выдают сотрудники HRBox.
|
# Лицензирование и общие сервисы. Токен выдают сотрудники HRBox.
|
||||||
hub:
|
hub:
|
||||||
url: "https://hub.hrbox.io"
|
url: "https://hub.hrbox.io"
|
||||||
token: ""
|
token: ""
|
||||||
|
|
||||||
# --- AI -------------------------------------------------------------------
|
# --- AI -----------------------------------------------------------------
|
||||||
ai:
|
ai:
|
||||||
docsIndexEnabled: "true"
|
docsIndexEnabled: "true"
|
||||||
semanticIndexEnabled: "true"
|
semanticIndexEnabled: "true"
|
||||||
@@ -476,82 +450,74 @@ app:
|
|||||||
folderId: ""
|
folderId: ""
|
||||||
apiKey: ""
|
apiKey: ""
|
||||||
|
|
||||||
# --- Трассировка ----------------------------------------------------------
|
# --- Трассировка --------------------------------------------------------
|
||||||
# Включает OpenTelemetry в PHP и sidecar-коллектор в поде web.
|
# Включает OpenTelemetry в PHP и коллектор рядом с подом web
|
||||||
tracing:
|
tracing:
|
||||||
enabled: false
|
enabled: false
|
||||||
exporterUrl: "http://localhost:4318"
|
exporterUrl: "http://localhost:4318"
|
||||||
# Куда коллектор пересылает трейсы (Tempo, Jaeger)
|
# Куда коллектор отправляет трейсы: Tempo, Jaeger
|
||||||
tempoUrl: ""
|
tempoUrl: ""
|
||||||
|
|
||||||
# --- Безопасность ---------------------------------------------------------
|
# --- Безопасность -------------------------------------------------------
|
||||||
security:
|
security:
|
||||||
# "true" разрешает встроенному iframe полный доступ к родительскому окну.
|
# "true" даёт встроенному iframe полный доступ к родительскому окну.
|
||||||
# Для production рекомендуется "false".
|
# Для production лучше "false".
|
||||||
iframeFullAccess: "false"
|
iframeFullAccess: "false"
|
||||||
|
|
||||||
# ============================================================================
|
# --- Секреты --------------------------------------------------------------
|
||||||
# Секреты приложения
|
|
||||||
# ============================================================================
|
|
||||||
# Эти значения вместе с паролями из app.* складываются в один Kubernetes
|
# Эти значения вместе с паролями из app.* складываются в один Kubernetes
|
||||||
# Secret, а контейнеры читают его через secretKeyRef.
|
# Secret, поды читают их оттуда.
|
||||||
secrets:
|
secrets:
|
||||||
# Имя Secret, созданного вне чарта. Если задано — чарт свой Secret не
|
# Имя Secret, созданного вне чарта. Если задано, чарт свой Secret не
|
||||||
# создаёт и берёт все ключи из указанного. Список ключей — в README.
|
# создаёт и берёт ключи из указанного. Список ключей — в README.
|
||||||
existingSecret: ""
|
existingSecret: ""
|
||||||
|
|
||||||
# Защита cookie от подделки, 32 символа.
|
# Защита cookie от подделки, 32 символа.
|
||||||
# Генерация: openssl rand -hex 16
|
# Генерация: openssl rand -hex 16
|
||||||
cookieValidationKey: ""
|
cookieValidationKey: ""
|
||||||
|
|
||||||
# Шифрование данных: пароли интеграций (S3, ADFS и другие).
|
# Шифрование паролей интеграций в базе.
|
||||||
# ВАЖНО: без этого ключа данные не расшифровать. Не теряйте его.
|
# Без этого ключа данные не расшифровать, храните копию отдельно.
|
||||||
# Генерация: openssl rand -base64 48
|
# Генерация: openssl rand -base64 48
|
||||||
encryptionKey: ""
|
encryptionKey: ""
|
||||||
|
|
||||||
# Аутентификация вызовов между микросервисами релиза.
|
# Проверка вызовов между сервисами внутри релиза.
|
||||||
# Генерация: openssl rand -base64 48
|
# Генерация: openssl rand -base64 48
|
||||||
servicesInternalSecret: ""
|
servicesInternalSecret: ""
|
||||||
|
|
||||||
# ============================================================================
|
# --- Ingress --------------------------------------------------------------
|
||||||
# Ingress
|
|
||||||
# ============================================================================
|
|
||||||
ingress:
|
ingress:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
||||||
# Обычно "nginx" или "traefik"
|
# Обычно "nginx" или "traefik"
|
||||||
className: "nginx"
|
className: "nginx"
|
||||||
|
|
||||||
# Домен инсталляции. Wildcard (*.hrbox.company.com) — для мультиарендности.
|
# Домен установки. Для мультиарендности можно wildcard: *.hrbox.company.com
|
||||||
host: "hrbox.example.com"
|
host: "hrbox.example.com"
|
||||||
|
|
||||||
# Дополнительные аннотации ingress-контроллера
|
# Дополнительные аннотации ingress-контроллера
|
||||||
annotations: {}
|
annotations: {}
|
||||||
|
|
||||||
# Максимальный размер загружаемого файла на общих путях.
|
# Максимальный размер загружаемого файла.
|
||||||
# Загрузка оргструктуры из 1С идёт потоком и имеет собственный лимит.
|
# У загрузки оргструктуры из 1С отдельный лимит, он выше.
|
||||||
maxBodySize: "10m"
|
maxBodySize: "10m"
|
||||||
|
|
||||||
tls:
|
tls:
|
||||||
enabled: true
|
enabled: true
|
||||||
# kubectl create secret tls hrbox-tls --cert=cert.pem --key=key.pem
|
# kubectl create secret tls hrbox-tls --cert=cert.pem --key=key.pem
|
||||||
# либо выпуск через cert-manager
|
# или выпустить сертификат через cert-manager
|
||||||
secretName: "hrbox-tls"
|
secretName: "hrbox-tls"
|
||||||
|
|
||||||
# ============================================================================
|
# --- Кластер --------------------------------------------------------------
|
||||||
# Кластер
|
|
||||||
# ============================================================================
|
|
||||||
cluster:
|
cluster:
|
||||||
# Домен служебных имён Kubernetes. Меняйте, только если он нестандартный.
|
# Домен служебных имён Kubernetes. Менять только если он нестандартный.
|
||||||
domain: "cluster.local"
|
domain: "cluster.local"
|
||||||
|
|
||||||
# ============================================================================
|
# --- Ресурсы --------------------------------------------------------------
|
||||||
# Ресурсы
|
# Значения близки к тем, что используются в облаке HRBox.
|
||||||
# ============================================================================
|
# Можно оставить только requests: незаполненные поля в манифест не попадают.
|
||||||
# Значения близки к продовым. Незаданные поля не рендерятся, поэтому
|
|
||||||
# компоненту можно оставить только requests.
|
|
||||||
resources:
|
resources:
|
||||||
# PHP-FPM: HTTP-запросы, API, веб-интерфейс
|
# PHP-FPM: веб-интерфейс и API
|
||||||
app:
|
app:
|
||||||
requests:
|
requests:
|
||||||
cpu: "1"
|
cpu: "1"
|
||||||
@@ -562,7 +528,7 @@ resources:
|
|||||||
memory: "2Gi"
|
memory: "2Gi"
|
||||||
ephemeralStorage: "2Gi"
|
ephemeralStorage: "2Gi"
|
||||||
|
|
||||||
# nginx в поде web: проксирует запросы в PHP-FPM
|
# nginx в поде web
|
||||||
nginx:
|
nginx:
|
||||||
requests:
|
requests:
|
||||||
cpu: "0.1"
|
cpu: "0.1"
|
||||||
@@ -573,7 +539,7 @@ resources:
|
|||||||
memory: "256Mi"
|
memory: "256Mi"
|
||||||
ephemeralStorage: "512Mi"
|
ephemeralStorage: "512Mi"
|
||||||
|
|
||||||
# Фоновые задачи: конвертация файлов, почта, отчёты
|
# Фоновые задачи: файлы, почта, отчёты
|
||||||
worker:
|
worker:
|
||||||
requests:
|
requests:
|
||||||
cpu: "0.6"
|
cpu: "0.6"
|
||||||
@@ -645,7 +611,7 @@ resources:
|
|||||||
memory: "1Gi"
|
memory: "1Gi"
|
||||||
ephemeralStorage: "2Gi"
|
ephemeralStorage: "2Gi"
|
||||||
|
|
||||||
# Конвертация видео: тяжёлый профиль, отдельные ноды
|
# Конвертация видео: тяжёлые поды на отдельных нодах
|
||||||
fileProcessorVideo:
|
fileProcessorVideo:
|
||||||
requests:
|
requests:
|
||||||
cpu: "4"
|
cpu: "4"
|
||||||
@@ -679,7 +645,7 @@ resources:
|
|||||||
cpu: "1"
|
cpu: "1"
|
||||||
memory: "2Gi"
|
memory: "2Gi"
|
||||||
|
|
||||||
# Разовые задачи: миграции, обновление кластера
|
# Разовые задачи: миграции и обновление кластера
|
||||||
jobs:
|
jobs:
|
||||||
requests:
|
requests:
|
||||||
cpu: "0.5"
|
cpu: "0.5"
|
||||||
@@ -690,31 +656,29 @@ resources:
|
|||||||
memory: "4Gi"
|
memory: "4Gi"
|
||||||
ephemeralStorage: "256Mi"
|
ephemeralStorage: "256Mi"
|
||||||
|
|
||||||
# ============================================================================
|
# --- NATS -----------------------------------------------------------------
|
||||||
# NATS JetStream
|
|
||||||
# ============================================================================
|
|
||||||
nats:
|
nats:
|
||||||
# Обязателен для работы HRBox. Выключайте только если ставите NATS отдельно
|
# HRBox без брокера не работает. Выключают, только если NATS ставят
|
||||||
# и указали его адрес в app.nats.url.
|
# отдельно и указали его адрес в app.nats.url.
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
||||||
# Для отказоустойчивости — 3 или 5. Должно совпадать с cluster.replicas.
|
# Для отказоустойчивости 3 или 5. Должно совпадать с cluster.replicas.
|
||||||
replicas: 3
|
replicas: 3
|
||||||
|
|
||||||
jetstream:
|
jetstream:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
||||||
# Хранение в памяти — для небольших установок
|
# Хранение в памяти: подходит небольшим установкам
|
||||||
memStorage:
|
memStorage:
|
||||||
enabled: true
|
enabled: true
|
||||||
size: "2Gi"
|
size: "2Gi"
|
||||||
|
|
||||||
# Хранение на диске — для production
|
# Хранение на диске: для production
|
||||||
fileStorage:
|
fileStorage:
|
||||||
enabled: false
|
enabled: false
|
||||||
size: "4Gi"
|
size: "4Gi"
|
||||||
storageDirectory: "/data"
|
storageDirectory: "/data"
|
||||||
# Для JetStream нужен быстрый диск
|
# JetStream нужен быстрый диск
|
||||||
storageClassName: "fast-ssd"
|
storageClassName: "fast-ssd"
|
||||||
|
|
||||||
cluster:
|
cluster:
|
||||||
@@ -722,17 +686,16 @@ nats:
|
|||||||
# Должно совпадать с nats.replicas
|
# Должно совпадать с nats.replicas
|
||||||
replicas: 3
|
replicas: 3
|
||||||
|
|
||||||
# Автоматическая перезагрузка конфигурации без рестарта сервера
|
# Подхватывает изменения конфигурации без перезапуска NATS
|
||||||
reloader:
|
reloader:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
||||||
terminationGracePeriodSeconds: 120
|
terminationGracePeriodSeconds: 120
|
||||||
|
|
||||||
# ============================================================================
|
# --- Dragonfly ------------------------------------------------------------
|
||||||
# Dragonfly (Redis-совместимый кеш)
|
# Redis-совместимый кеш.
|
||||||
# ============================================================================
|
|
||||||
dragonfly:
|
dragonfly:
|
||||||
# false — если Redis разворачивается отдельно; тогда укажите его в app.redis.
|
# false — если Redis ставят отдельно; тогда заполните app.redis.host
|
||||||
enabled: true
|
enabled: true
|
||||||
# Ограничение памяти. Раскомментируйте при необходимости.
|
# Ограничение памяти
|
||||||
# maxmemory: "256M"
|
# maxmemory: "256M"
|
||||||
|
|||||||
+91
-92
@@ -7,63 +7,61 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [3.0.0] - 2026-09-02
|
## [3.0.0] - 2026-09-02
|
||||||
|
|
||||||
Синхронизация с продовым окружением HRBox и приведение чарта в порядок:
|
Чарт подтянут к тому, как HRBox работает в облаке: добавлен плеер учебных
|
||||||
добавлен плеер учебных материалов, секреты перестали лежать открытым текстом
|
материалов, пароли и ключи уехали в Secret, повторяющиеся куски шаблонов
|
||||||
в спеках подов, вместо девяти одинаковых блоков ресурсов — один хелпер,
|
заменены одним хелпером, а неполная конфигурация теперь останавливает
|
||||||
а неполная конфигурация теперь останавливает установку с внятным текстом.
|
установку с понятным сообщением.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
#### Nanabush Player
|
#### Nanabush Player
|
||||||
|
|
||||||
Проигрыватель учебных материалов: SCORM 1.2 и 2004, cmi5, xAPI, нативные
|
Плеер учебных материалов: SCORM 1.2 и 2004, cmi5, xAPI, нативные курсы,
|
||||||
курсы, тесты и эссе.
|
тесты и эссе.
|
||||||
|
|
||||||
- `09-nanabush-player.yaml` — Deployment и Service, образ `nanabush-player:1.0.11`
|
- `09-nanabush-player.yaml` — Deployment и Service, образ `nanabush-player:1.0.11`
|
||||||
- `00-nanabush-player-secret.yaml` — ключи launch-тикета и сессии
|
- `00-nanabush-player-secret.yaml` — ключи launch-тикета и сессии
|
||||||
- маршрут `/nanabush-player` на основном Ingress
|
- маршрут `/nanabush-player` на общем Ingress
|
||||||
- настройки: `app.nanabushPlayer` в values.yaml, ресурсы — `resources.nanabushPlayer`
|
- настройки `app.nanabushPlayer`, ресурсы `resources.nanabushPlayer`
|
||||||
- переменные `NANABUSH_PLAYER_*` в HRBox и `PLAYER_*` в самом плеере
|
- переменные `NANABUSH_PLAYER_*` в HRBox и `PLAYER_*` в самом плеере
|
||||||
|
|
||||||
On-premise-топология отличается от облачной: выделенного поддомена нет,
|
В on-premise выделенного поддомена нет, поэтому плеер стоит на основном
|
||||||
плеер монтируется на основной домен под путём. Отсюда два ограничения,
|
домене по пути. Отсюда два ограничения, они описаны в README: cookie HRBox
|
||||||
описанные в README: нет изоляции cookie между HRBox и содержимым курсов,
|
доступны содержимому курсов, и нужны синхронизированные часы — тикет живёт
|
||||||
и нужны синхронизированные часы (тикет живёт 5 минут).
|
5 минут.
|
||||||
|
|
||||||
Три независимых переключателя (`enabled`, `ingress.enabled`,
|
Для быстрого отката оставлены три переключателя: `enabled`,
|
||||||
`deployment.enabled`) сохранены для аварийного отката; чарт не даёт оставить
|
`ingress.enabled`, `deployment.enabled`. Маршрут без пода или включённый
|
||||||
маршрут без пода или раскатку без маршрута.
|
плеер без маршрута чарт не пропустит.
|
||||||
|
|
||||||
#### Проверка конфигурации
|
#### Проверка конфигурации
|
||||||
|
|
||||||
- `00-validate.yaml` — объектов не создаёт, но останавливает рендер, если
|
- `00-validate.yaml` — объектов не создаёт, но останавливает установку, если
|
||||||
не заполнены обязательные значения, использованы ключи из версии 2.x или
|
не заполнены обязательные значения, остались ключи из версии 2.x или
|
||||||
нарушены инварианты плеера. Сообщения на русском, с указанием, что править.
|
нарушены требования плеера. Сообщения на русском, с указанием, что править.
|
||||||
|
|
||||||
#### Секрет приложения
|
#### Secret приложения
|
||||||
|
|
||||||
- `00-app-secret.yaml` — единый Secret с паролями и ключами. Контейнеры
|
- `00-app-secret.yaml` — один Secret со всеми паролями и ключами. Поды
|
||||||
читают его через `secretKeyRef`, поэтому `kubectl get deploy -o yaml`
|
читают его через `secretKeyRef`, поэтому `kubectl get deploy -o yaml`
|
||||||
больше не показывает пароль базы и ключ шифрования.
|
больше не показывает пароль базы и ключ шифрования.
|
||||||
- `secrets.existingSecret` — подстановка Secret, созданного вне чарта.
|
- `secrets.existingSecret` — можно подставить Secret, созданный вне чарта.
|
||||||
|
|
||||||
#### Новые компоненты и возможности
|
#### Новые компоненты
|
||||||
|
|
||||||
- `09-file-processor-video.yaml` — отдельный пул конвертации видео с
|
- `09-file-processor-video.yaml` — отдельные поды для конвертации видео,
|
||||||
собственным профилем ресурсов, `nodeSelector` и `tolerations`
|
со своими ресурсами, `nodeSelector` и `tolerations`
|
||||||
(`app.videoConverter.enabled`, по умолчанию выключен)
|
(`app.videoConverter.enabled`, по умолчанию выключено)
|
||||||
- `02-web-pdb.yaml` — PodDisruptionBudget для `web`, создаётся начиная с
|
- `02-web-pdb.yaml` — PodDisruptionBudget для `web`, создаётся от двух реплик
|
||||||
двух реплик
|
- `01-otel-configmap.yaml` и коллектор OpenTelemetry рядом с `web`
|
||||||
- `01-otel-configmap.yaml` и sidecar-коллектор в поде `web`
|
|
||||||
(`app.tracing.enabled`)
|
(`app.tracing.enabled`)
|
||||||
- `01-nginx-assetlinks.yaml` — привязка мобильных приложений к домену
|
- `01-nginx-assetlinks.yaml` — привязка мобильных приложений к домену
|
||||||
(`app.mobileApps`)
|
(`app.mobileApps`)
|
||||||
- `templates/NOTES.txt` — что делать после установки, с готовыми командами
|
- `templates/NOTES.txt` — что делать после установки, с готовыми командами
|
||||||
и предупреждениями о небезопасных настройках
|
|
||||||
|
|
||||||
#### Новые переменные окружения
|
#### Новые переменные окружения
|
||||||
|
|
||||||
- `NATS_STREAM_REPLICAS` — число реплик JetStream-стримов по размеру кластера
|
- `NATS_STREAM_REPLICAS` — число реплик стримов JetStream по размеру кластера
|
||||||
- `TELEGRAM_API_URL`, `AUTH_GOOGLE_ENABLED`
|
- `TELEGRAM_API_URL`, `AUTH_GOOGLE_ENABLED`
|
||||||
- `LIVEKIT_URL`, `LIVEKIT_API_KEY`, `LIVEKIT_API_SECRET` — видеозвонки
|
- `LIVEKIT_URL`, `LIVEKIT_API_KEY`, `LIVEKIT_API_SECRET` — видеозвонки
|
||||||
- `APP_INTERNAL_URL` — внутренний адрес HRBox для конвертера
|
- `APP_INTERNAL_URL` — внутренний адрес HRBox для конвертера
|
||||||
@@ -72,52 +70,53 @@ On-premise-топология отличается от облачной: выд
|
|||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
#### Структура values.yaml
|
#### values.yaml
|
||||||
|
|
||||||
- все образы собраны в блок `image` — обновление версии сервиса стало
|
- все образы собраны в блок `image`: сменить версию сервиса — это правка
|
||||||
правкой одной строки
|
одной строки
|
||||||
- `imagePullSecrets` вынесен в настройки, `regsecret` больше не захардкожен
|
- `imagePullSecrets` вынесен в настройки, `regsecret` больше не зашит
|
||||||
|
в шаблоны
|
||||||
- ключи приведены к camelCase: `file_processor` → `fileProcessor`,
|
- ключи приведены к camelCase: `file_processor` → `fileProcessor`,
|
||||||
`custom_policy` → `customPolicy`
|
`custom_policy` → `customPolicy`
|
||||||
- `resources` дополнен компонентами `fileProcessor`, `fileProcessorVideo`,
|
- в `resources` добавлены `fileProcessor`, `fileProcessorVideo`,
|
||||||
`nanabushPlayer`, `dragonfly`, `nats`
|
`nanabushPlayer`, `dragonfly`, `nats`
|
||||||
- адреса внутренних сервисов (`app.geonames.url`, `app.goworker.url`,
|
- адреса внутренних сервисов (`app.geonames.url`, `app.goworker.url`,
|
||||||
`app.kedoca.url`, `app.redis.host`, `app.nats.url`) по умолчанию пустые и
|
`app.kedoca.url`, `app.redis.host`, `app.nats.url`) по умолчанию пустые
|
||||||
выводятся из имён, которые создаёт сам чарт. Раньше это были захардкоженные
|
и собираются из имён, которые создаёт сам чарт. Раньше это были строки
|
||||||
строки `hrbox-*`, которые молча ломались при `nameOverride`. Явно заданное
|
`hrbox-*`, зашитые в шаблоны: при `nameOverride` они молча переставали
|
||||||
значение по-прежнему используется как есть, поэтому старые values работают
|
работать. Заданное значение по-прежнему используется как есть, поэтому
|
||||||
без правок. Выключение `dragonfly` или `nats` без указания внешнего адреса
|
старые values работают без правок. Выключить `dragonfly` или `nats`,
|
||||||
теперь останавливает установку
|
не указав внешний адрес, теперь нельзя.
|
||||||
|
|
||||||
#### Шаблоны
|
#### Шаблоны
|
||||||
|
|
||||||
- `_resources.tpl`: девять почти одинаковых define заменены одним
|
- `_resources.tpl`: девять почти одинаковых define заменены одним
|
||||||
`hrbox.resources`; незаданные поля не рендерятся
|
`hrbox.resources`, незаполненные поля не рендерятся
|
||||||
- `_helpers.tpl`: убрано около сотни строк мёртвого кода (хелперы `nats.*`,
|
- `_helpers.tpl`: удалено около сотни строк неиспользуемого кода (хелперы
|
||||||
которыми ничего не пользовалось и которые ссылались на несуществующий
|
`nats.*`, которые ссылались на несуществующий `nats.k8sClusterDomain`);
|
||||||
`nats.k8sClusterDomain`); добавлены `hrbox.component`, `hrbox.labels`,
|
добавлены `hrbox.component`, `hrbox.labels`, `hrbox.selectorLabels`,
|
||||||
`hrbox.selectorLabels`, `hrbox.secretEnv` и хелперы плеера
|
`hrbox.secretEnv` и хелперы плеера
|
||||||
- у всех объектов появились стандартные лейблы `app.kubernetes.io/*`;
|
- у всех объектов появились стандартные лейблы `app.kubernetes.io/*`;
|
||||||
лейбл `app` сохранён, привычные `kubectl get pods -l app=worker` работают
|
лейбл `app` остался, привычный `kubectl get pods -l app=worker` работает
|
||||||
- селекторы Deployment не менялись — обновление 2.x → 3.0 не пересоздаёт
|
- селекторы Deployment не менялись, обновление 2.x → 3.0 не пересоздаёт
|
||||||
объекты
|
объекты
|
||||||
- аннотации `checksum/*` перезапускают поды при изменении конфигурации nginx
|
- аннотации `checksum/*` перезапускают поды при изменении конфигурации
|
||||||
или секрета приложения
|
nginx или Secret приложения
|
||||||
- образы, порты и таймауты вынесены из шаблонов в values.yaml
|
- образы, порты и таймауты вынесены из шаблонов в values.yaml
|
||||||
|
|
||||||
#### nginx
|
#### nginx
|
||||||
|
|
||||||
Набор `location` синхронизирован с продовым:
|
Набор `location` синхронизирован с облачным:
|
||||||
|
|
||||||
- `/healthz` и `/health-check` — под них настроены пробы пода `web`
|
- `/healthz` и `/health-check` — на них настроены пробы пода `web`
|
||||||
(раньше проверялся только TCP-порт)
|
(раньше проверялся только TCP-порт)
|
||||||
- `/api/v1/integration/commit` — потоковая загрузка оргструктуры из 1С без
|
- `/api/v1/integration/commit` — потоковая загрузка оргструктуры из 1С
|
||||||
буферизации тела, лимит 500 МБ
|
без буферизации, лимит 500 МБ
|
||||||
- `/ai/` — увеличенные таймауты
|
- `/ai/` — увеличенные таймауты
|
||||||
- `/.well-known/assetlinks.json` и `/.well-known/apple-app-site-association`
|
- `/.well-known/assetlinks.json` и `/.well-known/apple-app-site-association`
|
||||||
- `/frontend/sw.js` — корректные заголовки service worker
|
- `/frontend/sw.js` — правильные заголовки service worker
|
||||||
- кеширование шрифтов
|
- кеширование шрифтов
|
||||||
- убран TLSv1 и TLSv1.1
|
- убраны TLSv1 и TLSv1.1
|
||||||
|
|
||||||
#### Версии образов
|
#### Версии образов
|
||||||
|
|
||||||
@@ -132,56 +131,56 @@ On-premise-топология отличается от облачной: выд
|
|||||||
|
|
||||||
#### Джобы
|
#### Джобы
|
||||||
|
|
||||||
- имя содержит номер ревизии релиза: в `kubectl get jobs` видно, какой выкат
|
- в имени появился номер ревизии релиза: в `kubectl get jobs` видно, какой
|
||||||
запускал миграции, а повторный `upgrade` не спотыкается об уже существующий
|
выкат запускал миграции, а повторный `upgrade` не спотыкается о старый
|
||||||
объект
|
объект
|
||||||
- `ttlSecondsAfterFinished` — час у обеих джоб (было 100 секунд у миграций и
|
- `ttlSecondsAfterFinished` — час у обеих джоб (было 100 секунд у миграций
|
||||||
ничего у обновления кластера): логи упавшей джобы успевают дожить до того,
|
и ничего у обновления кластера), логи упавшей джобы успевают дожить до
|
||||||
как их посмотрят
|
того, как их посмотрят
|
||||||
|
|
||||||
#### Переименования файлов
|
#### Переименования файлов
|
||||||
|
|
||||||
- `03-websocket.yaml` → `03-chatbox.yaml` (содержимое было chatbox с версии 2.0)
|
- `03-websocket.yaml` → `03-chatbox.yaml` (внутри был chatbox с версии 2.0)
|
||||||
- `09-geonames.yml` → `09-geonames.yaml`
|
- `09-geonames.yml` → `09-geonames.yaml`
|
||||||
- `99-update-cluser-job.yaml` → `99-update-cluster-job.yaml`
|
- `99-update-cluser-job.yaml` → `99-update-cluster-job.yaml`
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- **Общий секрет в коде чарта.** `SERVICES_INTERNAL_SECRET` имел захардкоженное
|
- **Общий секрет у всех установок.** У `SERVICES_INTERNAL_SECRET` было
|
||||||
значение по умолчанию, то есть все установки, где его не заполнили, работали
|
значение по умолчанию, зашитое в чарт: все, кто его не заполнил, работали
|
||||||
на одном и том же секрете межсервисной аутентификации. Теперь значение
|
на одном и том же секрете межсервисной аутентификации. Теперь значение
|
||||||
обязательно.
|
обязательное.
|
||||||
- **Домен кластера игнорировался.** Маршруты кластера NATS были захардкожены
|
- **`cluster.domain` не использовался.** Маршруты кластера NATS были зашиты
|
||||||
на `cluster.local`, хотя `cluster.domain` присутствовал в values и
|
на `cluster.local`, хотя параметр в values был и применялся в соседней
|
||||||
использовался в соседней переменной. На кластере с нестандартным доменом
|
переменной. На кластере с другим доменом ноды не находили друг друга.
|
||||||
ноды не находили друг друга.
|
- **`CLUSTER_ADVERTISE` без сегмента `svc`.** Имя не резолвилось, ноды NATS
|
||||||
- **`CLUSTER_ADVERTISE` без сегмента `svc`.** Имя не резолвилось, и ноды NATS
|
сообщали соседям недостижимый адрес.
|
||||||
объявляли соседям недостижимый адрес.
|
- **Разные значения реплик NATS.** `nats.replicas` и `nats.cluster.replicas`
|
||||||
- **Рассинхрон реплик NATS.** `nats.replicas` и `nats.cluster.replicas`
|
задавались независимо, при расхождении часть нод не входила в кластер.
|
||||||
задавались независимо; при расхождении часть нод не входила в кластер.
|
Теперь чарт требует, чтобы они совпадали.
|
||||||
Теперь чарт требует их совпадения.
|
|
||||||
- **Пробы `web` не проверяли приложение.** Проверялся TCP-порт 9000, поэтому
|
- **Пробы `web` не проверяли приложение.** Проверялся TCP-порт 9000, поэтому
|
||||||
под с неработающим PHP считался готовым. Теперь readiness ходит в
|
под с неработающим PHP считался готовым. Теперь readiness ходит
|
||||||
`/health-check` через FPM.
|
в `/health-check` через FPM.
|
||||||
- Пароли и ключи больше не видны в спеках Deployment.
|
- Пароли и ключи больше не видны в спеках Deployment.
|
||||||
- `imagePullPolicy` у части сервисов был `Always` на закреплённых тегах —
|
- У части сервисов `imagePullPolicy` был `Always` на фиксированных тегах —
|
||||||
лишние обращения к реестру при каждом рестарте пода.
|
лишние обращения к реестру при каждом рестарте пода.
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
- `secrets` больше не имеет значений по умолчанию — пустые ключи
|
- у `secrets` больше нет значений по умолчанию: с пустыми ключами установка
|
||||||
останавливают установку вместо тихого запуска на предсказуемых секретах
|
останавливается, а не запускается на предсказуемых секретах
|
||||||
- убраны неиспользуемые хелперы `nats.name`, `nats.fullname`, `nats.chart`,
|
- удалены неиспользуемые хелперы `nats.name`, `nats.fullname`, `nats.chart`,
|
||||||
`nats.labels`, `nats.selectorLabels`, `nats.clusterAdvertise`,
|
`nats.labels`, `nats.selectorLabels`, `nats.clusterAdvertise`,
|
||||||
`nats.clusterRoutes`, `nats.extraRoutes`, `nats.tlsConfig`, `tplvalues.render`
|
`nats.clusterRoutes`, `nats.extraRoutes`, `nats.tlsConfig`,
|
||||||
- `SENDGRID_API_KEY` — не используется в on-premise
|
`tplvalues.render`
|
||||||
|
- `SENDGRID_API_KEY` — в on-premise не используется
|
||||||
|
|
||||||
### Migration Guide
|
### Migration Guide
|
||||||
|
|
||||||
#### Переход с 2.x на 3.0
|
#### Переход с 2.x на 3.0
|
||||||
|
|
||||||
Все переехавшие ключи чарт распознаёт и сообщает, куда именно они переехали,
|
Все переехавшие ключи чарт узнаёт и пишет, куда именно они переехали,
|
||||||
поэтому надёжнее всего запустить `helm template` и править по сообщениям.
|
поэтому проще всего запустить `helm template` и править по сообщениям.
|
||||||
|
|
||||||
**Шаг 1. Перенесите образы в блок `image`**
|
**Шаг 1. Перенесите образы в блок `image`**
|
||||||
|
|
||||||
@@ -225,20 +224,20 @@ app:
|
|||||||
| `app.chatbox.sentryDsn` | `app.sentry.chatboxDsn` |
|
| `app.chatbox.sentryDsn` | `app.sentry.chatboxDsn` |
|
||||||
| `nats.image` | `image.nats` |
|
| `nats.image` | `image.nats` |
|
||||||
|
|
||||||
**Шаг 3. Заполните ключи плеера**
|
**Шаг 3. Сгенерируйте ключи плеера**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
openssl rand -base64 48 # app.nanabushPlayer.keys.ticketHs256
|
openssl rand -base64 48 # app.nanabushPlayer.keys.ticketHs256
|
||||||
openssl rand -base64 48 # app.nanabushPlayer.keys.sessionHs256
|
openssl rand -base64 48 # app.nanabushPlayer.keys.sessionHs256
|
||||||
```
|
```
|
||||||
|
|
||||||
Ключи должны отличаться друг от друга.
|
Ключи должны быть разными.
|
||||||
|
|
||||||
**Шаг 4. Проверьте `secrets.servicesInternalSecret`**
|
**Шаг 4. Проверьте `secrets.servicesInternalSecret`**
|
||||||
|
|
||||||
Если поле было пустым, установка работала на общем значении по умолчанию.
|
Если поле было пустым, установка работала на общем значении по умолчанию.
|
||||||
Сгенерируйте своё: `openssl rand -base64 48`. После обновления перезапустятся
|
Сгенерируйте своё: `openssl rand -base64 48`. После обновления перезапустятся
|
||||||
все сервисы, обменивающиеся внутренними вызовами, — это ожидаемо.
|
все сервисы, которые ходят друг к другу, — это нормально.
|
||||||
|
|
||||||
**Шаг 5. Проверьте рендер и обновитесь**
|
**Шаг 5. Проверьте рендер и обновитесь**
|
||||||
|
|
||||||
@@ -249,21 +248,21 @@ helm upgrade hrbox .helm -n hrbox -f values.yaml
|
|||||||
|
|
||||||
**Шаг 6. Включите плеер**
|
**Шаг 6. Включите плеер**
|
||||||
|
|
||||||
Порядок первого включения и проверки — в README, раздел «Nanabush Player».
|
Порядок включения и проверки — в README, раздел «Nanabush Player».
|
||||||
|
|
||||||
#### Breaking Changes
|
#### Breaking Changes
|
||||||
|
|
||||||
1. **Ключи `values.yaml` переехали.** Установка останавливается с подсказкой,
|
1. **Ключи `values.yaml` переехали.** Установка останавливается с подсказкой,
|
||||||
молча ничего не игнорируется.
|
молча ничего не игнорируется.
|
||||||
2. **`secrets.*` стали обязательными.** Установка без них не пройдёт.
|
2. **`secrets.*` стали обязательными.** Без них установка не пройдёт.
|
||||||
3. **Появился Nanabush Player.** Это дополнительный под, Service, Secret и
|
3. **Появился Nanabush Player.** Это дополнительный под, Service, Secret и
|
||||||
маршрут; учтите ресурсы кластера. Плеер требует синхронизированного времени
|
маршрут, учтите ресурсы кластера. Плееру нужно синхронизированное время
|
||||||
на нодах.
|
на нодах.
|
||||||
4. **Пробы `web` стали строже.** Под, где PHP-FPM не отвечает по HTTP, теперь
|
4. **Пробы `web` стали строже.** Под, где PHP-FPM не отвечает по HTTP, теперь
|
||||||
не проходит readiness. Если приложение отдаёт `/health-check` иначе,
|
не проходит readiness. Если приложение отдаёт `/health-check` иначе,
|
||||||
проверьте это до обновления.
|
проверьте это до обновления.
|
||||||
5. **`app.replicas` расширился** полями `goworker`, `kedoca`, `fileProcessor`,
|
5. **В `app.replicas` добавились** `goworker`, `kedoca`, `fileProcessor`,
|
||||||
`fileProcessorVideo`; соответствующие `replicas` внутри сервисов удалены.
|
`fileProcessorVideo`; поля `replicas` внутри самих сервисов удалены.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
# HRBox Helm Chart
|
# HRBox Helm Chart
|
||||||
|
|
||||||
Helm-чарт для развёртывания HRBox в собственном Kubernetes-кластере.
|
Чарт для установки HRBox в свой Kubernetes-кластер.
|
||||||
|
|
||||||
Чарт лежит в каталоге [`.helm`](.helm), настройки — в [`.helm/values.yaml`](.helm/values.yaml).
|
Сам чарт лежит в [`.helm`](.helm), настройки — в [`.helm/values.yaml`](.helm/values.yaml).
|
||||||
Каждый параметр там прокомментирован; ниже — только то, что нужно сделать руками.
|
Каждый параметр там подписан, ниже — только то, что нужно сделать руками.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -11,32 +11,32 @@ Helm-чарт для развёртывания HRBox в собственном
|
|||||||
|
|
||||||
| Компонент | Что делает | Порт |
|
| Компонент | Что делает | Порт |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `web` | PHP-FPM + nginx: веб-интерфейс и API | 80 |
|
| `web` | PHP-FPM и nginx: веб-интерфейс и API | 80 |
|
||||||
| `worker` | фоновые задачи: файлы, почта, отчёты | — |
|
| `worker` | фоновые задачи: файлы, почта, отчёты | — |
|
||||||
| `conductor` | планировщик задач по расписанию (строго 1 реплика) | 8080 |
|
| `conductor` | задачи по расписанию, всегда 1 под | 8080 |
|
||||||
| `chatbox` | вебсокеты чата и real-time уведомлений | 80 → 9797 |
|
| `chatbox` | вебсокеты чата и уведомлений | 80 → 9797 |
|
||||||
| `nanabush-player` | проигрыватель курсов: SCORM, cmi5, xAPI, нативные материалы | 8094 |
|
| `nanabush-player` | плеер курсов: SCORM, cmi5, xAPI, нативные материалы | 8094 |
|
||||||
| `goworker` | мессенджеры, push, синхронизация оргструктуры с 1С | 8686 |
|
| `goworker` | мессенджеры, пуши, синхронизация оргструктуры с 1С | 8686 |
|
||||||
| `kedoca` | электронная подпись: КЭДО, МЧД | 8558 |
|
| `kedoca` | электронная подпись: КЭДО, МЧД | 8558 |
|
||||||
| `geonames` | справочник городов, стран, часовых поясов | 8181 |
|
| `geonames` | справочник городов, стран, часовых поясов | 8181 |
|
||||||
| `file-processor` | конвертация документов и изображений | — |
|
| `file-processor` | конвертация документов и изображений | — |
|
||||||
| `file-processor-video` | конвертация видео, выключена по умолчанию | — |
|
| `file-processor-video` | конвертация видео, по умолчанию выключен | — |
|
||||||
| `dragonfly` | Redis-совместимый кеш и сессии | 6379 |
|
| `dragonfly` | Redis-совместимый кеш и сессии | 6379 |
|
||||||
| `nats` | брокер сообщений JetStream | 4222 |
|
| `nats` | брокер сообщений JetStream | 4222 |
|
||||||
|
|
||||||
Все три публичных маршрута живут на одном домене: `/` — приложение,
|
Публичных маршрутов три, и все на одном домене: `/` — приложение,
|
||||||
`/chatbox/` — вебсокеты, `/nanabush-player` — плеер курсов.
|
`/chatbox/` — вебсокеты, `/nanabush-player` — плеер курсов.
|
||||||
|
|
||||||
## Что нужно от вас
|
## Что нужно подготовить
|
||||||
|
|
||||||
- Kubernetes 1.21+ и ingress-контроллер (nginx или traefik);
|
- Kubernetes 1.21+ и ingress-контроллер (nginx или traefik);
|
||||||
- PostgreSQL 14+ (с расширением Citus, если планируется шардирование);
|
- PostgreSQL 14+ (с Citus, если планируется шардирование);
|
||||||
- S3-совместимое хранилище: AWS S3, MinIO, Yandex Object Storage, VK Cloud;
|
- S3-совместимое хранилище: AWS S3, MinIO, Yandex Object Storage, VK Cloud;
|
||||||
- SMTP-сервер;
|
- SMTP-сервер;
|
||||||
- доступ к Docker-реестру HRBox и токен HRBox Hub — выдают сотрудники HRBox.
|
- доступ к реестру образов HRBox и токен HRBox Hub — выдают сотрудники HRBox.
|
||||||
|
|
||||||
PostgreSQL и S3 чарт не разворачивает: это состояние, которое переживает
|
Базу и хранилище чарт не разворачивает: это данные, которые живут дольше
|
||||||
установку и требует собственного резервного копирования.
|
установки и требуют своего резервного копирования.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -52,13 +52,13 @@ kubectl create secret docker-registry regsecret \
|
|||||||
--docker-email=not@used.com
|
--docker-email=not@used.com
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. TLS-сертификат домена
|
### 2. TLS-сертификат
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl create secret tls hrbox-tls --cert=cert.pem --key=key.pem
|
kubectl create secret tls hrbox-tls --cert=cert.pem --key=key.pem
|
||||||
```
|
```
|
||||||
|
|
||||||
Или выпустите сертификат через cert-manager и укажите его Secret
|
Либо выпустите сертификат через cert-manager и укажите его Secret
|
||||||
в `ingress.tls.secretName`.
|
в `ingress.tls.secretName`.
|
||||||
|
|
||||||
### 3. Ключи
|
### 3. Ключи
|
||||||
@@ -72,15 +72,15 @@ openssl rand -hex 16
|
|||||||
openssl rand -base64 48
|
openssl rand -base64 48
|
||||||
```
|
```
|
||||||
|
|
||||||
`secrets.encryptionKey` — единственный ключ, потеря которого необратима:
|
`secrets.encryptionKey` теряется безвозвратно: им зашифрованы пароли
|
||||||
им зашифрованы пароли интеграций в базе. Сохраните его отдельно от кластера.
|
интеграций в базе. Сохраните копию отдельно от кластера.
|
||||||
|
|
||||||
Ключи плеера `ticketHs256` и `sessionHs256` должны отличаться друг от друга —
|
Ключи плеера `ticketHs256` и `sessionHs256` должны быть разными, одинаковые
|
||||||
это ключи разных контуров, и чарт откажется ставить одинаковые.
|
чарт не примет.
|
||||||
|
|
||||||
### 4. Заполните `values.yaml`
|
### 4. Заполните `values.yaml`
|
||||||
|
|
||||||
Обязательный минимум:
|
Минимум:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
ingress:
|
ingress:
|
||||||
@@ -121,7 +121,7 @@ secrets:
|
|||||||
servicesInternalSecret: "..."
|
servicesInternalSecret: "..."
|
||||||
```
|
```
|
||||||
|
|
||||||
Всё остальное имеет рабочие значения по умолчанию.
|
У остальных параметров есть рабочие значения по умолчанию.
|
||||||
|
|
||||||
Проверить конфигурацию, ничего не устанавливая:
|
Проверить конфигурацию, ничего не устанавливая:
|
||||||
|
|
||||||
@@ -129,8 +129,7 @@ secrets:
|
|||||||
helm template hrbox .helm -f values.yaml > /dev/null
|
helm template hrbox .helm -f values.yaml > /dev/null
|
||||||
```
|
```
|
||||||
|
|
||||||
Если чего-то не хватает, чарт скажет об этом текстом, а не оставит
|
Если чего-то не хватает, команда остановится и напишет, что заполнить.
|
||||||
неработающие поды в кластере.
|
|
||||||
|
|
||||||
### 5. Установка
|
### 5. Установка
|
||||||
|
|
||||||
@@ -144,7 +143,7 @@ helm upgrade --install hrbox .helm -n hrbox --create-namespace -f values.yaml
|
|||||||
kubectl -n hrbox wait --for=condition=complete --timeout=30m job -l app=jobs
|
kubectl -n hrbox wait --for=condition=complete --timeout=30m job -l app=jobs
|
||||||
```
|
```
|
||||||
|
|
||||||
### 7. Первый администратор
|
### 7. Создайте администратора
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl -n hrbox exec -it deploy/hrbox-worker -- \
|
kubectl -n hrbox exec -it deploy/hrbox-worker -- \
|
||||||
@@ -155,14 +154,13 @@ kubectl -n hrbox exec -it deploy/hrbox-worker -- \
|
|||||||
|
|
||||||
## Секреты
|
## Секреты
|
||||||
|
|
||||||
Чувствительные значения из `values.yaml` чарт складывает в один Secret
|
Пароли и ключи из `values.yaml` чарт кладёт в один Secret `hrbox-secrets`,
|
||||||
`hrbox-secrets` и монтирует контейнерам через `secretKeyRef` — в спеке
|
поды читают их оттуда. В спеке Deployment паролей нет.
|
||||||
Deployment паролей нет.
|
|
||||||
|
|
||||||
Если секретами управляет внешний инструмент, создайте Secret сами и укажите
|
Если секретами управляет внешний инструмент, создайте Secret сами и укажите
|
||||||
его имя в `secrets.existingSecret`. Ключи должны называться так:
|
имя в `secrets.existingSecret`. Ключи должны называться так:
|
||||||
|
|
||||||
| Ключ | Откуда берётся при `existingSecret: ""` |
|
| Ключ | Что кладут |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `cookie-validation-key` | `secrets.cookieValidationKey` |
|
| `cookie-validation-key` | `secrets.cookieValidationKey` |
|
||||||
| `encryption-key` | `secrets.encryptionKey` |
|
| `encryption-key` | `secrets.encryptionKey` |
|
||||||
@@ -180,63 +178,63 @@ Deployment паролей нет.
|
|||||||
| `slack-client-secret` | `app.slack.clientSecret` |
|
| `slack-client-secret` | `app.slack.clientSecret` |
|
||||||
| `slack-verification-token` | `app.slack.verificationToken` |
|
| `slack-verification-token` | `app.slack.verificationToken` |
|
||||||
|
|
||||||
Ключи плеера лежат в отдельном Secret `hrbox-nanabush-player` — им управляет
|
Ключи плеера лежат в отдельном Secret `hrbox-nanabush-player`, за него
|
||||||
`app.nanabushPlayer.deployment.existingSecret`.
|
отвечает `app.nanabushPlayer.deployment.existingSecret`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Nanabush Player
|
## Nanabush Player
|
||||||
|
|
||||||
Проигрыватель учебных материалов: SCORM 1.2 и 2004, cmi5, xAPI, нативные
|
Плеер учебных материалов: SCORM 1.2 и 2004, cmi5, xAPI, нативные курсы,
|
||||||
курсы, тесты и эссе.
|
тесты и эссе.
|
||||||
|
|
||||||
В облаке HRBox плеер живёт на отдельном поддомене. В on-premise выделенного
|
В облаке HRBox плеер стоит на отдельном поддомене. В on-premise поддомена
|
||||||
поддомена нет, поэтому плеер монтируется на основной домен под путём
|
нет, поэтому плеер живёт на основном домене по пути `/nanabush-player`.
|
||||||
`/nanabush-player`. Что из этого следует:
|
Из этого следуют две вещи:
|
||||||
|
|
||||||
- **Изоляции cookie нет.** Плеер и HRBox делят один origin, поэтому cookie
|
- **Cookie общие.** Плеер и HRBox на одном домене, поэтому cookie сессии
|
||||||
сессии HRBox отправляются браузером и на запросы к содержимому курсов,
|
HRBox уходят и в запросы к содержимому курсов, включая сторонние
|
||||||
включая сторонние SCORM-пакеты. Если нужна настоящая изоляция —
|
SCORM-пакеты. Если такая изоляция нужна, запросите у HRBox схему
|
||||||
запрашивайте у HRBox схему с отдельным поддоменом.
|
с отдельным поддоменом.
|
||||||
- **Часы должны быть синхронизированы.** Launch-тикет живёт 5 минут, сессия
|
- **Часы должны быть синхронны.** Launch-тикет живёт 5 минут, у сессии
|
||||||
проверяется с допуском 2 минуты. Настройте NTP на нодах и сервере БД;
|
допуск 2 минуты. Настройте NTP на нодах и сервере базы. Если это
|
||||||
если это невозможно, выключите плеер (`app.nanabushPlayer.enabled: false`).
|
невозможно, выключите плеер: `app.nanabushPlayer.enabled: false`.
|
||||||
|
|
||||||
Порядок первого включения:
|
Порядок первого включения:
|
||||||
|
|
||||||
1. Убедитесь, что миграции применились: плееру нужны таблицы проекций.
|
1. Убедитесь, что миграции применились: плееру нужны свои таблицы.
|
||||||
2. Дождитесь, пока **все** поды `web` перейдут на новую ревизию. Смешанный
|
2. Дождитесь, пока **все** поды `web` перейдут на новую версию. Пока часть
|
||||||
выкат при `rollout.percent > 0` может создать вторую активную попытку по
|
подов старая, при `rollout.percent > 0` по одному назначению может
|
||||||
одному назначению.
|
открыться вторая попытка.
|
||||||
3. Проверьте, что плеер отвечает сам, а не HRBox через общий маршрут:
|
3. Проверьте, что отвечает именно плеер, а не HRBox через общий маршрут:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl -n hrbox exec deploy/hrbox-worker -- \
|
kubectl -n hrbox exec deploy/hrbox-worker -- \
|
||||||
curl -s http://hrbox-nanabush-player:8094/readyz
|
curl -s http://hrbox-nanabush-player:8094/readyz
|
||||||
```
|
```
|
||||||
|
|
||||||
Настоящий плеер вернёт JSON. HTML означает, что запрос ушёл в HRBox.
|
Плеер вернёт JSON. HTML означает, что запрос ушёл в HRBox.
|
||||||
|
|
||||||
4. Проверьте публичный путь: `https://<домен>/nanabush-player/start`,
|
4. Откройте `https://<домен>/nanabush-player/start` и проверьте статику
|
||||||
статику и API плеера под этим путём.
|
и API плеера по этому пути.
|
||||||
|
|
||||||
Служебные пути (`/healthz`, `/readyz`, метрики) живут в корне и не зависят
|
`/healthz`, `/readyz` и метрики отвечают в корне и от `basePath` не зависят.
|
||||||
от `basePath`. Порт метрик наружу не публикуется намеренно.
|
Порт метрик наружу не публикуется.
|
||||||
|
|
||||||
Аварийное отключение — три независимых переключателя:
|
Быстро выключить плеер можно тремя переключателями:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
app:
|
app:
|
||||||
nanabushPlayer:
|
nanabushPlayer:
|
||||||
enabled: false # пользователи возвращаются на старый проигрыватель
|
enabled: false # пользователи вернутся на старый проигрыватель
|
||||||
ingress:
|
ingress:
|
||||||
enabled: false # маршрут снимается
|
enabled: false # маршрут снимается
|
||||||
deployment:
|
deployment:
|
||||||
enabled: false # под останавливается
|
enabled: false # под останавливается
|
||||||
```
|
```
|
||||||
|
|
||||||
Выключать нужно сверху вниз: чарт не даст оставить включённым маршрут
|
Выключать нужно сверху вниз: чарт не даст оставить маршрут без пода
|
||||||
без пода или раскатку без маршрута.
|
или включённый плеер без маршрута.
|
||||||
|
|
||||||
Подробности контракта — `docs/nanabush-player-deployment.md` в репозитории HRBox.
|
Подробности контракта — `docs/nanabush-player-deployment.md` в репозитории HRBox.
|
||||||
|
|
||||||
@@ -250,9 +248,9 @@ app:
|
|||||||
helm upgrade hrbox .helm -n hrbox -f values.yaml
|
helm upgrade hrbox .helm -n hrbox -f values.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Миграции и обновление кластера запускаются автоматически как хуки
|
Миграции и обновление кластера запускаются сами как хуки `post-upgrade`,
|
||||||
`post-upgrade` и выполняются строго по порядку. Имя джобы содержит номер
|
строго по очереди. В имени джобы есть номер ревизии релиза, поэтому
|
||||||
ревизии релиза, поэтому в `kubectl get jobs` видно, какой выкат её запускал.
|
в `kubectl get jobs` видно, к какому выкату она относится.
|
||||||
|
|
||||||
### Масштабирование
|
### Масштабирование
|
||||||
|
|
||||||
@@ -264,16 +262,16 @@ app:
|
|||||||
chatbox: 4 # по числу открытых вкладок
|
chatbox: 4 # по числу открытых вкладок
|
||||||
```
|
```
|
||||||
|
|
||||||
`conductor` всегда в одном экземпляре: второй планировщик запустил бы
|
`conductor` всегда в одном экземпляре: два планировщика запустят каждую
|
||||||
каждую задачу дважды.
|
задачу дважды.
|
||||||
|
|
||||||
Для `web` при двух и более репликах создаётся PodDisruptionBudget
|
Для `web` от двух реплик создаётся PodDisruptionBudget (`minAvailable: 75%`),
|
||||||
(`minAvailable: 75%`), чтобы drain ноды не уронил приложение целиком.
|
чтобы вывод ноды из обслуживания не уронил приложение целиком.
|
||||||
|
|
||||||
### Конвертация видео
|
### Конвертация видео
|
||||||
|
|
||||||
Выключена по умолчанию: профиль ресурсов у неё на порядок тяжелее обычной
|
Выключена по умолчанию, потому что требует заметно больше ресурсов, чем
|
||||||
обработки файлов. Включение:
|
остальная обработка файлов. Включение:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
app:
|
app:
|
||||||
@@ -297,7 +295,7 @@ app:
|
|||||||
tempoUrl: "http://tempo.monitoring:4317"
|
tempoUrl: "http://tempo.monitoring:4317"
|
||||||
```
|
```
|
||||||
|
|
||||||
Рядом с `web` поднимется коллектор OpenTelemetry, PHP начнёт слать трейсы.
|
Рядом с `web` появится коллектор OpenTelemetry, PHP начнёт слать трейсы.
|
||||||
|
|
||||||
### Внешние Redis и NATS
|
### Внешние Redis и NATS
|
||||||
|
|
||||||
@@ -323,18 +321,18 @@ kubectl -n hrbox logs -l app=nanabush-player --tail=200
|
|||||||
kubectl -n hrbox get jobs
|
kubectl -n hrbox get jobs
|
||||||
```
|
```
|
||||||
|
|
||||||
| Симптом | Куда смотреть |
|
| Что видно | Куда смотреть |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Поды `web` не готовы | пробы `/healthz` и `/health-check`, логи контейнера `fpm` |
|
| Поды `web` не готовы | пробы `/healthz` и `/health-check`, логи контейнера `fpm` |
|
||||||
| Джоба миграций висит | init-контейнер `wait-postgres`: доступность и права в БД |
|
| Джоба миграций висит | init-контейнер `wait-postgres`: доступность базы и права |
|
||||||
| Курс не открывается | логи `nanabush-player`, совпадение домена в `ingress.host` и `app.defaultTenantHostname` |
|
| Курс не открывается | логи `nanabush-player`, совпадают ли `ingress.host` и `app.defaultTenantHostname` |
|
||||||
| Не приходят уведомления | логи `goworker`, очереди NATS, `app.launchpad.topics` |
|
| Не приходят уведомления | логи `goworker`, очереди NATS, `app.launchpad.topics` |
|
||||||
| Пользователей разлогинивает | перезапуски `dragonfly`: сессии живут в памяти |
|
| Пользователей разлогинивает | перезапуски `dragonfly`: сессии хранятся в памяти |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Миграция с версии 2.x
|
## Обновление с версии 2.x
|
||||||
|
|
||||||
Часть ключей `values.yaml` переехала. Чарт проверяет старые имена и
|
Часть ключей `values.yaml` переехала. Старые имена чарт узнаёт и
|
||||||
останавливает установку с подсказкой, поэтому незамеченным ничего не
|
останавливает установку с подсказкой, поэтому ничего не потеряется.
|
||||||
останется. Полный список изменений и порядок перехода — в [CHANGELOG.md](CHANGELOG.md).
|
Список изменений и порядок перехода — в [CHANGELOG.md](CHANGELOG.md).
|
||||||
|
|||||||
Reference in New Issue
Block a user