Установка CodeScoring.Save в Kubernetes
CodeScoring.Save устанавливается с помощью Helm-чарта save. Один и тот же чарт поддерживает два сценария развертывания:
- стандартную установку в Kubernetes с PostgreSQL, Redis, а также поддержкой S3-совместимого объектного хранилища;
- hosted-установку в одноузловом кластере k3s с SQLite и файловым хранилищем.
Перед установкой проверьте системные требования.
Установка с помощью Helm-чарта
Адреса Helm-репозитория и реестра контейнерных образов, а также учетные данные предоставляет вендор. В командах ниже используются следующие обозначения:
HELM_REPOSITORY_URL— адрес Helm-репозитория;REGISTRY_URL— адрес реестра контейнерных образов;USERNAMEиPASSWORD— учетные данные для доступа;CHART_VERSION— версия Helm-чарта и CodeScoring.Save.
-
Создайте namespace:
-
Создайте Secret для доступа к приватному реестру контейнерных образов:
Имя Secret должно совпадать со значениями
image.pullSecretsиosa-proxy.imagePullSecretsвvalues.yaml. -
Установите Helm и добавьте репозиторий CodeScoring.Save:
-
Скачайте и распакуйте чарт:
Настройка параметров Helm-чарта
Внесите необходимые изменения до первой установки. Перед обновлением установленной системы создайте резервные копии PostgreSQL и объектного хранилища.
Вся конфигурация инсталляции находится в values.yaml. Примеры ниже содержат только изменяемые фрагменты: остальные параметры из поставляемого файла необходимо сохранить.
Контейнерные образы
Основные компоненты используют общие реестр, тег и Secret для скачивания образов:
OSA Proxy поставляется как зависимость чарта и имеет отдельные настройки образа:
Используйте версии образов, указанные в поставляемом values.yaml. Они проверены на совместимость с выбранной версией чарта.
Секреты приложения
Конфиденциальные параметры backend, worker, scheduler и auth находятся в secrets.save-secrets.data:
SECRETS_ENCRYPTION_KEY используется для шифрования сохраненных учетных данных. Сгенерируйте его один раз, например командой openssl rand -base64 32, сохраните в защищенном хранилище и не меняйте при обновлениях. После смены ключа ранее сохраненные данные невозможно расшифровать.
Не храните рабочие пароли и ключи в системе контроля версий. Для продуктивной установки используйте защищенный файл значений или External Secrets.
Ключ подписи JWT
При первом старте сервис cs-auth создаёт ключ RSA-2048 и сохраняет его в своей базе данных. При перезапуске и на других репликах ключ читается оттуда.
Ключ хранится в базе данных без шифрования. Дамп или резервная копия базы (в том числе общей с Save) позволяет выпускать токены от имени любого пользователя — храните их как секреты.
Ротация ключа доступна администратору через API (нужен токен администратора, см. Получение JWT администратора):
При плановой ротации новый ключ сначала публикуется в JWKS и через 2 минуты начинает подписывать токены. Старый ключ продолжает проверять уже выданные токены, пока они не истекут, затем удаляется сам. При экстренной ротации refresh-токены продолжают работать, поэтому веб-интерфейс просто получит новую пару токенов. Каждая ротация записывается в журнал аудита.
PostgreSQL и Redis из Helm-чарта
По умолчанию чарт создает PostgreSQL и Redis как StatefulSet. Включите эти ресурсы и настройте PersistentVolumeClaim:
Замените storageClassName и размеры томов в соответствии с конфигурацией кластера и ожидаемым объемом данных.
Учетные данные встроенной PostgreSQL задаются отдельно и должны совпадать с параметрами DATABASE_NAME, DATABASE_USER и DATABASE_PASSWORD в secrets.save-secrets.data:
Параметры подключения приложения к PostgreSQL и Redis находятся в ConfigMap save-backend-envs:
HEALTH_PORT используется сервисами worker и scheduler для отдельного probe-listener (API backend не использует этот порт). По умолчанию чарт проверяет:
- startup probe:
/health/startup, - readiness probe:
/health/ready, - liveness probe:
/health/live.
Если вы меняете HEALTH_PORT, синхронно обновите startupProbe, readinessProbe и livenessProbe в deployments.worker и deployments.scheduler, чтобы порт в probe-конфигурации совпадал с переменной окружения.
ConfigMap и Secret уже подключены к компонентам через deploymentsGeneral.envConfigmaps и deploymentsGeneral.envSecrets. При изменении полного values.yaml сохраните эти ссылки:
Внешние PostgreSQL и Redis
Для внешней PostgreSQL отключите встроенный StatefulSet и его PVC, затем измените параметры подключения:
База данных и пользователь должны быть созданы до установки CodeScoring.Save.
Для внешнего Redis отключите встроенные StatefulSet, Service и PVC:
S3-совместимое объектное хранилище
Текущий чарт не разворачивает S3-хранилище. Для стандартной Kubernetes-инсталляции заранее создайте бакет во внешнем S3-совместимом хранилище и укажите параметры подключения:
Для хранилища, которое поддерживает virtual-hosted-style URL, установите S3_FORCE_PATH_STYLE: "false".
Параметр S3_REGION обязателен. Для MinIO и других хранилищ без регионов укажите любое значение, например us-east-1. Если в одном бакете нужно разместить несколько инсталляций, задайте каждой свой префикс ключей в S3_PREFIX.
Загрузка больших файлов
Файл не больше одной части (по умолчанию 8 МиБ) Save записывает в S3 одним запросом. Файл больше — multipart-загрузкой: он делится на части, и несколько частей отправляются параллельно. Поэтому Save хранит артефакты больше 5 ГБ (предел S3 — 5 ТиБ на объект) и не упирается в ограничение MinIO на размер фрагмента в 16 МиБ (ошибка chunk too big).
Обычно значения по умолчанию подходят. При необходимости их можно изменить в configMaps.save-backend-envs.data:
Что важно учесть:
- Память. Одна multipart-загрузка занимает около
(S3_MULTIPART_CONCURRENCY + 2) × S3_MULTIPART_PART_SIZE_MB, а под в худшем случае —S3_MULTIPART_MAX_INFLIGHTтаких загрузок. Со значениями по умолчанию это 16 × 4 × 8 МиБ = 512 МиБ. Учитывайте это вresources.limits.memoryдля backend и worker. S3 допускает не больше 10 000 частей, поэтому для очень больших файлов (с частями по 8 МиБ — больше ~78 ГиБ) размер части увеличивается автоматически, и памяти на такую загрузку нужно пропорционально больше. - MinIO. Не задавайте
S3_MULTIPART_PART_SIZE_MBбольше16: MinIO по https отклоняет фрагменты крупнее 16 МиБ. - Временные файлы. Перед отправкой в S3 Save часто сохраняет входящий файл во временный каталог пода (по умолчанию
/tmp): так обрабатываются слои Docker, пакеты RPM и Composer и любые потоки, которые нельзя перечитать. В памяти файл целиком не держится, но на диске нужно свободное место не меньше суммарного размера файлов, которые загружаются одновременно. В Kubernetes это ephemeral storage узла: задайте для backend запасephemeral-storageили подключите отдельный том и укажите его путь в переменнойTMPDIR. - Время запроса. Save ждёт один HTTP-запрос не дольше 10 минут — за это время файл должен быть и получен, и записан в S3. Например, для файла 5 ГБ нужна скорость не меньше ~10 МБ/с. Таймауты ingress и балансировщика должны быть не меньше (см. Ingress).
- Прерванные загрузки. Если загрузка оборвалась, Save отменяет multipart-загрузку в S3. Если отменить не удалось (например, S3 был недоступен), уже загруженные части остаются в бакете и занимают место. В AWS S3 и Yandex Object Storage настройте для бакета правило жизненного цикла
AbortIncompleteMultipartUpload(например, 1 день). MinIO удаляет незавершённые загрузки сам (параметрstale_uploads_expiry, по умолчанию 24 часа). - Контрольные суммы. Если задан
S3_ENDPOINT, Save добавляет контрольные суммы к запросам только тогда, когда хранилище их требует, — так совместимость с MinIO, Ceph и другими S3-хранилищами лучше. Изменить поведение можно стандартными переменными AWS SDKAWS_REQUEST_CHECKSUM_CALCULATIONиAWS_RESPONSE_CHECKSUM_VALIDATION(when_supportedилиwhen_required). - Свой сертификат у S3. Если S3 открыт по https с сертификатом корпоративного центра сертификации, укажите путь к его сертификату в
AWS_CA_BUNDLE.
Hosted-установка в k3s
Hosted-вариант предназначен для односерверной установки в k3s и использует SQLite для метаданных и локальную файловую систему для артефактов.
Установите k3s и настройте доступ к кластеру:
Чтобы переключить стандартный профиль чарта на hosted, измените три переменные в configMaps.save-backend-envs.data:
ConfigMap save-backend-envs подключен к backend, worker, scheduler и auth, поэтому дополнительные ConfigMap создавать не требуется. Остальные параметры из поставляемого values.yaml сохраните без изменений.
Компоненты worker и scheduler требуют PostgreSQL и не поддерживают работу с SQLite. В hosted-инсталляции обязательно отключите оба deployment:
Постоянное хранение данных
Для hosted-установки нужны три отдельных постоянных тома:
db-data— база SQLite backend;auth-data— база SQLite auth;storage— файловое хранилище артефактов.
Подключите PVC к deployments через volumes и volumeMounts. Для auth также задайте пустое значение initContainers, чтобы удалить унаследованный init-контейнер wait-for-postgres:
Backend и auth используют одинаковое значение DATABASE_SQLITE_PATH, но отдельные PVC, поэтому каждый сервис хранит собственную базу в своем каталоге /app/data. Значение STORAGE_ROOT_PATH по умолчанию — ./storage, что соответствует точке монтирования /app/storage при рабочем каталоге /app.
При использовании Dynamic Volume Provisioning укажите StorageClass для каждого PVC. Соответствующие PV будут созданы автоматически:
Размеры томов и storageClassName необходимо подобрать с учетом нагрузки и конфигурации кластера.
Также можно использовать заранее созданные PV любого поддерживаемого Kubernetes типа. В этом случае создайте PV самостоятельно или опишите их в секции pvs, а в каждом PVC задайте пустой storageClassName и соответствующий volumeName, например:
В примере для Helm-релиза codescoring-save чарт создает PV codescoring-save-db-data из секции pvs.db-data, а PVC явно привязывается к нему через volumeName. Замените адрес NFS-сервера и путь экспорта значениями своей инфраструктуры.
Аналогично создайте и привяжите тома auth-data и storage. Конкретный источник тома может быть NFS, CSI, локальным диском или другим хранилищем; параметры зависят от инфраструктуры кластера.
Опциональный Redis
Redis не обязателен для hosted-установки. Чтобы запустить Save без Redis, выключите его в конфигурации приложения и отключите связанные StatefulSet, Service и PVC:
Если Redis используется, сохраните REDIS_ENABLED: "true", оставьте его StatefulSet, Service и PVC включенными.
SQLite рассчитана на работу одной реплики. Не увеличивайте deploymentsGeneral.replicas и отключите автоматическое масштабирование backend и worker:
После переключения приложение не использует PostgreSQL. Чтобы не создавать неиспользуемые ресурсы, можно дополнительно отключить StatefulSet и PVC:
SQLite и файловое хранилище подходят только для односерверной установки. Каталоги с базами SQLite и артефактами должны находиться на сохраняемом диске k3s и регулярно копироваться. Не используйте этот профиль для многорепличного развертывания.
Ingress
По умолчанию Ingress выключен. Чтобы открыть веб-интерфейс и API, включите его и замените доменное имя:
Если TLS завершается на внешнем балансировщике, настройте tls и аннотации Ingress в соответствии с инфраструктурой кластера.
Чтобы через Ingress проходили большие файлы (слои Docker, архивы, пакеты), снимите ограничение на размер запроса и увеличьте таймауты до 10 минут — столько Save ждёт один запрос. Пример для ingress-nginx:
Без этих настроек ingress-nginx по умолчанию отклоняет запросы больше 1 МБ с ошибкой 413 Request Entity Too Large.
HTTPRoute (Gateway API)
Если в кластере используется Kubernetes Gateway API, настройте маршрут к frontend через секцию httpRoutes. Ресурс Gateway, на который ссылается маршрут, должен существовать до установки CodeScoring.Save.
Значения gatewayName, gatewayNamespace, gatewaySectionName и hostnames должны соответствовать Gateway и DNS-имени в вашем кластере.
Значение backendRefs.name формируется как {helm-release-name}-frontend. Например, для команды helm install codescoring-save ... необходимо указать name: codescoring-save-frontend.
OSA Proxy
OSA Proxy отключена по умолчанию. Для ее включения необходимо выставить поле osa-proxy.enabled в значение true.
В существующем блоке osa-proxy.config.content замените значение codescoring.url на адрес инсталляции CodeScoring. Токен передайте через Secret osa-proxy:
Если проверка компонентов через OSA Proxy не требуется, отключите зависимость:
osa-proxy.config.content содержит полную конфигурацию сервиса. При ее изменении сохраните остальные секции из поставляемого values.yaml.
Ограничения ресурсов
В поставляемом values.yaml ресурсы контейнеров не ограничены. Для продуктивной установки задайте requests и limits для каждого компонента по результатам нагрузочного тестирования:
Аналогично настройте deployments.scheduler, deployments.auth, deployments.save-frontend, statefulSets.save-postgresql и statefulSets.save-redis. Для корректной работы HPA у масштабируемых контейнеров должны быть заданы CPU requests.
External Secrets
Чарт может получать секреты из внешнего хранилища через External Secrets Operator. В кластере должны быть заранее установлены оператор и SecretStore или ClusterSecretStore.
Включите нужный ресурс в секции vaults:
Затем подключите создаваемый Secret к deployments:
Для встроенной PostgreSQL аналогично настройте vaults.postgresql-secrets-external и подключите Secret в statefulSets.save-postgresql.envSecrets.
Установка
Из каталога распакованного чарта выполните:
Для обновления существующей инсталляции используйте ту же версию настроенного values.yaml:
Проверка установки
Проверьте состояние ресурсов:
Все Pod должны перейти в состояние Running, а их контейнеры — быть готовы. Для диагностики используйте логи компонентов:
Проверить probe-эндпоинты worker/scheduler можно вручную (через port-forward на HEALTH_PORT, по умолчанию 8082):
После установки откройте адрес, указанный в Ingress, и введите ключ активации. Затем войдите с паролем из AUTH_ADMIN_PASSWORD.
Ключ активации
Пока ключ активации не введён, Save отвечает 403 с сообщением No valid license на запросы к API и к репозиториям. Без ключа работают только вход в систему, проверка состояния, Swagger и страница ключа активации.
Ключ активации предоставляет вендор. Ввести его можно двумя способами.
В веб-интерфейсе.
- Откройте
Settings -> Activation key. - Нажмите Add new activation key в правом верхнем углу.
- Вставьте ключ в поле Enter new key here и нажмите Activate.
Новый ключ заменяет текущий. На странице Activation key видны состояние ключа (Status), дата выдачи (Issued at), срок действия (Expires in) и число артефактов (Artifacts).
Через API:
В ответе — состояние ключа: is_valid, владелец (owner), даты issued_at и expires_at, оставшееся время expires_in (в миллисекундах) и пояснение message.
Проверить состояние ключа и счётчик артефактов:
Каждый под запоминает результат проверки ключа активации до 2 часов. С Redis новый ключ сразу виден всем подам. Без Redis под, который уже запомнил, что ключа нет, может отвечать 403 до 2 часов — после ввода ключа перезапустите поды backend: kubectl rollout restart deployment -n codescoring-save.
Следующие шаги
После успешной установки:
