217 lines
18 KiB
Markdown
217 lines
18 KiB
Markdown
# Конфигурация проекта inspections-backend
|
||
|
||
Документ описывает все переменные окружения и способы конфигурирования сервиса.
|
||
|
||
## Способы конфигурирования
|
||
|
||
Сервис настраивается **только через переменные окружения**. Разбор выполняется в `src/config.py` через библиотеку [`pydantic-settings`](https://docs.pydantic.dev/latest/concepts/pydantic_settings/) (класс `Config` и вложенные `*Config`).
|
||
|
||
Особенности разбора:
|
||
|
||
- у приложения **нет единого общего префикса** — каждая секция задаётся собственным `env_prefix` в своём `SettingsConfigDict` (напр. `HTTP_APP_`, `DATABASE_`, `KAFKA_`, `OTEL_`, `JWT_AUTH_`, `NOTIFICATIONS_`, `SAREX_BACKEND_`, `EAV_`, `WORKFLOWS_`, `MOBILE_APP_`);
|
||
- две переменные верхнего уровня (`DEBUG`, `SERVICE_URL`) читаются без префикса;
|
||
- вложенности через разделитель нет — плоские имена вида `<PREFIX><FIELD>`, напр. `DATABASE_HOST` → `database.host`;
|
||
- почти у всех полей есть значения по умолчанию, поэтому отсутствие переменной обычно не приводит к ошибке старта — берётся дефолт из кода. В таблицах ниже приведены дефолты из `src/config.py`.
|
||
|
||
Отдельного конфиг-файла (yaml/toml) у приложения нет. Часовой пояс приложения зафиксирован в коде: `app_timezone = ZoneInfo("Europe/Moscow")`.
|
||
|
||
Источники переменных по способам запуска:
|
||
|
||
| Способ запуска | Откуда берутся переменные |
|
||
| --- | --- |
|
||
| Локально (uv) | `Makefile` через `SET_ENV` делает `set -a; source .env; set +a` перед запуском команд. Шаблон переменных — `.env.template` (в репозитории; `.env*` в `.gitignore`, кроме `.env.template`) |
|
||
| Docker | `docker/http/Dockerfile` и `docker/kafka/Dockerfile` фиксируют `PYTHONPATH=src` и `PICCOLO_CONF=db.config`; прикладные переменные пробрасываются рантаймом (k8s) |
|
||
| Kubernetes (Helm) | `.helm/values.yaml`: блоки `envs` (обычные значения) и `secretEnvs` (значения из k8s-секретов) для сервисов `api` и `kafka-app` |
|
||
| CI/CD (GitLab) | `.gitlab-ci.yml`: переменные пайплайна (`workflow.rules`), сборка образа и деплой универсального чарта |
|
||
|
||
Способы запуска процессов:
|
||
|
||
| Команда (`Makefile`) | Точка входа | Назначение |
|
||
| --- | --- | --- |
|
||
| `make run` | `src/cmd/http/main.py` | HTTP API (uvicorn, `app.http:create_app`, `factory=True`) |
|
||
| — (kafka-consumer) | `src/cmd/kafka/main.py` | Обработчик Kafka-событий (FastStream) |
|
||
| `make migrate` | `piccolo migrations forwards all` | Применение миграций Piccolo |
|
||
| `make migrations` | `piccolo migrations new inspections --auto` | Генерация новой миграции |
|
||
| `make sync_eav` | `src/cmd/scripts/sync_eav.py` | Разовая синхронизация EAV |
|
||
| `make playground` | `piccolo playground run` | Локальный playground Piccolo (sqlite) |
|
||
| `make format` / `make format-check` | `ruff` | Форматирование/проверка кода |
|
||
|
||
Порядок запуска в контейнере HTTP (`docker/http/entrypoint.sh`): сначала выполняются миграции (`piccolo migrations forwards all`), затем стартует `src/cmd/http/main.py`. Контейнер kafka-consumer (`docker/kafka/entrypoint.sh`) запускает только `src/cmd/kafka/main.py` (миграции не применяет).
|
||
|
||
## Переменные приложения
|
||
|
||
В столбце «Переменная» указано полное имя (префикс + поле). Дефолт `—` означает, что значения по умолчанию у поля нет.
|
||
|
||
### App (верхний уровень)
|
||
|
||
| Переменная | Тип | Значение по умолчанию | Назначение |
|
||
| --- | --- | --- | --- |
|
||
| `DEBUG` | bool | `True` | Режим отладки: логирование SQL-запросов Piccolo, `reload=True` у uvicorn, непродакшн-режим админки |
|
||
| `SERVICE_URL` | string | `https://stage.sarex.io` | Внешний базовый URL Sarex, используется при формировании ссылок (уведомления, экспорт) |
|
||
|
||
### HTTP App (`HTTP_APP_*`)
|
||
|
||
| Переменная | Тип | Значение по умолчанию | Назначение |
|
||
| --- | --- | --- | --- |
|
||
| `HTTP_APP_HOST` | string | `0.0.0.0` | Адрес прослушивания |
|
||
| `HTTP_APP_PORT` | int | `8000` | Порт |
|
||
| `HTTP_APP_ROOT_PATH` | string | `""` | Root path (префикс за реверс-прокси, напр. `/inspections`) |
|
||
| `HTTP_APP_WORKERS` | int | `1` | Число воркеров uvicorn |
|
||
| `HTTP_APP_ADMIN_ENABLE` | bool | `True` | Монтировать ли Piccolo-admin по пути `/admin/` |
|
||
|
||
### Database (`DATABASE_*`)
|
||
|
||
PostgreSQL через Piccolo (`PostgresEngine`).
|
||
|
||
| Переменная | Тип | Значение по умолчанию | Назначение |
|
||
| --- | --- | --- | --- |
|
||
| `DATABASE_HOST` | string | `postgres` | Хост PostgreSQL |
|
||
| `DATABASE_PORT` | int | `5432` | Порт PostgreSQL |
|
||
| `DATABASE_NAME` | string | `postgres` | Имя базы данных |
|
||
| `DATABASE_USER` | string | `postgres` | Пользователь БД |
|
||
| `DATABASE_PASSWORD` | string | `postgres` | Пароль пользователя БД |
|
||
|
||
### Kafka (`KAFKA_*`)
|
||
|
||
Используется FastStream (`KafkaBroker`). Продюсер — в HTTP-приложении (публикация событий инспекций), консьюмер — отдельный процесс (`kafka-app`), подписан на топик EAV-ассетов.
|
||
|
||
| Переменная | Тип | Значение по умолчанию | Назначение |
|
||
| --- | --- | --- | --- |
|
||
| `KAFKA_HOST` | string | `""` | Bootstrap-сервер (`bootstrap_servers=[host]`) |
|
||
| `KAFKA_USERNAME` | string | `""` | Пользователь (SASL) |
|
||
| `KAFKA_PASSWORD` | string | `""` | Пароль (SASL) |
|
||
| `KAFKA_SSL_CERT` | string | `""` | CA-сертификат как строка (`cadata`). Если задан — HTTP-приложение подключается по `SASLScram512` поверх TLS, иначе без SSL |
|
||
| `KAFKA_SSL_CAFILE` | string | `""` | Путь к CA-файлу (`cafile`). Если задан — kafka-consumer подключается по `SASLScram512` поверх TLS, иначе без SSL |
|
||
| `KAFKA_EAV_ASSETS_TOPIC` | string | `""` | Топик событий EAV-ассетов, на который подписан consumer |
|
||
|
||
> Механизм безопасности отличается между процессами: HTTP-приложение (`app/http.py`) смотрит на `KAFKA_SSL_CERT` (строка сертификата), а kafka-consumer (`app/kafka.py`) — на `KAFKA_SSL_CAFILE` (путь к файлу).
|
||
|
||
### OpenTelemetry (`OTEL_*`)
|
||
|
||
| Переменная | Тип | Значение по умолчанию | Назначение |
|
||
| --- | --- | --- | --- |
|
||
| `OTEL_ENABLE` | bool | `False` | Включить трейсинг/структурированное логирование. При `True` отключается `access_log` uvicorn |
|
||
| `OTEL_URL` | string | `http://signoz-otel-collector-external.signoz.svc.cluster.local:4317` | Адрес OTLP-коллектора |
|
||
| `OTEL_SERVICE_NAME` | string | `inspections-backend.inspections-stage` | Имя сервиса в трейсах |
|
||
| `OTEL_INSECURE` | bool | `True` | Небезопасное (без TLS) подключение к коллектору |
|
||
|
||
### Auth (`JWT_AUTH_*`)
|
||
|
||
| Переменная | Тип | Значение по умолчанию | Назначение |
|
||
| --- | --- | --- | --- |
|
||
| `JWT_AUTH_ENABLE` | bool | `False` | Подключать ли middleware `TokenUserMiddleware`. При `False` используется дефолтный пользователь из `entity/context.py` (для локальной разработки) |
|
||
|
||
> Middleware декодирует JWT **без проверки подписи** (`verify_signature: False`). При наличии заголовка `identity` полезная нагрузка берётся из него (метаданные Zitadel), иначе — из `authorization`. Роуты `/docs/`, `/openapi.json/`, `/admin/`, `/internal/` исключены из проверки.
|
||
|
||
### Notifications (`NOTIFICATIONS_*`)
|
||
|
||
| Переменная | Тип | Значение по умолчанию | Назначение |
|
||
| --- | --- | --- | --- |
|
||
| `NOTIFICATIONS_ENABLE` | bool | `False` | Включить отправку уведомлений об инспекциях |
|
||
| `NOTIFICATIONS_EMAIL_FROM` | string | `hello@sarex.io` | Адрес отправителя писем |
|
||
|
||
### Sarex backend (`SAREX_BACKEND_*`)
|
||
|
||
HTTP-клиент основного бэкенда Sarex (данные пользователей и т.п.).
|
||
|
||
| Переменная | Тип | Значение по умолчанию | Назначение |
|
||
| --- | --- | --- | --- |
|
||
| `SAREX_BACKEND_URL` | string | `https://stage.sarex.io` | Базовый URL |
|
||
| `SAREX_BACKEND_TIMEOUT` | int | `30` | Таймаут запроса (сек) |
|
||
| `SAREX_BACKEND_AUTH` | string (base64) | `base64(login:password)` | Basic-auth в виде base64(`login:password`) |
|
||
|
||
### EAV (`EAV_*`)
|
||
|
||
HTTP-клиент сервиса атрибутов (EAV).
|
||
|
||
| Переменная | Тип | Значение по умолчанию | Назначение |
|
||
| --- | --- | --- | --- |
|
||
| `EAV_URL` | string | `https://stage-api.sarex.io/eav` | Базовый URL |
|
||
| `EAV_TIMEOUT` | int | `30` | Таймаут запроса (сек) |
|
||
|
||
### Workflows (`WORKFLOWS_*`)
|
||
|
||
HTTP-клиент сервиса процессов; используется, в т.ч. для запуска отправки email.
|
||
|
||
| Переменная | Тип | Значение по умолчанию | Назначение |
|
||
| --- | --- | --- | --- |
|
||
| `WORKFLOWS_URL` | string | `http://workflows-api-service.processing-stage` | Базовый URL |
|
||
| `WORKFLOWS_TIMEOUT` | int | `30` | Таймаут запроса (сек) |
|
||
| `WORKFLOWS_EMAIL_DOCKER_IMAGE` | string | `cr.yandex/crp3ccidau046kdj8g9q/notification:email` | Docker-образ шага отправки email |
|
||
|
||
### Mobile App (`MOBILE_APP_*`)
|
||
|
||
Значения отдаются эндпоинтом `GET /api/v1/mobile-app/version/`.
|
||
|
||
| Переменная | Тип | Значение по умолчанию | Назначение |
|
||
| --- | --- | --- | --- |
|
||
| `MOBILE_APP_CURRENT_VERSION` | string | `""` | Текущая версия |
|
||
| `MOBILE_APP_RECOMMENDED_VERSION` | string | `""` | Рекомендуемая версия |
|
||
| `MOBILE_APP_REQUIRED_VERSION` | string | `""` | Минимально требуемая версия |
|
||
|
||
## Переменные инфраструктуры и сборки
|
||
|
||
Не читаются кодом приложения через `pydantic-settings`, но участвуют в запуске/сборке/деплое.
|
||
|
||
| Переменная | Где используется | Назначение |
|
||
| --- | --- | --- |
|
||
| `PYTHONPATH=src` | `.env.template`, `Dockerfile` | Корень пакета приложения |
|
||
| `PICCOLO_CONF=db.config` | `.env.template`, `Dockerfile` | Модуль конфигурации Piccolo (`APP_REGISTRY`, `DB`, `ADMIN_ASGI_APP`) |
|
||
|
||
## Переменные из Helm-чарта (`.helm/values.yaml`)
|
||
|
||
Чарт — обёртка над зависимостью `universal-chart` (`oci://cr.yandex/crp3ccidau046kdj8g9q/charts`, версия `0.1.7`). Описаны два сервиса: `api` (HTTP) и `kafka-app` (consumer), у каждого свои блоки `envs` и `secretEnvs`. Значения различаются по окружениям через ключи `_default`/`stage`/`preprod`/`production`.
|
||
|
||
Обычные значения (`envs`) содержат те же переменные приложения, что и выше (различаются `SERVICE_URL`, `EAV_URL`, `WORKFLOWS_URL`, `OTEL_*`, `KAFKA_EAV_ASSETS_TOPIC`, `HTTP_APP_ROOT_PATH=/inspections`, `HTTP_APP_WORKERS=3`, `JWT_AUTH_ENABLE=true`, `NOTIFICATIONS_ENABLE` и т.п.). Отличия от дефолтов кода: в проде `DEBUG=false`, `OTEL_ENABLE=true`, `JWT_AUTH_ENABLE=true`.
|
||
|
||
Значения из секретов (`secretEnvs`, монтируются как env через `secretKeyRef`):
|
||
|
||
| Переменная | Секрет (`_default` / `stage`) | Ключ (`secretKey`) |
|
||
| --- | --- | --- |
|
||
| `DATABASE_USER` | `ya-pg-secret` / `inspections-postgresql-secret` | `username` |
|
||
| `DATABASE_PORT` | `ya-pg-secret` / `inspections-postgresql-secret` | `port` |
|
||
| `DATABASE_NAME` | `ya-pg-secret` / `inspections-postgresql-secret` | `database` |
|
||
| `DATABASE_HOST` | `ya-pg-secret` / `inspections-postgresql-secret` | `host` |
|
||
| `DATABASE_PASSWORD` | `ya-pg-secret` / `inspections-postgresql-secret` | `password` |
|
||
| `KAFKA_HOST` | `yc-kafka-secret` / `inspections-kafka-secret` | `host` |
|
||
| `KAFKA_USERNAME` | `yc-kafka-secret` / `inspections-kafka-secret` | `username` |
|
||
| `KAFKA_PASSWORD` | `yc-kafka-secret` / `inspections-kafka-secret` | `password` |
|
||
| `KAFKA_SSL_CERT` | `inspections-kafka-secret` | `cert` |
|
||
| `SAREX_BACKEND_AUTH` | `sarex-backend-auth-secret` | `key` |
|
||
|
||
Помимо env, у сервиса `kafka-app` смонтирован CA-сертификат Yandex как файл `/usr/local/share/ca-certificates/Yandex/YandexInternalRootCA.crt` (секрет `yc-ch-certificate`, ключ `certificate`) — на него указывает `KAFKA_SSL_CAFILE`.
|
||
|
||
Прочие значения чарта (не переменные приложения): `deployment.*` (имя, реплики, ресурсы, probes), `image.*`, `service.*`, `imagePullSecrets`, у `kafka-app` — `command` (`python src/cmd/kafka/main.py`) и `volumes`.
|
||
|
||
## Переменные в CI (`.gitlab-ci.yml`)
|
||
|
||
Пайплайн подключает шаблоны из `generic/common-ci` (`common-security-scan.yaml`, `universal-pipeline.yaml`, ref `apps-business`) и переключает окружение по ветке/тегу через `workflow.rules`:
|
||
|
||
| Условие | STAND | Namespace | Release / Chart |
|
||
| --- | --- | --- | --- |
|
||
| ветка `stage` | `stage` | `proc` | `inspections-backend` |
|
||
| ветка `master` | `preprod` | `inspections-preprod` | `inspections-backend` |
|
||
| тег (`CI_COMMIT_TAG`) | `production` | `inspections-prod` | `sarex-inspections` |
|
||
| `merge_request_event` | — | — | сборка образа отключена (`ENABLE_BUILD_IMAGE=false`) |
|
||
|
||
Ключевые переменные пайплайна: `SERVICE_NAME=inspections-backend`, `DOCKERFILE_PATH=./docker/http/Dockerfile`, `CHART_VERSION`, `K8S_HUSTLER_BRANCH`, `HELM_SET_ARGS` (проброс `image.name`, `global.env`, метаданных коммита для сервисов `api` и `kafka-app`). Job `lint` прогоняет `ruff check` и `ruff format --check` на образе `uv 0.7.13 / python3.13`.
|
||
|
||
## Замечания
|
||
|
||
- Приложение **не загружает `.env` автоматически** — переменные экспортируются в окружение (в `Makefile` — через `set -a; source .env; set +a`, в k8s — через env-блоки чарта).
|
||
- Аутентификация в middleware декодирует JWT **без проверки подписи**; безопасность обеспечивается сетевым слоем/ingress. При `JWT_AUTH_ENABLE=false` активен захардкоженный дефолтный пользователь (`entity/context.py`), пригодный только для локальной разработки.
|
||
- Большинство полей конфигурации имеют дефолты — при отсутствии переменной сервис стартует со значением из кода. Для реального окружения значения задаются в `.helm/values.yaml`.
|
||
- Для экспорта поддерживается единственный формат — `xlsx` (`InspectionExportType`).
|
||
|
||
## Минимальный набор для локального запуска
|
||
|
||
Скопировать `.env.template` в `.env`, поднять PostgreSQL и (при необходимости обработки событий) Kafka, применить миграции (`make migrate`) и запустить API (`make run`). Минимально стоит задать:
|
||
|
||
- `DEBUG`, `SERVICE_URL`
|
||
- `HTTP_APP_HOST`, `HTTP_APP_PORT`
|
||
- `DATABASE_HOST`, `DATABASE_PORT`, `DATABASE_NAME`, `DATABASE_USER`, `DATABASE_PASSWORD`
|
||
- `JWT_AUTH_ENABLE=false` (для дебага без токена)
|
||
- `KAFKA_*` (если нужен consumer/публикация событий)
|
||
- `SAREX_BACKEND_*`, `EAV_*`, `WORKFLOWS_*` (для интеграций)
|
||
- `OTEL_ENABLE=false` локально
|