iac/apps/documentations/dps-message-hub.CONFIGURATION.md

157 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Конфигурация проекта dps-message-hub
# Версия: 0.1.0
Документ описывает все переменные окружения и способы конфигурирования сервиса.
`dps-message-hub` (`dps_message_hub`) — это Kafka-воркер на базе [FastStream](https://faststream.airt.ai/), потребляющий сообщения об изменении ассетов и обновляющий данные разметки (`markup_event`) в PostgreSQL домена «documentations». HTTP API у сервиса нет.
> Это отдельный сервис, не путать с приложением `message-hub` (домен `planning`): у них разные префиксы переменных, набор интеграций и назначение.
## Способы конфигурирования
Сервис настраивается **только через переменные окружения**. Разбор выполняется в `src/dps_message_hub/infra/config.py` через библиотеку [`pydantic-settings`](https://docs.pydantic.dev/latest/concepts/pydantic_settings/) (класс `AppSettings(BaseSettings)`).
Особенности разбора (`SettingsConfigDict`):
- `env_prefix="DPS_MESSAGE_HUB_"` — все переменные приложения начинаются с этого префикса;
- `env_nested_delimiter="__"` — вложенные секции задаются двойным подчёркиванием, напр. `DPS_MESSAGE_HUB_DOCUMENTATION_DB__HOST``documentation_db.host`;
- `env_ignore_empty=False` — пустая строка считается заданным значением (не игнорируется);
- `frozen=True` — объект настроек неизменяем после инициализации.
Настройки разбиты на три вложенные секции (модели `pydantic.BaseModel`), читаемые одним классом `AppSettings`:
- `app` (`App`) — префикс `DPS_MESSAGE_HUB_APP__`;
- `documentation_db` (`Database`) — префикс `DPS_MESSAGE_HUB_DOCUMENTATION_DB__`;
- `kafka` (`Kafka`) — префикс `DPS_MESSAGE_HUB_KAFKA__`.
Класс `Settings` (`src/dps_message_hub/infra/config.py`) — синглтон (`wiring.SingletonMeta`) поверх `AppSettings`, отдаёт настройки через свойство `.settings`.
Отдельного конфиг-файла (yaml/toml) у приложения нет. У классов настроек **не задан** `env_file`, поэтому файл `.env` автоматически не загружается — переменные нужно экспортировать в окружение процесса самостоятельно (`make config` лишь копирует `.example.env``.env` как шаблон), либо пробрасывать их в контейнер через `--env-file` (см. `Makefile`, цель `container-run`).
Источники переменных по способам запуска:
| Способ запуска | Откуда берутся переменные |
| --- | --- |
| Локально (бинарник) | Переменные окружения процесса. `make config` копирует `.example.env``.env`, но приложение **не загружает `.env` автоматически** — экспортируйте сами, напр. `set -a && . ./.env && set +a` |
| Локально (контейнер) | `Makefile`: цель `container-run` пробрасывает переменные через `--env-file .env` |
| Kubernetes (Helm) | `.helm/values.yaml`: блок `universal-chart.services.api.envs` (обычные значения) и `secretEnvs` (значения из k8s-секретов); базовый чарт — `universal-chart` (`oci://.../charts`, версия `0.1.7`) |
| CI/CD (GitLab) | `.gitlab-ci.yml`: переменные пайплайна (`workflow.rules`) и `HELM_SET_ARGS` |
Запуск процесса (`scripts/entrypoint.sh`): единый FastStream-процесс с брокером Kafka:
```
faststream run \
--factory \
--workers ${DPS_MESSAGE_HUB_NUM_WORKERS} \
'dps_message_hub.infra.app:get_app'
```
Фабрика `dps_message_hub.infra.app:get_app` (`src/dps_message_hub/infra/app.py`) собирает `FastStream`-приложение: создаёт `KafkaBroker`, подключает роутер-потребитель топика `assets` и открывает пул соединений PostgreSQL в lifespan. Отдельных точек входа для воркеров/крон-задач нет — `pyproject.toml` не содержит `[project.scripts]`.
## Переменные приложения
Дефолт `—` означает, что значение обязательно (иначе ошибка старта настроек).
### Приложение (`DPS_MESSAGE_HUB_APP__*`) — класс `App`
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `DPS_MESSAGE_HUB_APP__LOG_LEVEL` | enum (`LogLevel`) | `INFO` | Уровень логирования. Допустимо: `CRITICAL`/`FATAL`/`ERROR`/`WARNING`/`WARN`/`INFO`/`DEBUG`/`NOTSET` |
| `DPS_MESSAGE_HUB_APP__IS_DEV` | bool | `False` | Признак dev-режима. Поле объявлено в настройках, но в текущем коде не используется |
| `DPS_MESSAGE_HUB_APP__BROKER_TYPE` | enum (`BrokerType`) | `—` (обязательно) | Тип брокера сообщений. Поддерживается только значение `kafka` |
### База данных PostgreSQL (`DPS_MESSAGE_HUB_DOCUMENTATION_DB__*`) — класс `Database`
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `DPS_MESSAGE_HUB_DOCUMENTATION_DB__HOST` | string | `—` | Хост PostgreSQL |
| `DPS_MESSAGE_HUB_DOCUMENTATION_DB__PORT` | int | `—` | Порт PostgreSQL |
| `DPS_MESSAGE_HUB_DOCUMENTATION_DB__USER` | string | `—` | Пользователь БД |
| `DPS_MESSAGE_HUB_DOCUMENTATION_DB__PASSWORD` | string | `—` | Пароль пользователя БД |
| `DPS_MESSAGE_HUB_DOCUMENTATION_DB__NAME` | string | `—` | Имя базы данных |
| `DPS_MESSAGE_HUB_DOCUMENTATION_DB__ENABLE_SSL` | bool | `—` | Включить TLS-подключение к БД |
| `DPS_MESSAGE_HUB_DOCUMENTATION_DB__SSL_MODE` | enum (`verify-full`/`verify-ca`/`""`) | `—` | Режим проверки TLS (параметр `sslmode` DSN). При `ENABLE_SSL=true` не должно быть пустым |
| `DPS_MESSAGE_HUB_DOCUMENTATION_DB__SSL_ROOT_CERT_PATH` | string | `—` | Путь к CA-сертификату (параметр `sslrootcert` DSN). При `ENABLE_SSL=true` не должно быть пустым |
Валидатор `check_ssl_options_configured_when_ssl_enabled`: если `ENABLE_SSL=true`, то `SSL_MODE` и `SSL_ROOT_CERT_PATH` обязаны быть непустыми, иначе ошибка старта. Итоговый DSN собирается в вычисляемом поле `documentation_db.uri` (`postgresql://user:password@host:port/name`, при SSL добавляются `?sslmode=...&sslrootcert=...`).
### Kafka (`DPS_MESSAGE_HUB_KAFKA__*`) — класс `Kafka`
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `DPS_MESSAGE_HUB_KAFKA__HOST` | string | `—` | Хост брокера Kafka |
| `DPS_MESSAGE_HUB_KAFKA__PORT` | int | `—` | Порт брокера Kafka |
| `DPS_MESSAGE_HUB_KAFKA__USERNAME` | string | `—` | Логин SASL (`SCRAM-SHA-512`) |
| `DPS_MESSAGE_HUB_KAFKA__PASSWORD` | string | `—` | Пароль SASL (`SCRAM-SHA-512`) |
| `DPS_MESSAGE_HUB_KAFKA__SSL_CAFILE` | string \| null | `None` | Путь к CA-сертификату для SSL-контекста. Если задан — используется `SASL_SSL`, иначе SASL без TLS |
| `DPS_MESSAGE_HUB_KAFKA__TOPICS` | dict (JSON) → `KafkaTopics` | `—` | Соответствие логического топика реальному имени в Kafka. Обязателен ключ `assets`, напр. `{"assets": "assets_broadcast"}` |
Формирование параметров подключения (`src/dps_message_hub/infra/app.py`): адрес брокера — вычисляемое поле `kafka.uri` (`host:port`). Безопасность через `faststream.security.SASLScram512`:
- если заданы `USERNAME` и `PASSWORD` и `SSL_CAFILE` пуст — `SASLScram512(..., use_ssl=False)`;
- если задан `SSL_CAFILE``SASLScram512(..., ssl_context=create_ssl_context(cafile=...))`.
## Переменные инфраструктуры, сборки и запуска
Не читаются классами настроек приложения, но участвуют в запуске/сборке/деплое.
| Переменная | Где используется | Назначение |
| --- | --- | --- |
| `DPS_MESSAGE_HUB_NUM_WORKERS` | `scripts/entrypoint.sh`, Helm `envs` | Число воркеров FastStream (`faststream run --workers`). В Helm `_default: '2'` |
| `DPS_MESSAGE_HUB_PYTHON_IMAGE_NAME` | `Dockerfile` (ARG) | Базовый образ Python (по умолчанию `python`) |
| `DPS_MESSAGE_HUB_PYTHON_IMAGE_TAG` | `Dockerfile` (ARG) | Тег базового образа (по умолчанию `3.13-slim`) |
| `PIP_INDEX_URL`, `PIP_TRUSTED_HOST` | `Dockerfile` (ARG) | Индекс/доверенный хост pip при сборке |
Сборка (`Dockerfile`): многостадийная — стадия `builder` собирает wheel'ы из `requirements/requirements.txt`, стадия `runner` ставит их, копирует `src/` и устанавливает пакет (`pip install . --no-deps`); процесс запускается непривилегированным пользователем `dps_message_hub`. Целевая версия Python — `3.13` (`.python-version`, `requires-python >=3.13`).
## Переменные из Helm-чарта (`.helm/values.yaml`)
Сервис деплоится через зависимость `universal-chart` (`.helm/Chart.yaml`, версия `0.1.7`). Настраивается один сервис — `services.api` (тип нагрузки — deployment, `replicaCount._default: 1`). HTTP-`service` и `ingress` отключены, health-пробы (`liveness`/`readiness`, путь `/ping`) — `enabled: false` (у сервиса нет HTTP-эндпоинтов).
Обычные значения (блок `services.api.envs`) различаются по окружениям (`_default`/`stage`/`preprod`/`production`) адресами БД и Kafka, именем БД и именами топиков. В Helm дополнительно заданы (отсутствуют в `.example.env`): `DPS_MESSAGE_HUB_KAFKA__HOST`, `DPS_MESSAGE_HUB_KAFKA__PORT` (`9091`), `DPS_MESSAGE_HUB_KAFKA__SSL_CAFILE` (`/opt/config/ca.crt`), `DPS_MESSAGE_HUB_DOCUMENTATION_DB__ENABLE_SSL=true`, `SSL_MODE=verify-full`, `SSL_ROOT_CERT_PATH=/opt/config/ca.crt`.
Значения из секретов (блок `secretEnvs`, монтируются как env через `secretKeyRef`):
| Переменная | Секрет (`_default` / `stage`) | Ключ (`secretKey`) |
| --- | --- | --- |
| `DPS_MESSAGE_HUB_DOCUMENTATION_DB__USER` | `ya-pg-secret` / `documentations-postgresql-secret` | `username` |
| `DPS_MESSAGE_HUB_DOCUMENTATION_DB__PASSWORD` | `ya-pg-secret` / `documentations-postgresql-secret` | `password` |
| `DPS_MESSAGE_HUB_KAFKA__USERNAME` | `kafka-secret` | `username` |
| `DPS_MESSAGE_HUB_KAFKA__PASSWORD` | `kafka-secret` | `password` |
Помимо env, чарт монтирует CA-сертификат Яндекса из `ConfigMap` `ya-ca-cert` (ключ `ca.crt`) как файл `/opt/config/ca.crt` (том `cm-ya-ca-cert`, `readOnly`) — на него указывают `DPS_MESSAGE_HUB_KAFKA__SSL_CAFILE` и `DPS_MESSAGE_HUB_DOCUMENTATION_DB__SSL_ROOT_CERT_PATH`.
## Переменные в CI (`.gitlab-ci.yml`)
Пайплайн подключает общие шаблоны из `generic/common-ci` (`common-security-scan.yaml`, `universal-pipeline.yaml`, ref `apps-business`) и переключает окружение по ветке/тегу через `workflow.rules`:
| Условие | STAND | NAMESPACE | CHART_VERSION | K8S_HUSTLER_BRANCH |
| --- | --- | --- | --- | --- |
| MR (`merge_request_event`) | — | — | — | сборка образа отключена (`ENABLE_BUILD_IMAGE=false`) |
| ветка `stage` | `stage` | `documentations` | `0.0.1-stage` | `stage` |
| ветка `master` | `preprod` | `documentations-preprod` | `0.0.1-preprod` | `preprod` |
| тег (`CI_COMMIT_TAG`) | `prod` | `documentations-prod` | `0.0.1-prod` | `master` |
Ключевые переменные пайплайна: `SERVICE_NAME=dps-message-hub`, `DOCKERFILE_PATH=Dockerfile`, `CI_TRIGGER_SOURCE=app`, `RELEASE_NAME=dps-message-hub`, `CHART_NAME=dps-message-hub`, флаги `ENABLE_BUILD_CHART`/`ENABLE_BUILD_IMAGE`/`ENABLE_DEPLOY`, `HELM_SET_ARGS` (`--set universal-chart...`). Отдельные job'ы `format` (`ruff format --diff`) и `lint` (`ruff check`) на образе `python:3.13-slim`.
## Замечания и потенциальные проблемы
- Приложение **не читает `.env`** автоматически (в `SettingsConfigDict` нет `env_file`). `make config` только создаёт `.env` из шаблона — переменные нужно экспортировать самому либо передавать контейнеру через `--env-file`.
- Большинство полей БД и Kafka **обязательны** (без дефолтов): при пустом окружении настройки не пройдут валидацию и сервис не стартует. Единственные необязательные — `APP__LOG_LEVEL`, `APP__IS_DEV`, `KAFKA__SSL_CAFILE`.
- `DPS_MESSAGE_HUB_APP__BROKER_TYPE` обязателен; поддерживается только `kafka` (иных веток в `match` нет). При другом значении брокер не будет создан.
- При `ENABLE_SSL=true` обязательно задавать `SSL_MODE` и `SSL_ROOT_CERT_PATH`, иначе валидатор настроек прервёт старт.
- `DPS_MESSAGE_HUB_KAFKA__TOPICS` обязан содержать ключ `assets` (модель `KafkaTopics`); прочие ключи игнорируются, отсутствие `assets` — ошибка старта.
- Поле `APP__IS_DEV` присутствует в настройках, но в текущем коде нигде не задействовано.
- Обработка Kafka-сообщений идёт с `auto_commit=False` и middleware `Retry` (`src/dps_message_hub/interface/middleware.py`), которая повторяет обработку **бесконечно** с экспоненциальной задержкой (до `1<<10 = 1024` сек) — «отравленное» сообщение может заблокировать партицию.
## Минимальный набор для локального запуска
Kafka и Zookeeper поднимаются через `Makefile` (цели `run-deps`/`run-zookeeper`/`run-kafka`); PostgreSQL — внешний. Минимально нужно задать:
- `DPS_MESSAGE_HUB_APP__BROKER_TYPE=kafka`;
- `DPS_MESSAGE_HUB_DOCUMENTATION_DB__HOST`, `__PORT`, `__USER`, `__PASSWORD`, `__NAME`, `__ENABLE_SSL` (для локали `false`), `__SSL_MODE`, `__SSL_ROOT_CERT_PATH` (при `ENABLE_SSL=false` можно пустыми);
- `DPS_MESSAGE_HUB_KAFKA__HOST`, `__PORT`, `__USERNAME`, `__PASSWORD`, `__TOPICS` (JSON с ключом `assets`);
- `DPS_MESSAGE_HUB_NUM_WORKERS` (для `entrypoint.sh`).
Локальный запуск: `make run` (через `entrypoint.sh`) либо `make run-dev` (`faststream run --factory --reload dps_message_hub.infra.app:get_app`). Готовые значения-примеры приведены в `dps-message-hub.env.example` рядом с этим документом.