iac/apps/django/CONFIGURATION.md

358 lines
23 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.

# Конфигурация проекта sarex-backend (Django)
Документ описывает способы конфигурирования backend-сервиса `sarex` (Django) и
основные переменные окружения. Фронтенд-приложение `sarex-frontend` (шелл на
Module Federation) конфигурируется отдельно на этапе сборки — см. раздел в конце
и `ENDPOINTS.md`.
## Способы конфигурирования
Сервис — это Django-приложение (проект `config`, бизнес-логика в пакете `sarex`).
Конфигурация складывается из двух механизмов:
1. **Модуль настроек Django** выбирается переменной `DJANGO_SETTINGS_MODULE`.
Модули лежат в `config/settings/` и наследуются друг от друга через
`from .base import *`.
2. **Переменные окружения** читаются двумя способами:
- `django-environ` — объект `env = environ.Env()` в `config/settings/base.py`,
вызовы `env('NAME', default=...)`, `env.bool(...)`, `env.list(...)`,
`env.str(...)`;
- `pydantic-settings` — классы-наследники `BaseSettings` с `env_prefix`
(напр. `ServerSettings` → префикс `SERVER_`), инстанцируются как синглтоны
(`SERVERSETTINGS = ServerSettings()` и т.п.).
Приложение **не загружает `.env` автоматически** в основном конфиге
(`DJANGO_READ_DOT_ENV_FILE` закомментирован). Исключение — pydantic-классы
`SentrySettings` (читает `.env.base`, `.env`), `ZitadelSettings`, `KafkaSettings`
(читают `.env`). В остальном переменные нужно экспортировать в окружение процесса.
### Модули настроек (`config/settings/*.py`)
| Модуль | Назначение |
| --- | --- |
| `base.py` | Базовые настройки, все классы `*Settings`, INSTALLED_APPS, DRF, Celery-очереди |
| `production.py` | Продакшн: `DEBUG=False`, БД из `DJANGO_POSTGRES_*`, SimpleJWT (RS512), логирование |
| `docker.py` | Наследует `test.py`, `ALLOWED_HOSTS=["*"]`, БД на хосте `postgres` |
| `test.py` / `test_ksg.py` | Прогон тестов |
| `example.local.py` / `example.ldap.local.py` | Шаблоны для локального `local.py` (копируются вручную) |
По умолчанию `manage.py` и `config/celery.py` используют `config.settings.local`.
В кластере задаётся `DJANGO_SETTINGS_MODULE=config.settings.production`, при этом
файл `production.py` **подменяется** ConfigMap-ом `django-configmap` (монтируется в
`/opt/sarex/config/settings/production.py`) — см. раздел про деплой.
### Способы запуска процессов
| Процесс | Команда | Назначение |
| --- | --- | --- |
| Web/API (uWSGI) | `uwsgi --plugin python3 --ini uwsgi.ini` | HTTP API на `0.0.0.0:8000`, модуль `config.wsgi:application` |
| Web/API (dev) | `python manage.py runserver` | Локальный запуск |
| Celery worker+beat | `celery -A config worker -B -l info -E -Q default -n default_worker.%h` | Фоновые задачи и периодические таски |
| Миграции | `python manage.py migrate` | Выполняются в `entrypoint.sh` перед стартом uWSGI |
Порядок запуска контейнера backend (`entrypoint.sh`): сначала
`opentelemetry-instrument python manage.py migrate`, затем
`opentelemetry-instrument uwsgi --plugin python3 --ini uwsgi.ini`. В кластере
перед `entrypoint.sh` секреты из Vault экспортируются в окружение (`set -a; . /vault/secrets/...`).
## Переменные приложения
Ниже перечислены основные переменные. Дефолт `—` означает, что значение
обязательно (в `production.py` без него будет ошибка старта).
### Django core
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `DJANGO_SETTINGS_MODULE` | string | `config.settings.local` | Модуль настроек Django |
| `DJANGO_DEBUG` | bool | `False` | Режим отладки |
| `DJANGO_ISOLATED` | bool | `False` | Изолированный режим (в configmap отключает Sentry) |
| `ALLOWED_HOSTS` | list/str | — (в prod из env) | Разрешённые хосты; в кластере `*` |
| `APPEND_SLASH` | bool | `True` | Автодобавление слеша в URL |
| `FZ152_COMPLIANCE` | bool | `False` | Режим соответствия 152-ФЗ |
| `PDM_SYNC` | bool | `False` | Синхронизация с PDM |
| `OBJECT_STORAGE_SYNC` | bool | `True` | Синхронизация с объектным хранилищем |
| `SECRET_KEY` | string | хардкод в `production.py` | Секретный ключ Django |
| `SIMPLE_JWT_ISSUER` | string | `django` | Issuer для JWT |
| `DISK_USAGE_ROOT` | string | `/` | Корень для расчёта занятого места |
| `USE_SSL_FOR_URL_SERIALIZATION` | bool | `True` | Использовать https при сериализации URL |
| `WEB_APP_AUTH_MODE` | string | `JWTDefault` | Режим авторизации веб-приложения |
### База данных (PostgreSQL)
Читаются в `config/settings/production.py`. В кластере приходят из Vault-секрета
`secrets/data/postgresql/apps/django` (файл `/vault/secrets/django-postgresql`).
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `DJANGO_POSTGRES_HOST` | string | — | Хост PostgreSQL |
| `DJANGO_POSTGRES_PORTS` | string | `5432` | Порт PostgreSQL |
| `DJANGO_POSTGRES_DATABASE` | string | — | Имя базы |
| `DJANGO_POSTGRES_USER` | string | — | Пользователь |
| `DJANGO_POSTGRES_PASSWORD` | string | — | Пароль |
Движок БД — `django_prometheus.db.backends.postgresql`.
### JWT (SimpleJWT, RS512)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `JWT_PRIVATE_KEY` | string | — | Приватный RSA-ключ подписи (`\n` заменяются на переводы строк). В кластере — из Vault `rsa_keys` |
| `JWT_PUBLIC_KEY` | string | — | Публичный RSA-ключ проверки |
| `JWT_KID` | string | `None` | `kid` в заголовке токена (используется для межсервисных вызовов) |
| `DJANGO_JWT_SECRET` | string | `Froom too much love of living` | Легаси-секрет |
### Celery (`CELERY_*`)
Брокер — RabbitMQ; backend результатов — Redis (по умолчанию) или Postgres
(`CELERY_USE_POSTGRES=True`). `CELERY_RABBITMQ_*` в кластере из Vault-секрета
`secrets/data/rabbitmq/apps/django`.
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `CELERY_USE_POSTGRES` | bool | `False` | Использовать Postgres как result backend |
| `CELERY_RABBITMQ_HOST` | string | `localhost` | Хост RabbitMQ |
| `CELERY_RABBITMQ_PORT` | int | `5672` | Порт |
| `CELERY_RABBITMQ_USER` | string | `rabbit` | Пользователь |
| `CELERY_RABBITMQ_PASSWORD` | string | `rabbit` | Пароль |
| `CELERY_RABBITMQ_VHOST` | string | `api` | Виртуальный хост |
| `CELERY_REDIS_HOST` | string | `localhost` | Хост Redis (result backend) |
| `CELERY_REDIS_PORT` | int | `6379` | Порт Redis |
| `CELERY_REDIS_DATABASE` | int | `0` | Номер БД Redis |
| `CELERY_POSTGRES_DATABASE` | string | `celery_db` | БД для result backend на Postgres |
| `CELERY_POSTGRES_USER` | string | `sarex` | Пользователь |
| `CELERY_POSTGRES_PASSWORD` | string | `sarex` | Пароль |
| `CELERY_POSTGRES_HOST` | string | `localhost` | Хост |
| `CELERY_POSTGRES_PORT` | string | `5432` | Порт |
Дополнительно из Vault-шаблона прокидываются дублирующие `DJANGO_RABBIT_HOSTNAME`,
`DJANGO_RABBIT_USER`, `DJANGO_RABBIT_PASS`, `DJANGO_RABBIT_VHOST`, а также
`DJANGO_REDIS_HOST` / `DJANGO_REDIS_PORT`.
### Кеш Redis (`CACHE_*`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `CACHE_HOST` | string | `localhost` | Хост Redis |
| `CACHE_PORT` | int | `6379` | Порт |
| `CACHE_PASSWORD` | string \| null | `None` | Пароль |
| `CACHE_SSL` | bool | `False` | TLS |
| `CACHE_SSL_CA_CERTS` | string \| null | `None` | CA-сертификат |
### S3 / объектное хранилище (`S3_*`)
`S3_*` в кластере из Vault-секрета `secrets/data/minio/apps/django`.
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `S3_HOST` | string | `https://storage.yandexcloud.net` | Эндпоинт S3 |
| `S3_LOGIN` | string | `""` | Access key |
| `S3_PASSWORD` | string | `""` | Secret key |
| `S3_BUCKET` | string | `sarex-media-storage` | Бакет по умолчанию |
| `S3_REGION` | string | `""` | Регион (fallback: `AWS_DEFAULT_REGION`) |
| `AWS_S3_ENDPOINT_URL` | string | `https://storage.yandexcloud.net` | Эндпоинт (легаси-переменная) |
| `S3TOOLS_LIB_PATH` | string | `/opt/sarex/lib/s3tools.so` | Путь к нативной библиотеке загрузки (Dockerfile) |
| `S3TOOLS_WORKERS` | int | `10` | Число воркеров загрузки |
### Kafka (`KAFKA_*`)
Аутентификация в кластере из Vault-секрета `secrets/data/kafka/apps/django`.
Продюсер создаётся только при `SERVER_KAFKA_ENABLED=True`.
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `KAFKA_BOOTSTRAP_SERVERS` | list[str] (JSON) | `["localhost:9092"]` | Список брокеров |
| `KAFKA_SECURITY_PROTOCOL` | string | `""` | Протокол безопасности |
| `KAFKA_SASL_MECHANISM` | string | `""` | SASL-механизм |
| `KAFKA_SASL_PLAIN_USERNAME` | string | `user` | Логин |
| `KAFKA_SASL_PLAIN_PASSWORD` | string | `password` | Пароль |
| `KAFKA_SSL_CAFILE` | string | `""` | Путь к CA-сертификату |
| `KAFKA_TOPICS` | dict (JSON) | `{}` | Маппинг логических имён на топики |
### Sentry (`SENTRY_*`)
Читается классом `SentrySettings` из `.env.base` / `.env`.
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `SENTRY_USE` | bool | `True` | Включить Sentry |
| `SENTRY_HOST` | string | `""` | DSN/хост Sentry |
| `SENTRY_ENVIRONMENT` | string | `""` | Окружение |
| `SENTRY_TRACES_SAMPLE_RATE` | float | `1.0` | Доля трейсов |
| `SENTRY_PROFILES_SAMPLE_RATE` | float | `0.1` | Доля профилей |
### Флаги приложения (`SERVER_*`, класс `ServerSettings`)
Класс содержит десятки булевых флагов и параметров. Наиболее значимые (реально
задаются в манифестах):
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `SERVER_HOST` | string | `https://lk.sarex.io` | Внешний хост ЛК |
| `SERVER_API_HOST` | string | `https://api.sarex.io` | Внешний хост API |
| `SERVER_ZITADEL_ENABLED` | bool | `True` | Включить Zitadel-аутентификацию |
| `SERVER_KAFKA_ENABLED` | bool | `False` | Включить Kafka-продюсер |
| `SERVER_USE_METASHAPE` | bool | `True` | Использовать Metashape |
| `SERVER_USE_CLICKHOUSE` | bool | `False` | Использовать ClickHouse |
| `SERVER_CACHE_ENABLED` | bool | `False` | Включить кеш (в configmap выставляется `True`) |
| `SERVER_USE_NOTIFICATIONS` | bool | `True` | Уведомления |
| `SERVER_TIMEOUT` | int | `60` | Таймаут по умолчанию |
| `SERVER_CHUNKED_PATH` | string | — | Путь для чанкованных загрузок |
Полный список полей — в `ServerSettings` (`config/settings/base.py`). Любое поле
переопределяется переменной `SERVER_<FIELD>` в верхнем регистре.
### Workflows / processing (`WORKFLOWS_*`, класс `WorkFlowsSettings`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `WORKFLOWS_USE` | bool | `False` | Включить интеграцию с processing |
| `WORKFLOWS_HOST` | string | `https://api.sarex.io` | Хост сервиса processing |
| `WORKFLOWS_BASE_HOST` | string | `https://lk.sarex.io` | Базовый хост |
| `WORKFLOWS_PREFIX` | string | `/internal/v1` | Префикс внутреннего API |
| `WORKFLOWS_TIMEOUT` | int | `120` | Таймаут |
| `WORKFLOWS_REGISTRY` | string | `cr.yandex/crp3ccidau046kdj8g9q` | Реестр образов задач |
| `WORKFLOWS_TAG` | string | `stable` | Тег образов |
### Внешние API-сервисы (`BaseApiServiceMixin`)
Классы `GateWaySetttings` (`GATEWAY_`), `BimV2ApiSettings` (`BIMV2_`),
`EAVSettings` (`EAV_`), `AnalyticsSettings` (`ANALYTICS_`),
`DocumentationSettings` (`DOCUMENTATION_`), `UsersSettings` (`USERS_`),
`SystemLogSettings` (`SYSTEM_LOG_`), `ResourceSettings` (`RESOURCES_`) наследуют
общий набор полей:
| Поле (переменная `<PREFIX>_<FIELD>`) | Тип | Назначение |
| --- | --- | --- |
| `HOST` | string | Внешний хост сервиса |
| `API_PREFIX` | string | Префикс публичного API |
| `INTERNAL_HOST` | string | Внутренний хост (внутрикластерный) |
| `INTERNAL_PREFIX` | string | Префикс внутреннего API |
| `TIMEOUT` | int | Таймаут запроса |
| `ENABLE` | bool | Включён ли сервис |
Реально задаваемые в манифестах: `BIMV2_INTERNAL_HOST`, `BIMV2_TIMEOUT`,
`EAV_ENABLE`. Отдельно — `GK_ENCRYPTION_KEY` (класс `GatekeeperSettings`).
### Measurements (`MEASUREMENTS_*`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `MEASUREMENTS_HOST` | string | `https://api.sarex.io/measurements/` | Хост сервиса измерений |
| `MEASUREMENTS_TIMEOUT` | int | `180` | Таймаут |
| `MEASUREMENTS_WINDOW_SIZE` | int | `1000` | Размер окна |
### ClickHouse (`CLICKHOUSE_*`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `CLICKHOUSE_HOST` | string | `rc1d-...yandexcloud.net` | Хост |
| `CLICKHOUSE_PORT` | int | `9000` | Порт |
| `CLICKHOUSE_USER` / `CLICKHOUSE_PASSWORD` | string | `""` | Учётные данные |
| `CLICKHOUSE_DATABASE` | string | `values_db` | База |
| `CLICKHOUSE_TABLE` | string | `values` | Таблица |
| `CLICKHOUSE_SECURE` / `CLICKHOUSE_VERIFY` | bool | `False` | TLS и проверка сертификата |
| `CLICKHOUSE_CERT` | string | `""` | CA-сертификат |
### Zitadel (`ZITADEL_*`) и Keycloak (`KC_*`, `KC_SYNC*`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `ZITADEL_HOST` | string | `""` | Хост Zitadel (IdP) |
| `ZITADEL_ACCESS_TOKEN` | string | `""` | Сервисный токен (из Vault `django_auth`) |
| `ZITADEL_USERS_ENDPOINT` | string | `/v2/users` | Эндпоинт пользователей |
| `KC_SYNC_ENABLE` | bool | `False` | Включить синхронизацию с Keycloak |
| `KC_USE_REDIRECT_LOGOUT` | bool | `False` | Redirect при logout |
| `KC_CLIENT_ID` / `KC_CLIENT_SECRET` / `KC_DISCOVERY_URL` / `KC_REALM` | string | см. `KeyCloakSettings` | Параметры клиента Keycloak |
### Трейсинг (`TRACING_*`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `TRACING_SERVICE_NAME` | string | `backend.sarex-stage` | Имя сервиса в трейсах |
| `TRACING_ENDPOINT` | string | `localhost:4317` | OTLP-коллектор |
| `TRACING_INSECURE` | bool | `False` | Без TLS |
| `TRACING_ENVIRONMENT` | string | `prod` | Окружение |
### Comparator и прочее
| Переменная | Значение по умолчанию | Назначение |
| --- | --- | --- |
| `COMPARATOR_URL` | `https://wb.sarex.io/comparator` | URL сервиса сравнения |
| `COMPARATOR_SECTION` | `sarex-production-storage` | Секция хранилища |
| `COMPARATOR_JWT` | `default_jwt` | Токен сравнения |
| `WORKFLOWSSETTINGS_HOST` / `WORKFLOWSSETTINGS_REGISTRY` | — | Используются напрямую в configmap `production.py` |
| `PG_NODE_HOST`, `PG_API_KEY`, `PG_MONGO_HOST`, `PG_MONGO_PORT`, `PG_IMPORT_PATH` | см. `base.py` | Легаси-интеграции PG |
## Конфигурация в кластере (Kubernetes)
Манифесты приложения — в этом же каталоге (`base/`, оверлеи `brusnika-stage`,
`brusnika-prod`, `yc-k8s-test`). Секреты монтируются через **Vault Agent Injector**
(аннотации `vault.hashicorp.com/*` на Deployment `backend` и `celery`). Файлы
секретов в контейнере и их содержимое:
| Файл `/vault/secrets/...` | Секрет Vault | Переменные |
| --- | --- | --- |
| `django-postgresql` | `secrets/data/postgresql/apps/django` | `DJANGO_POSTGRES_HOST/PORTS/DATABASE/USER/PASSWORD` |
| `django-rabbitmq` | `secrets/data/rabbitmq/apps/django` | `CELERY_RABBITMQ_*`, `DJANGO_RABBIT_*` |
| `django-s3` | `secrets/data/minio/apps/django` | `AWS_S3_ENDPOINT_URL`, `S3_HOST/BUCKET/LOGIN/PASSWORD` |
| `django-kafka` | `secrets/data/kafka/apps/django` | `KAFKA_BOOTSTRAP_SERVERS/SECURITY_PROTOCOL/SASL_*` |
| `django-jwt-private` / `django-jwt-public` | `secrets/data/vault/common/rsa_keys` | `JWT_PRIVATE_KEY` / `JWT_PUBLIC_KEY` |
| `django-common` | `secrets/data/vault/common/django_auth` | `ZITADEL_ACCESS_TOKEN` |
Контейнер экспортирует эти файлы в окружение до запуска (`set -a; . /vault/secrets/...`).
Кроме того, `production.py` из ConfigMap содержит функцию `_load_env_file`, которая
подхватывает те же файлы при запуске `manage.py` через `kubectl exec` вне entrypoint.
Остальные (несекретные) переменные задаются в блоке `env` контейнеров
`backend`/`celery` (`SERVER_*`, `WORKFLOWS_*`, `BIMV2_*`, `MEASUREMENTS_*`,
`ZITADEL_HOST`, `KAFKA_TOPICS`, `EAV_ENABLE`, `PDM_SYNC`, `JWT_KID` и др.).
ConfigMap `django-configmap` подменяет `config/settings/production.py`
(смонтирован в `/opt/sarex/config/settings/production.py`) и переопределяет
`ALLOWED_HOSTS`, CORS, `DATABASES`, `SIMPLE_JWT`, `REST_FRAMEWORK`, `MIDDLEWARE`,
`KeyCloakSettings`, `SAREX_MODULES`, а также включает Sentry (если не `ISOLATED`).
ConfigMap `zitadel-configmap` содержит `config.json` с `client_id`/`host` Zitadel.
`uwsgi-configmap` монтирует `uwsgi.ini`.
## CI (`.gitlab-ci.yml`)
Пайплайн подключает общие шаблоны из `generic/common-ci`
(`common-security-scan.yaml`, `universal-pipeline.yaml`) и переключает окружение
по ветке/тегу через `workflow.rules`:
| Условие | STAND | NAMESPACE |
| --- | --- | --- |
| ветка `stage` | `stage` | `aero` |
| ветка `master` | `preprod` | (см. правила) |
| тег | `prod` | (см. правила) |
Ключевые переменные: `SERVICE_NAME=backend`, `DOCKERFILE_PATH=./Dockerfile`,
`RELEASE_NAME`, `CHART_NAME`, `CHART_VERSION`, `HELM_SET_ARGS`
(`universal-chart.services.backend.image.name…`, `…celery.image.name…`).
## Замечания и потенциальные проблемы
- В `production.py` `SECRET_KEY` задан хардкодом (закомментированный `env('SECRET_KEY')`).
Для реального прод-развёртывания ключ желательно вынести в секрет.
- Основной конфиг не читает `.env` автоматически; переменные нужно экспортировать
в окружение (в кластере это делает Vault + `set -a`). Только `SENTRY_*`,
`ZITADEL_*`, `KAFKA_*` читаются из файлов `.env.base`/`.env` их pydantic-классами.
- `production.py` в репозитории backend и `production.py` из ConfigMap `django-configmap`
**разные** файлы. В кластере используется версия из ConfigMap (в ней, в частности,
выставлено `DEBUG=True` в конце и включён `corsheaders`).
- `DATABASES['default']['ENGINE']``django_prometheus.db.backends.postgresql`
(обёртка для метрик Prometheus).
- Значения `SERVER_*`-флагов у `backend` и `celery` местами различаются
(напр. `SERVER_ZITADEL_ENABLED`, `SERVER_API_HOST`) — это ожидаемо.
## Минимальный набор для локального запуска
Согласно `README.md` backend: поднять Postgres/Redis/RabbitMQ (docker-compose),
скопировать шаблон настроек `cp config/settings/example.local.py config/settings/local.py`,
применить миграции (`python manage.py migrate`) и создать суперпользователя.
Минимально требуются переменные БД (`DJANGO_POSTGRES_*` или значения в `local.py`),
брокера Celery (`CELERY_RABBITMQ_*`) и, при использовании соответствующих функций,
`S3_*`, `JWT_PRIVATE_KEY`/`JWT_PUBLIC_KEY`. Примеры значений — в `.env.example`
рядом с этим файлом.