iac/apps/measurements/CONFIGURATION.md

151 lines
16 KiB
Markdown
Raw Permalink 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.

# Конфигурация measurements
Документ описывает все переменные окружения и способы конфигурирования сервиса репозитория `measurements`:
- **measurements** — HTTP-сервис на FastAPI (`src/measurements`), запускается через gunicorn/uvicorn (`entrypoint.sh`, `measurements.main:app`). Считает измерения по растрам (GeoTIFF), читая их напрямую из S3/MinIO через GDAL (`vsis3`). Отдельного воркера у сервиса нет.
## Способы конфигурирования
Сервис настраивается **только через переменные окружения**. Разбор выполняется в `src/measurements/config.py` через библиотеку [`pydantic-settings`](https://docs.pydantic.dev/latest/concepts/pydantic_settings/): классы `LoggerSettings`, `SentrySettings`, `DjangoSettings`, `ApplicationSettings`, `TraceSettings`, `S3CredentialsSettings`, `Store`. Отдельного конфиг-файла (yaml/toml) у приложения нет.
Каждый класс задаёт свой префикс через `class Config: env_prefix` (`LOG_`, `SENTRY_`, `DJANGO_`, `TRACING_`, `S3_`); у `ApplicationSettings` префикса нет — её поля читаются по имени напрямую (`AUTH`, `SHOW_UI`, `USE_SENTRY` и т.п.). Почти все переменные имеют значения по умолчанию, поэтому обязательна фактически одна — **`S3_JSON_SETTINGS`**: её отсутствие приводит к `ValueError` в `S3CredentialsSettings.from_env()` и процесс не стартует.
Источники переменных по способам запуска:
| Способ запуска | Откуда берутся переменные |
| --- | --- |
| Локально (docker-compose) | `docker-compose.yaml` — образ `measurements`, проброс порта `8000:8000`, инлайн `environment: S3_JSON_SETTINGS`. Сервис запускается `entrypoint.sh` (gunicorn, 4 воркера, uvicorn worker, таймаут 240) |
| Kubernetes — собственный Helm-чарт репозитория | `.helm/values.yaml` (universal-chart, dependency `oci://…/charts`): блок `envs` (обычные значения) и `secretEnvs` (значения из k8s-секретов). Per-env значения через ключи `_default`/`stage`/`preprod`/`production` |
| Kubernetes — этот infra-репозиторий (`iac/apps/measurements`) | `base/` — kustomize-манифесты с инъекцией секрета S3 через **HashiCorp Vault** (annotations `vault.hashicorp.com/*`), обычные переменные заданы инлайн в `env:`. Оверлеи: `yc-k8s-test` (base + патч реплик), `brusnika-stage`/`brusnika-prod` (Flux `HelmRelease` на `universal-chart`, блок `secretEnvs`) |
| CI/CD (GitLab) | `.gitlab-ci.yml` подключает шаблоны `generic/common-ci` (`universal-pipeline.yaml`, ref `apps-business`); в `workflow.rules` задаются переменные пайплайна (`STAND`, `NAMESPACE`, `RELEASE_NAME`, `CHART_NAME`, `CHART_VERSION`, `K8S_HUSTLER_BRANCH`, `HELM_SET_ARGS`, `SERVICE_NAME`, `DOCKERFILE_PATH`) |
**Миграции БД.** Отсутствуют. Сервис не хранит собственное состояние в реляционной БД (`psycopg2` присутствует в зависимостях, но код измерений работает с растрами из S3). Шага миграций в `entrypoint.sh` нет.
---
## measurements (`measurements`)
Переменные читаются набором классов `*Settings` в `config.py`, инстанцируемых на уровне модуля: `settings = ApplicationSettings()`, `store = Store()`, `logger = LoggerSettings().logger`, `tracing_settings = TraceSettings()`.
### S3 / MinIO (обязательно)
Класс `S3CredentialsSettings`. Единственный обязательный источник конфигурации — переменная `S3_JSON_SETTINGS` (JSON-строка). Валидатор `from_env` (`model_validator(mode='before')`) читает её из окружения и при отсутствии выбрасывает `ValueError`. Доступы к S3 используются как boto3-клиентом (список бакетов), так и GDAL (`AWS_S3_ENDPOINT`/`AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY`, драйвер `vsis3`).
| Переменная | Тип | Обяз. | По умолчанию | Назначение |
| --- | --- | --- | --- | --- |
| `S3_JSON_SETTINGS` | string (JSON) | да | — | JSON с доступами к S3. Поля: `host`, `login`, `password` (обяз.); `verify` (bool, по умолч. `false`); `buckets` (список; если пуст — бакеты запрашиваются через `list_buckets()`). Пример: `{"host":"https://s3…","login":"…","password":"…","verify":false,"buckets":["measurements"]}` |
> В `host` поддерживаются схемы `http://`/`https://`: при `http://` GDAL переключается на `AWS_HTTPS=NO`, отключает `GDAL_DISABLE_READDIR_ON_OPEN` и `AWS_VIRTUAL_HOSTING`.
### Логирование (префикс `LOG_`)
Класс `LoggerSettings`. Настраивает JSON-логгер (`python-json-logger`).
| Переменная | Тип | Обяз. | По умолчанию | Назначение |
| --- | --- | --- | --- | --- |
| `LOG_LEVEL` | string | нет | `INFO` | Уровень логирования (`INFO`/`DEBUG`/…); неизвестное значение → `INFO` |
| `LOG_FORMAT` | string | нет | JSON-шаблон | Формат строки лога для `JsonFormatter` |
### Приложение (`ApplicationSettings`, без префикса)
Поля читаются по имени напрямую (регистронезависимо). Управляют поведением сервиса и подключением middleware в `main.py`.
| Переменная | Тип | Обяз. | По умолчанию | Назначение |
| --- | --- | --- | --- | --- |
| `AUTH` | bool | нет | `false` | Подключить `CustomAuthenticationMiddleware` (проверка JWT `authorization`/`identity`) |
| `SHOW_UI` | bool | нет | `false` | Включить Swagger/redoc; при `false` `docs_url`/`redoc_url` отключены |
| `USE_SENTRY` | bool | нет | `false` | Инициализировать Sentry SDK и `SentryAsgiMiddleware` |
| `DEBUG` | bool | нет | `false` | Флаг отладки |
| `CLASSIC_MODE` | bool | нет | `true` | Классический режим расчётов |
| `BLOCK_SIZE` | int | нет | `256` | Размер блока обработки растра; участвует в `area_factor` |
| `BLOCK_SIZE_FACTOR` | int | нет | `10` | Множитель площади блока (`area_factor = BLOCK_SIZE_FACTOR × BLOCK_SIZE²`) |
| `CPU_NUMBER` | int | нет | `10` | Число используемых CPU |
> `DEBUG`, `CLASSIC_MODE`, `BLOCK_SIZE`, `BLOCK_SIZE_FACTOR`, `CPU_NUMBER` задаются в конфиге, но в текущих обработчиках напрямую не считываются (в `main.py` используются только `SHOW_UI`, `USE_SENTRY`, `AUTH`). Оставлены как настраиваемые параметры.
### Django / ЛК (префикс `DJANGO_`)
Класс `DjangoSettings`. Используется `CustomAuthenticationMiddleware`/`DjangoUserMiddleware` при включённой авторизации (`AUTH=1`) для запросов к ЛК.
| Переменная | Тип | Обяз. | По умолчанию | Назначение |
| --- | --- | --- | --- | --- |
| `DJANGO_USE` | bool | нет | `true` | Использовать интеграцию с Django |
| `DJANGO_HOST` | string | нет | `https://lk.sarex.io` | Базовый URL Django/ЛК |
| `DJANGO_TIMEOUT` | int | нет | `10` | Таймаут HTTP-запросов к Django, сек |
### Sentry (префикс `SENTRY_`)
Класс `SentrySettings`. Значения передаются в `sentry_sdk.init(**settings.sentry.kwargs)` только при `USE_SENTRY=1`.
| Переменная | Тип | Обяз. | По умолчанию | Назначение |
| --- | --- | --- | --- | --- |
| `SENTRY_DSN` | string | нет | `""` | DSN проекта Sentry |
| `SENTRY_ENVIRONMENT` | string | нет | `production` | Имя окружения в Sentry |
| `SENTRY_TRACES_SAMPLE_RATE` | float | нет | `1.0` | Доля трейсов |
| `SENTRY_SEND_DEFAULT_PII` | bool | нет | `true` | Отправлять PII |
### Трейсинг (OpenTelemetry, префикс `TRACING_`)
Класс `TraceSettings`. Активируется при `TRACING_USE=1` (`fastapi-otel-tools`).
| Переменная | Тип | Обяз. | По умолчанию | Назначение |
| --- | --- | --- | --- | --- |
| `TRACING_USE` | bool | нет | `false` | Включает OTEL-трейсинг, otel-логгер и `OtelMiddleware` |
| `TRACING_HOST` | string | нет | `localhost:4317` | Адрес OTLP-коллектора |
| `TRACING_SERVICE_NAME` | string | нет | `measurements` | Имя сервиса в трейсах |
| `TRACING_INSECURE` | bool | нет | `false` | Небезопасное (без TLS) подключение к коллектору |
> Тип `bool` в pydantic принимает `1`/`0`, `true`/`false`, `yes`/`no`.
---
## Инфраструктурные и вспомогательные переменные
Не читаются кодом приложения, но участвуют в запуске/сборке/деплое.
| Переменная | Где используется | Назначение |
| --- | --- | --- |
| `S3_JSON_FILE` | `.helm/values.yaml` (`envs`) | Путь к файлу с доступами S3 (`/opt/cred_s3.json`). **Кодом не читается** — приложение использует только `S3_JSON_SETTINGS` |
| `SERVICE_NAME`, `DOCKERFILE_PATH`, `BUILD_ARGS`, `CI_TRIGGER_SOURCE` | `.gitlab-ci.yml` (`variables`) | Параметры сборки образа |
| `STAND`, `NAMESPACE`, `RELEASE_NAME`, `CHART_NAME`, `CHART_VERSION`, `K8S_HUSTLER_BRANCH`, `HELM_SET_ARGS` | `.gitlab-ci.yml` (`workflow.rules`) | Параметры пайплайна `universal-pipeline` (деплой чарта per-env: `stage`/`preprod`/`production`) |
---
## Деплой из этого репозитория (`iac/apps/measurements`)
В `base/` используется **kustomize** (не собственный Helm-чарт сервиса). Доступ к S3/MinIO инъектируется агентом **Vault** и подгружается в окружение процесса до старта.
### `base/`
- `deployment.yaml` — единственный Deployment `measurements` (namespace `measurements`). Аннотации Vault (`agent-inject`, `role: measurements`) формируют шаблон секрета `measurements-s3` из `secrets/data/minio/apps/measurements`, собирая `S3_JSON_SETTINGS='{"host":…,"login":…,"password":…,"verify":false,"buckets":["measurements"]}'`. Контейнер запускается командой `set -a; . /vault/secrets/measurements-s3; set +a; exec /opt/entrypoint.sh`. Инлайн задан только `TRACING_USE=false`. Порт `8000` (`http`), `serviceAccountName: measurements-vault`, `imagePullSecrets: regcred`, ресурсы `cpu 25m` / `memory 128Mi`.
- `service.yaml``Service` `measurements-svc` (ClusterIP, порт `8000``8000`).
- `namespace.yaml` — namespace `measurements` с `istio-injection: enabled`.
- `serviceaccount.yaml` — SA `measurements-vault`.
- `kustomization.yaml` собирает `namespace`, `serviceaccount`, `deployment`, `service`.
### Оверлеи
- **`yc-k8s-test`** — `../base` + патч `replicas.yaml` (реплики Deployment `measurements` = 1).
- **`brusnika-stage`** / **`brusnika-prod`** — Flux `HelmRelease` `measurements` на `universal-chart` `0.1.7` (source `yc-oci-charts`). Секрет `S3_JSON_SETTINGS` берётся из k8s-секрета `s3-json-settings` (`secretEnvs`). `replicaCount`: `stage 1`, `preprod 3`, `production 3`; `imagePullSecrets: regcred`; `labels.monitoring: prometheus`; сервис `measurements-service` (ClusterIP, `8000`).
---
## Замечания и потенциальные проблемы
- **`S3_JSON_SETTINGS` — единственная жёстко обязательная переменная.** Локальный `docker-compose.yaml` задаёт её значением-заглушкой (`{"host":"host","login":"login","password":"password"}`) — для реальной работы значение нужно заменить.
- **`S3_JSON_FILE` в `.helm/values.yaml` кодом не читается** — приложение использует только `S3_JSON_SETTINGS` (в этом infra-репозитории она и инъектируется Vault). Расхождение способов передачи доступов между собственным чартом и infra-репо.
- **Опечатка в `middleware.py`:** в `DjangoUserMiddleware` используется `settings.django.self.timeout` вместо `settings.django.timeout` — лишний `.self` приведёт к `AttributeError`. Сам `DjangoUserMiddleware` в `main.py` не подключается (подключается `CustomAuthenticationMiddleware`).
- **Отсутствует поле `jwt_public_key`:** `CustomAuthenticationMiddleware` при отсутствии заголовка `identity` вызывает `jwt.decode(key=settings.jwt_public_key, …)`, но такого поля в `ApplicationSettings` нет — при `AUTH=1` и запросе без `identity` это приведёт к `AttributeError`. Если планируется проверка подписи, следует добавить переменную (напр. `JWT_PUBLIC_KEY`) в конфиг.
- **`brusnika-stage`/`brusnika-prod`: `image.name` указывает на `documentations` (`…/documentations:prod_5904312b`), а не на `measurements`** — вероятно скопировано из другого сервиса; для measurements образ должен указывать на `…/measurements`.
- **Проверки liveness/readiness отключены** во всех манифестах (`probes.*.enabled: false`); HTTP-эндпоинта healthcheck у сервиса нет.
- **Probes/порт в brusnika-оверлеях:** `deployment.port` задан `8080`, тогда как контейнер (`entrypoint.sh` → gunicorn) слушает `8000`, и `service.port`/`targetPort` = `8000`.
---
## Минимальный набор для локального запуска
- `S3_JSON_SETTINGS` (обязателен) — реальные доступы к S3/MinIO с бакетом(ами) растров.
- при необходимости: `LOG_LEVEL`, `TRACING_USE` (+ `TRACING_*`), `USE_SENTRY` (+ `SENTRY_*`), `AUTH` (+ `DJANGO_*`).
Сервис слушает `0.0.0.0:8000` (gunicorn, 4 воркера uvicorn). См. пример значений в `.env.example`.