# Конфигурация проекта 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_` в верхнем регистре. ### 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_`) наследуют общий набор полей: | Поле (переменная `_`) | Тип | Назначение | | --- | --- | --- | | `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` рядом с этим файлом.