# Конфигурация проекта sarex-resources Документ описывает все переменные окружения и способы конфигурирования сервиса ресурсов (`sarex-resources`, backend модуля «Ресурсы/Проекты»). ## Способы конфигурирования Сервис — приложение на **Django 4.1 + Django REST Framework** (GeoDjango/PostGIS). В отличие от сервисов на `pydantic-settings`, конфигурация задаётся **классическими Django settings-модулями** в `server/config/settings/`, а не единым классом настроек: - `base.py` — общие настройки (приложения, middleware, DRF, S3, интеграция с Sarex, OpenTelemetry); - `production.py` — наследует `base.py` (`from .base import *`), задаёт `DEBUG=False`, `ALLOWED_HOSTS`, БД, CORS, S3, статику; - `test.py` — наследует `base.py`, отдельная тестовая БД, снятие permission-классов DRF. Активный модуль выбирается переменной **`DJANGO_SETTINGS_MODULE`**. По умолчанию (`server/config/wsgi.py`, `server/manage.py`) — `config.settings.production`. Особенности разбора: - **префикса у переменных нет** — имена плоские (`DATABASE_HOST`, `YC_S3_BUCKET_NAME` и т.п.); - значения читаются напрямую через `os.getenv(...)`; вложенных секций/делимитеров (как `__` в pydantic-сервисах) нет; - **типизация и валидация окружения отсутствуют** — всё приходит строками; булевы флаги (`USE_OTEL`, `USE_INSECURE`) проверяются на «truthy», поэтому **любая непустая строка, включая `"False"`, считается истиной** (см. «Замечания»); - `.env`-файл приложением **не загружается автоматически** — переменные должны быть в окружении процесса (docker-compose `environment`, k8s `env`/`secretKeyRef`, либо `set -a && . ./.env && set +a`). > **Важно для прод-развёртывания.** В кластере файл `server/config/settings/production.py` **подменяется** содержимым ConfigMap `django-configmap` (монтируется на `/server/config/settings/production.py`, см. `infra/iac/apps/resources/base/django-configmap.yaml` и `.helm/templates/api.yaml`). Именно версия из ConfigMap определяет фактические `ALLOWED_HOSTS`, `CORS_*`, `SERVICE_ACCOUNTS_HOST`, cookie-имена и часть значений Sarex. Репозиторный `production.py` — это шаблон/локальный вариант. Источники переменных по способам запуска: | Способ запуска | Откуда берутся переменные | | --- | --- | | Локально (docker-compose) | `docker-compose.yml` — сервисы `postgres`/`api`; переменные Postgres задаются в `environment`, приложение читает окружение контейнера | | Локально (тесты) | `docker-compose.test.yml` + `pytest.ini` (`DJANGO_SETTINGS_MODULE=config.settings.test`), переменные `DJANGO_POSTGRES_*` | | Kubernetes (Helm-чарт репозитория) | `.helm/values-.yaml`: блоки `envs` (обычные значения) и `secrets` (из k8s-секретов); шаблон `.helm/templates/api.yaml` | | Kubernetes (infra, GitOps) | `infra/iac/apps/resources/*` — kustomize `base` (Vault-инъекция env в аннотациях Deployment + ConfigMaps) и оверлеи `brusnika-stage`/`brusnika-prod` (`helmrelease.yaml`, universal-chart) | | CI/CD (GitLab) | `.gitlab-ci.yml`: подключает общие шаблоны `generic/common-ci`, переключает окружение по ветке/тегу через `workflow.rules` | Способы запуска процессов: | Команда | Точка входа | Назначение | | --- | --- | --- | | `uwsgi --ini /opt/server/uwsgi.ini` | `config.wsgi:application` | HTTP API (uWSGI, порт 8000) | | `python manage.py migrate` | `manage.py` | Применение миграций (в `entrypoint.sh` перед стартом uWSGI) | | `python manage.py ` | `manage.py` | Служебные Django-команды (`createsuperuser`, `shell`, миграции и т.п.) | | `pytest` | `config.settings.test` | Юнит-тесты (`compose/test_server/entrypoint.sh`) | Порядок запуска в контейнере (`compose/server/entrypoint.sh`): сначала `python manage.py migrate`, затем `opentelemetry-instrument uwsgi --plugin python3 --ini /opt/server/uwsgi.ini` с `DJANGO_SETTINGS_MODULE=config.settings.production`. ## Переменные приложения Все переменные плоские (без префикса). Дефолт `—` означает, что значение при обращении вернёт `None`/пусто (Django/psycopg2 или интеграции могут упасть уже в рантайме, а не на старте). ### Выбор настроек | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `DJANGO_SETTINGS_MODULE` | string | `config.settings.production` | Модуль настроек Django. Значения: `config.settings.production` / `config.settings.test` | ### Окружение и трейсинг (`base.py`) Блок OpenTelemetry активируется целиком по `USE_OTEL` (`django-otel-tools`): добавляется `OtelMiddleware`, настраивается трейсер и OTEL-логгер. | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `USE_OTEL` | bool-ish | `False` (выкл.) | Включение трейсинга. Truthy-проверка: любая непустая строка включает | | `SERVICE_NAME` | string | `resources-backend.sarex-resources` | Имя сервиса в трейсах | | `TRACER_ENDPOINT` | string | `localhost:4375` | Адрес OTLP-коллектора | | `USE_INSECURE` | bool-ish | `False` | Небезопасное (без TLS) подключение к коллектору; та же truthy-проверка | | `ENVIRONMENT` | string | `prod` | Метка окружения в атрибутах трейсинга (`stage`/`preprod`/`prod`) | | `MODULE` | string | `resources` | Атрибут `module` в трейсинге | | `TEAM` | string | `platform_team` | Атрибут `team` в трейсинге | | `COMPONENT` | string | `backend` | Атрибут `component` в трейсинге | ### База данных (`production.py`, `django.contrib.gis.db.backends.postgis`) | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `DATABASE_HOST` | string | — | Хост PostgreSQL/PostGIS | | `DATABASE_PORT` | int (string) | — | Порт PostgreSQL | | `DATABASE_NAME` | string | — | Имя базы данных | | `DATABASE_USER` | string | — | Пользователь БД | | `DATABASE_PASSWORD` | string | — | Пароль пользователя БД | > БД требует расширения PostGIS (образ `postgis/postgis`), т.к. используются гео-поля (`Location.geometry`/`geography`) и `django.contrib.gis`. TLS к БД настраивается на уровне libpq: в Helm-чарте секрет `yc-pg-certificate` монтируется как `/root/.postgresql/root.crt` (в settings отдельного `sslmode` нет). ### База данных для тестов (`test.py`) | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `DJANGO_POSTGRES_DB` | string | `resources` | Имя тестовой БД | | `DJANGO_POSTGRES_USER` | string | `postgres` | Пользователь тестовой БД | | `DJANGO_POSTGRES_PASSWORD` | string | `12345678dev` | Пароль тестовой БД | | `DJANGO_POSTGRES_HOST` | string | `test_postgres` | Хост тестовой БД | | `DJANGO_POSTGRES_PORT` | int (string) | `5432` | Порт тестовой БД | Дополнительно `test.py` выставляет `DJANGO_ALLOW_ASYNC_UNSAFE=true` в коде. ### S3 / объектное хранилище (`base.py` и `production.py`, `django-storages` + `boto3`) Файлы (`ResourcePhoto.image` и т.п.) хранятся в S3-совместимом хранилище; `DEFAULT_FILE_STORAGE=storages.backends.s3boto3.S3Boto3Storage`, `AWS_DEFAULT_ACL="public-read"`. | Переменная | Тип | Значение по умолчанию | Назначение (Django-настройка) | | --- | --- | --- | --- | | `YC_S3_ACCESS_KEY_ID` | string | — | `AWS_ACCESS_KEY_ID` | | `YC_S3_SECRET_ACCESS_KEY` | string | — | `AWS_SECRET_ACCESS_KEY` | | `YC_S3_BUCKET_NAME` | string | — | `AWS_STORAGE_BUCKET_NAME` | | `YC_S3_ENDPOINT_URL` | string | — | `AWS_S3_ENDPOINT_URL` | ### Интеграция с ядром Sarex (`base.py`) Используется для получения токена (`/api/token/`) и списка пользователей (`/api/core/users/`) в эндпоинтах группировки пользователей/ресурсов (`users-grouped-by-resource`, `users-with-resources`). | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `SAREX_HOST` | string | `https://lk.sarex.io` | Базовый хост Sarex (`SAREX_BASE_HOST`) | | `SAREX_ADMIN_USERNAME` | string | — | Логин сервисной учётки Sarex | | `SAREX_ADMIN_PASSWORD` | string | — | Пароль сервисной учётки Sarex | | `SERVICE_ACCOUNTS_HOST` | string | `https://lk.sarex.io/api/core` | Определяется в `production.py`; кодом приложения напрямую не читается (см. «Замечания») | ## Переменные инфраструктуры, сборки и вспомогательных утилит Не читаются кодом приложения, но участвуют в запуске/сборке/деплое. | Переменная | Где используется | Назначение | | --- | --- | --- | | `API_ADDRESS` | `.helm/values-*.yaml`, `infra/.../backend-deployment.yaml` | Задаётся в окружении (`8000`), кодом не читается — порт фактически берётся из `uwsgi.ini` (`http = 0.0.0.0:8000`) | | `POSTGRES_USER` / `POSTGRES_PASSWORD` / `POSTGRES_DB` | `docker-compose.yml`, `docker-compose.test.yml` | Инициализация контейнера Postgres (не путать с `DATABASE_*`, которые читает Django) | | `PYTHONUNBUFFERED` | `Dockerfile` | Небуферизованный stdout/stderr | | build-настройки uWSGI | `compose/server/uwsgi.ini` | `processes=8`, `http=0.0.0.0:8000`, `harakiri`, `buffer-size`, `static-map` для `/static` и `/media` | Приватный индекс пакетов для сборки (`django-otel-tools`) задан прямо в `requirements/base.txt` через `--extra-index-url` (nexus.infra.sarex.io). ## Переменные из Helm-чарта репозитория (`.helm/values-.yaml`) Обычные значения — блок `envs`, секреты — блок `secrets` (монтируются как env через `secretKeyRef`). Значения различаются по окружениям (`stage`/`preprod`/`production`): адрес БД (`DATABASE_HOST`), `SERVICE_NAME`, `TRACER_ENDPOINT`, `ENVIRONMENT`, число реплик. Значения из секретов: | Переменная | Секрет (`secret_name`) | Ключ (`secret_key`) | | --- | --- | --- | | `DATABASE_USER` | `ya-pg-secret` | `user` | | `DATABASE_PASSWORD` | `ya-pg-secret` | `password` | | `YC_S3_ACCESS_KEY_ID` | `yc-s3-secret` | `key_id` | | `YC_S3_SECRET_ACCESS_KEY` | `yc-s3-secret` | `access_key` | | `YC_S3_BUCKET_NAME` | `yc-s3-secret` | `storage_bucket_name` | | `YC_S3_ENDPOINT_URL` | `yc-s3-secret` | `endpoint_url` | | `SAREX_ADMIN_USERNAME` | `sarex-auth-secret` | `username` | | `SAREX_ADMIN_PASSWORD` | `sarex-auth-secret` | `password` | Помимо env, чарт монтирует CA-сертификат PostgreSQL из секрета `yc-pg-certificate` (ключ `certificate`) как файл `/root/.postgresql/root.crt`, а также ConfigMap `uwsgi-configmap` (файл `uwsgi.ini`). Прочие значения чарта (не переменные приложения): `deployment.*` (имя, образ, порт, реплики, ресурсы), `service_*`, `api_host` (istio `VirtualService`, prefix `/resource-management`). ## Переменные из infra (GitOps, kustomize `base`) В `infra/iac/apps/resources/base/backend-deployment.yaml` секреты БД и S3 подаются через **HashiCorp Vault Agent** (аннотации `vault.hashicorp.com/*`), который рендерит файлы `/vault/secrets/resources-db` и `/vault/secrets/resources-s3`; они подгружаются в окружение в `args` контейнера (`set -a && . /vault/secrets/... && set +a`) перед запуском `entrypoint.sh`. | Переменная | Источник (Vault path / значение) | | --- | --- | | `DATABASE_HOST` | `postgresql.resources.svc.cluster.local` (шаблон Vault) | | `DATABASE_PORT` | `5432` | | `DATABASE_NAME` | `resources_db` | | `DATABASE_USER` | `secrets/data/postgresql/apps/resources` → `username` | | `DATABASE_PASSWORD` | `secrets/data/postgresql/apps/resources` → `password` | | `YC_S3_ENDPOINT_URL` | `secrets/data/minio/apps/resources` → `client.endpoint` | | `YC_S3_BUCKET_NAME` | `resources` | | `YC_S3_ACCESS_KEY_ID` | `secrets/data/minio/apps/resources` → `access_key` | | `YC_S3_SECRET_ACCESS_KEY` | `secrets/data/minio/apps/resources` → `secret_key` | | `DJANGO_SETTINGS_MODULE` | `config.settings.production` (env Deployment) | | `API_ADDRESS` | `8000` (env Deployment) | Оверлеи `brusnika-stage`/`brusnika-prod` используют `HelmRelease` (universal-chart): env `DJANGO_SETTINGS_MODULE`, `DATABASE_HOST/PORT/NAME`, `API_ADDRESS`, `YC_S3_ENDPOINT_URL`, `YC_S3_BUCKET_NAME`; секреты `DATABASE_USER/PASSWORD` (`postgres-secret`), `YC_S3_ACCESS_KEY_ID/SECRET_ACCESS_KEY` (`yc-s3-secret`, ключи `key-id`/`access-key`). ## Переменные в CI (`.gitlab-ci.yml`) Пайплайн подключает общие шаблоны из `generic/common-ci` (`universal-pipeline-*`, `common-security-scan`, `common-build`) и переключает окружение по ветке/тегу: | Условие | STAND | Namespace | RELEASE_NAME | | --- | --- | --- | --- | | ветка `master` | `preprod` | `resources-preprod` | `resources` | | ветка `stage` | `stage` | `resources-stage` | `sarex-resources` | | тег (`CI_COMMIT_TAG`) | `prod` | `resources-prod` | `sarex-resources` | Ключевые переменные пайплайна: `CHART_NAME=sarex-resources`, `CHART_VERSION`, `DOCKERFILE_PATH=./compose/server/Dockerfile`, `IMAGE_PATH=deployment.image`, `HELM_SET_ARGS` (`--set deployment.image=…`), флаги `ENABLE_LINTER`/`ENABLE_BUILD_CHART`/`ENABLE_BUILD_IMAGE`/`ENABLE_STATE_UPDATE`/`ENABLE_DEPLOY`. Job `linter` запускает `flake8` (образ `python:3.8-buster`). ## Замечания и потенциальные проблемы - **Truthy-флаги.** `USE_OTEL` и `USE_INSECURE` читаются как `os.getenv(name, False)` без приведения типа. Любая непустая строка — истина, включая `"False"`, `"0"`, `"no"`. Чтобы **выключить** трейсинг, переменную `USE_OTEL` нужно **не задавать вовсе** (а не ставить в `False`). В Helm-values она задана строкой `"True"`. - **`.env` не загружается автоматически.** В settings нет `python-dotenv`/`env_file`; переменные должны попадать в окружение процесса (compose `environment`, k8s `env`/Vault, ручной `export`). - **`production.py` подменяется в кластере.** Репозиторный `production.py` содержит хардкод `ALLOWED_HOSTS`, `CORS_*`, тестовый `SECRET_KEY` и др.; в проде используется версия из ConfigMap `django-configmap`. Различия: `ALLOWED_HOSTS=['*']`, другой `SERVICE_ACCOUNTS_HOST`, хардкод `SAREX_ADMIN_*`/`SAREX_BASE_HOST`, cookie-имена `resource-sessionid`/`resource-csrftoken`. - **`SECRET_KEY` захардкожен** в `base.py`/`production.py` (в т.ч. пометка `# Delete after Test`) — секрет не берётся из окружения. Для реального прода его следует вынести в секрет. - **`SERVICE_ACCOUNTS_HOST`** определяется, но напрямую в коде не используется (интеграции ходят по `SAREX_BASE_HOST`); переменная задаётся «на вырост». - **`DATABASE_*` без дефолтов.** При отсутствии переменных Django получит `None` и подключение к БД упадёт в рантайме (не на импортстарте). Пять переменных БД обязательны для рабочего запуска. - **Аутентификация DRF отключена.** `DEFAULT_AUTHENTICATION_CLASSES=[]`, permission-классы не заданы (эффективно `AllowAny`) — доступ ограничивается только сетевым слоем/istio. Учитывать при публикации. - **Имя релиза различается между окружениями** (`resources` на preprod vs `sarex-resources` на stage/prod) — при работе с Helm/namespace это легко перепутать. ## Минимальный набор для локального запуска Postgres (PostGIS) поднимается через `docker-compose up postgres`, приложение — через сервис `api` (`docker-compose.yml`) или локально `uwsgi`/`manage.py runserver`. Минимально необходимо задать: - `DJANGO_SETTINGS_MODULE=config.settings.production` (или свой dev-модуль) - `DATABASE_HOST`, `DATABASE_PORT`, `DATABASE_NAME`, `DATABASE_USER`, `DATABASE_PASSWORD` - `YC_S3_*` — если задействуется загрузка файлов/статики в S3 (иначе операции с файлами упадут) - `SAREX_HOST`, `SAREX_ADMIN_USERNAME`, `SAREX_ADMIN_PASSWORD` — если нужны эндпоинты интеграции с пользователями Sarex - OTEL — по умолчанию не задавать (`USE_OTEL` отсутствует); при включении — `USE_OTEL=1`, `SERVICE_NAME`, `TRACER_ENDPOINT`, при необходимости `USE_INSECURE` Для тестов достаточно поднять `docker-compose.test.yml` — переменные `DJANGO_POSTGRES_*` имеют рабочие дефолты, `pytest.ini` уже указывает `config.settings.test`. Готовые значения-примеры для всех переменных приведены в `.env.example`.