Перейти к содержимому

Начало работы в Kubernetes (Helm)

Helm-чарт по пути deploy/helm/olivares разворачивает control plane с теми же безопасными настройками по умолчанию, что и любой другой способ: core StatefulSet (не от root, корневая файловая система только для чтения, все capabilities сброшены), включённый TLS, экспозиция, эквивалентная loopback (Service типа ClusterIP — ничего публичного, пока вы сами не решите), и никаких учётных данных по умолчанию. Отсюда вы по своему выбору подключаете Postgres, active-passive HA, плановые зашифрованные DR-резервные копии и DaemonSet коллекторов для распределённого приёма данных.

Всё, что приведено ниже, было отрендерено и проверено относительно чарта в этом репозитории (helm lint + helm template, включая конфигурации HA и резервного копирования, а также собственные предохранители чарта). Чарт требует Kubernetes ≥ 1.25.

  1. Установка из чекаута:

    Окно терминала
    helm install olivares deploy/helm/olivares

    Это рендерит ровно три объекта рабочих нагрузок — StatefulSet (1 реплика, SQLite на постоянном PVC объёмом 8 Gi), ClusterIP Service (8443 HTTPS, 8444 gRPC) и ServiceAccount без привилегий Kubernetes API. Пробы обращаются к /readyz (readiness — выводится из ротации, когда хранилище недоступно или реплика не лидер) и /livez (liveness — только процесс, никогда не зависимость, так что отказ хранилища никогда не вызовет цикл перезапусков).

  2. Прочитайте одноразовый токен настройки из лога пода (он выводится только в stdout — в Kubernetes это лог контейнера):

    Окно терминала
    kubectl logs -l app.kubernetes.io/component=core | sed -n '/FIRST-BOOT SETUP/,/========================/p'
  3. Сделайте port-forward и завершите первичную настройку (тот же процесс, что и везде):

    Окно терминала
    # Service называется <release>-olivares-core:
    kubectl port-forward svc/olivares-core 8443:8443
    curl -ksf -X POST https://127.0.0.1:8443/v1/setup \
    -H 'Content-Type: application/json' \
    -d '{"token":"<olst_ token>","email":"you@example.com","password":"<strong-password>"}'

Как вариант, вообще без Helm: репозиторий поставляет плоский манифест с теми же безопасными одноузловыми настройками по умолчанию, регенерируемый из чарта в CI:

Окно терминала
kubectl apply -f deploy/manifests/install.yaml

Для Argo CD / Flux / Kustomize (kustomize build --enable-helm) см. deploy/gitops/ — декларативные обёртки над тем же чартом.

Движку требуется роль базы данных с минимальными привилегиями: LOGIN, не superuser, без BYPASSRLS — row-level security служит подстраховкой арендатора, и движок отказывается запускаться с привилегированной ролью. Подготовьте роль с помощью канонического deploy/postgres/01-app-role.sql (чарт может выполнить его за вас как pre-install Job), поместите DSN в Secret и укажите его чарту:

Окно терминала
kubectl create secret generic olivares-pg \
--from-literal=dsn='postgres://olivares_app:***@db:5432/olivares?sslmode=verify-full' \
--from-literal=admin-dsn='postgres://olivares_admin:***@db:5432/olivares?sslmode=verify-full'
helm install olivares deploy/helm/olivares \
--set core.engine=postgres \
--set postgres.dsnSecret=olivares-pg \
--set postgres.adminDsnKey=admin-dsn

Ключ admin-dsn в том же Secret содержит выделенную роль NOSUPERUSER BYPASSRLS. Он опционален только если вы никогда не будете включать резервное копирование: именно он делает полными межарендные системные чтения — список организаций и охват многоарендности, — а включение резервного копирования его требует (плановые зашифрованные резервные копии). Если создать его сейчас, тот последующий шаг сведётся к правке в одну строку.

С Postgres в роли общего хранилища запустите несколько реплик. Одна избирается лидером (advisory lock Postgres); резервные реплики отвечают на /readyz 503 {"status":"standby"}, так что Service маршрутизирует только к лидеру, а резервная реплика автоматически берёт управление, когда лидер исчезает.

Две вещи структурно обязательны, и чарт обеспечивает обе (мы убедились, что предохранители рендерятся как жёсткие отказы, а не предупреждения):

| Требование | Зачем | Предохранитель чарта при отсутствии | |---|---|---| | core.engine=postgres | Файл SQLite локален для одного пода — он не может быть общим хранилищем. | core.replicaCount > 1 requires core.engine=postgres … | | core.auditSigningKeySecret | Каждая реплика должна подписывать audit ledger одним и тем же ключом Ed25519, иначе hash chain раздваивается при failover. | core.replicaCount > 1 requires core.auditSigningKeySecret … |

Окно терминала
kubectl create secret generic olivares-audit-key \
--from-file=audit-signing.key=<base64-ed25519-private-key-file>
helm install olivares deploy/helm/olivares \
--set core.engine=postgres \
--set postgres.dsnSecret=olivares-pg \
--set core.replicaCount=3 \
--set core.auditSigningKeySecret=olivares-audit-key

Канонические размеры HA — 3 или 5 реплик, active-passive. Эта одно-писательская архитектура намеренна (она соответствует модели консистентности продукта); показатели готовности к продакшену документируют уровни доступности, которые она поддерживает.

4. Плановые зашифрованные резервные копии

Заголовок раздела «4. Плановые зашифрованные резервные копии»

Чарт поставляет CronJob, который запускает olivares dr backup — зашифрованный, безопасный для непрерывности ledger пакет (снимок хранилища + ключи подписи, запечатанные под вашим KEK + манифест chain-tip по каждому арендатору):

Окно терминала
kubectl create secret generic dr-kek --from-literal=passphrase='<strong passphrase>'
helm upgrade olivares deploy/helm/olivares --reuse-values \
--set backup.enabled=true \
--set backup.kekSecret=dr-kek \
--set postgres.adminDsnKey=admin-dsn # на Postgres ОБЯЗАТЕЛЕН вместе с backup

С core.engine=postgres чарт отказывается рендериться без postgres.adminDsnKey, и это жёсткий отказ по существу: pg_dump резервной копии удерживает row_security=off и аварийно завершается под ролью приложения на таблицах с FORCE ROW LEVEL SECURITY. CronJob, подключённый к DSN приложения, падал бы при каждом запуске — резервной копии не было бы вообще (речь не о «тихом захвате части строк»).

Значения по умолчанию: каждые 6 часов (backup.schedule задаёт ваш RPO), 14-дневное локальное хранение, выделенный PVC назначения. Зеркалируйте назначение вне площадки и храните KEK отдельно от пакетов — резервная копия в том же кластере не является аварийным восстановлением. Тренируйте восстановление через olivares dr verify; полная процедура описана в резервном копировании и восстановлении.

5. DaemonSet коллекторов (распределённый приём данных)

Заголовок раздела «5. DaemonSet коллекторов (распределённый приём данных)»

Для распределённой топологии DaemonSet коллекторов запускает коннекторы источников на каждом узле и отправляет наблюдения в core по gRPC — у коллекторов нет входящего слушателя. Чарт требует токен приёма данных и принимает опциональный материал mTLS:

Окно терминала
helm upgrade olivares deploy/helm/olivares --reuse-values \
--set collectors.enabled=true \
--set collectors.ingestTokenSecret=olivares-ingest-token # ingest:write bearer token

Передайте коллекторам их источники через collectors.sourcesConfig (тот же JSON источников, что и везде), и включите mTLS с проверкой клиентского сертификата для канала коллектор→core через tls.grpcClientCaSecret — см. укрепление безопасности.

Включите serviceMonitor, если у вас запущен Prometheus operator; в любом случае движок предоставляет /metrics без аутентификации (он не несёт данных арендатора), а репозиторий поставляет готовые правила алертов. См. мониторинг с Prometheus.