iac/apps/eav/CONFIGURATION.md

187 lines
17 KiB
Markdown
Raw 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.

# Конфигурация проекта eav-python
Документ описывает все переменные окружения и способы конфигурирования сервиса.
## Способы конфигурирования
Сервис — это Django-приложение (**Django 4.1 + Django REST Framework**), запускаемое как WSGI (`config.wsgi`) через **uWSGI** (порт `8000`, см. `compose/eav-backend/uwsgi.ini`). Настройки читаются из переменных окружения в `src/config/settings/base.py` и `src/config/settings/production.py`. Разбор выполняется частично через библиотеку [`django-environ`](https://django-environ.readthedocs.io/) (объект `env = environ.Env()`), частично напрямую через `os.getenv`.
Особенности разбора:
- **префикса/делимитера у секций нет** — каждая настройка задаётся плоской переменной окружения (напр. `DJANGO_POSTGRES_HOST`, `KAFKA_HOST`, `YC_S3_BUCKET_NAME`);
- **`.env` не загружается автоматически** — в коде нет вызова `environ.Env.read_env()` / `load_dotenv`, хотя `python-dotenv` присутствует в зависимостях. Переменные нужно экспортировать в окружение самому (напр. `set -a && . ./.env && set +a`) либо задавать через `--env`/манифесты k8s. Файл `.env` при этом в `.gitignore`;
- **выбор набора настроек** задаётся `DJANGO_SETTINGS_MODULE`: `config.settings.production` (боевой набор с БД, CORS, JWT), `config.settings.test` (только `base`), либо `config.settings.local` (по умолчанию в `manage.py`, в репозитории отсутствует, `.gitignore`);
- **часть переменных читается только в `production.py`** — БД (`DJANGO_POSTGRES_*`) и JWT (`JWT_PRIVATE_KEY`/`JWT_PUBLIC_KEY`); в `base.py`/`test.py` их нет.
Отдельного конфиг-файла (yaml/toml) у приложения нет.
Источники переменных по способам запуска:
| Способ запуска | Откуда берутся переменные |
| --- | --- |
| Локально (manage.py / uWSGI) | Переменные окружения процесса (`.env` нужно экспортировать вручную) |
| Локально (docker-compose) | `docker-compose.yml`: блок `environment` сервиса `backend` + образ `postgres` (timescaledb-postgis) |
| Kubernetes (Helm, репозиторий приложения) | `.helm/values-<env>.yaml`: блоки `backend.deployment.envs` (обычные значения) и `backend.deployment.secrets` (из k8s-секретов через `secretKeyRef`); шаблон `templates/server.yaml`, роутинг — `templates/mesh-config.yaml` (Istio VirtualService) |
| Kubernetes (infra, Flux/Kustomize) | `infra/iac/apps/eav/base/backend-deployment.yaml`: секреты инъектируются Vault-агентом (`vault.hashicorp.com/agent-inject-*`) и экспортируются в окружение в `args`; настройки `production.py` монтируются из `django-configmap` |
| CI/CD (GitLab) | `.gitlab-ci.yml`: общие шаблоны `generic/common-ci`, переменные пайплайна в `workflow.rules` |
Способы запуска процессов:
| Процесс | Точка входа | Назначение |
| --- | --- | --- |
| HTTP API | `compose/eav-backend/entrypoint.sh``uwsgi --ini uwsgi.ini` (`config.wsgi`, порт 8000) | REST API |
| Миграции | `entrypoint.sh``python3 manage.py migrate` (выполняется перед стартом uWSGI) | Миграции БД |
| Kafka-продюсер | `config/kafka.py` (инициализируется при импорте, если `KAFKA_ENABLED`) | Публикация событий EAV в топики |
Порядок запуска в контейнере (`entrypoint.sh`): сначала `manage.py migrate`, затем `uwsgi` (оба под `opentelemetry-instrument`).
## Переменные приложения
Дефолт `—` означает, что значения по умолчанию в коде нет.
### Django / приложение
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `DJANGO_SETTINGS_MODULE` | string | `config.settings.local``manage.py`); в контейнере — `config.settings.production` | Какой набор настроек Django загружать |
| `DJANGO_DEBUG` | bool | `False` | Режим отладки Django (в `production.py` жёстко `False`) |
| `DJANGO_SECRET_KEY` | string | (захардкоженный дефолт) | Секретный ключ Django. В проде обязателен свой |
| `SERVICE_NAME` | string | `eav` | Имя сервиса (в `base.py`); в OTEL-секции дефолт `eav.eav-backend` |
| `VERSION` | string | `1.0.0` | Версия приложения |
### Database — PostgreSQL (только `config.settings.production`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `DJANGO_POSTGRES_HOST` | string | — | Хост PostgreSQL |
| `DJANGO_POSTGRES_PORT` | int | `6432` | Порт PostgreSQL (в infra-манифесте — `5432`) |
| `DJANGO_POSTGRES_DATABASE` | string | — | Имя базы данных |
| `DJANGO_POSTGRES_USER` | string | — | Пользователь БД |
| `DJANGO_POSTGRES_PASSWORD` | string | — | Пароль пользователя БД |
> Engine — `django.db.backends.postgresql`. В `docker-compose.yml` поднимается `timescale/timescaledb-postgis` (проекту нужны расширения PostGIS/ltree).
### Auth / JWT (только `config.settings.production`)
Используются два механизма аутентификации (`REST_FRAMEWORK.DEFAULT_AUTHENTICATION_CLASSES`): `ZitadelJWTAuthentication` (заголовок `Identity`) и `rest_framework_simplejwt` (RS512).
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `SIMPLE_JWT_ISSUER` | string | `django` | Значение claim `iss` (проверяется при верификации токена) |
| `JWT_PRIVATE_KEY` | string (PEM) | — | Приватный RSA-ключ (подпись). Экранированные `\n` заменяются на переводы строк. Обязателен |
| `JWT_PUBLIC_KEY` | string (PEM) | — | Публичный RSA-ключ (проверка). Экранированные `\n` заменяются на переводы строк. Обязателен |
> `SIMPLE_JWT`: алгоритм `RS512`, `ACCESS_TOKEN_LIFETIME` 5 мин, `REFRESH_TOKEN_LIFETIME` 1 день, тип заголовка `Bearer`, claim пользователя — `user_id`.
### S3 — Yandex Object Storage (`base.py`, boto3/django-storages)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `YC_S3_ACCESS_KEY_ID` | string | `None` | Access key |
| `YC_S3_SECRET_ACCESS_KEY` | string | `None` | Secret key |
| `YC_S3_BUCKET_NAME` | string | `None` | Бакет по умолчанию |
| `YC_S3_ENDPOINT_URL` | string | `None` | Эндпоинт S3 |
> `DEFAULT_FILE_STORAGE`/`STATICFILES_STORAGE` — `storages.backends.s3boto3.S3Boto3Storage`, `AWS_DEFAULT_ACL=public-read`.
### Kafka (`base.py`, `config/kafka.py`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `KAFKA_ENABLED` | bool | `True` | Включить реального продюсера (иначе `MockProducer` — события не отправляются) |
| `KAFKA_HOST` | string | `""` | Адрес брокера (`bootstrap_servers`) |
| `KAFKA_USERNAME` | string | `platform` | Пользователь SASL |
| `KAFKA_PASSWORD` | string | `""` | Пароль SASL |
| `KAFKA_SSL_CAFILE` | string | `/usr/local/share/ca-certificates/Yandex/YandexInternalRootCA.crt` | CA-сертификат для TLS |
| `SASL_MECHANISM` | string | `SCRAM-SHA-512` | Механизм SASL |
| `SECURITY_PROTOCOL` | string | `SASL_SSL` | Протокол безопасности Kafka |
| `ASSETS_TOPIC` | string | `assets_broadcast_test` | Топик рассылки по ассетам |
Топики событий EAV:
| Переменная | Значение по умолчанию |
| --- | --- |
| `KAFKA_TOPIC_ATTRIBUTE_CREATED` | `eav.attribute.created.v1` |
| `KAFKA_TOPIC_ATTRIBUTE_UPDATED` | `eav.attribute.updated.v1` |
| `KAFKA_TOPIC_ATTRIBUTE_DELETED` | `eav.attribute.deleted.v1` |
| `KAFKA_TOPIC_VALUE_OPTION_CREATED` | `eav.value_option.created.v1` |
| `KAFKA_TOPIC_VALUE_OPTION_DELETED` | `eav.value_option.deleted.v1` |
### OpenTelemetry (`base.py`)
Блок трейсинга активируется, только если задана переменная `USE_OTEL` (проверяется через `os.getenv('USE_OTEL', False)` — истинно при любом непустом значении). Используется `django-otel-tools`; при включении в начало `MIDDLEWARE` добавляется `OtelMiddleware`.
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `USE_OTEL` | bool/string | `False` | Включить трейсинг и OTEL-логгер |
| `SERVICE_NAME` | string | `eav.eav-backend` | Имя сервиса в трейсах |
| `TRACER_ENDPOINT` | string | `localhost:4375` | Адрес OTLP-коллектора |
| `USE_INSECURE` | bool/string | `False` | Небезопасное (без TLS) подключение к коллектору |
| `ENVIRONMENT` | string | `prod` | Атрибут ресурса `environment` |
| `MODULE` | string | `eav` | Атрибут ресурса `module` |
| `TEAM` | string | `platform_team` | Атрибут ресурса `team` |
| `COMPONENT` | string | `backend` | Атрибут ресурса `component` |
## Переменные из Helm-чарта (`.helm/values-<env>.yaml`)
Обычные значения задаются в блоке `backend.deployment.envs` для каждого окружения (`stage`/`preprod`/`production`): `DJANGO_SETTINGS_MODULE`, `USE_OTEL`, `SERVICE_NAME`, `TRACER_ENDPOINT`, `USE_INSECURE`, `ENVIRONMENT`, `KAFKA_HOST`, `ASSETS_TOPIC` (различаются адресами коллектора/брокера и именами топиков).
Значения из секретов (блок `secrets`, монтируются как env через `secretKeyRef`):
| Переменная | Секрет (`secret_name`) | Ключ (`secret_key`) |
| --- | --- | --- |
| `DJANGO_POSTGRES_HOST` | `yc-pg-secret` | `host` |
| `DJANGO_POSTGRES_DATABASE` | `yc-pg-secret` | `database` |
| `DJANGO_POSTGRES_PORT` | `yc-pg-secret` | `port` (только preprod) |
| `DJANGO_POSTGRES_USER` | `yc-pg-secret` | `user` |
| `DJANGO_POSTGRES_PASSWORD` | `yc-pg-secret` | `password` |
| `DJANGO_CLICKHOUSE_HOST` | `yc-ch-secret` | `host` |
| `DJANGO_CLICKHOUSE_DATABASE` | `yc-ch-secret` | `database` |
| `DJANGO_CLICKHOUSE_USER` | `yc-ch-secret` | `user` |
| `DJANGO_CLICKHOUSE_PASSWORD` | `yc-ch-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` |
| `JWT_PRIVATE_KEY` | `jwt-secret` | `private_key` |
| `JWT_PUBLIC_KEY` | `jwt-secret` | `public_key` |
| `KAFKA_USERNAME` | `kafka-secret` / `yc-kafka-secret` | `username` |
| `KAFKA_PASSWORD` | `kafka-secret` / `yc-kafka-secret` | `password` |
| `KAFKA_HOST` | `yc-kafka-secret` | `host` (prod/stage) |
Помимо env, чарт монтирует CA-сертификаты: PostgreSQL (`yc-pg-certificate` → `~/.postgresql/root.crt`) и Yandex Internal Root CA (`yc-ch-certificate` → `/usr/local/share/ca-certificates/Yandex/YandexInternalRootCA.crt`, тот же путь, что в `KAFKA_SSL_CAFILE`), а также конфиг clickhouse-client.
## Переменные в infra-манифесте (Flux/Kustomize, `infra/iac/apps/eav`)
В отличие от Helm-чарта приложения, боевой деплой Sarex использует Vault-инъекцию (`base/backend-deployment.yaml`). Секреты рендерятся Vault-агентом в файлы `/vault/secrets/*` и экспортируются в окружение в `args` контейнера перед запуском `entrypoint.sh`:
| Переменная(ые) | Источник (Vault path) |
| --- | --- |
| `DJANGO_POSTGRES_HOST/PORT/DATABASE/USER/PASSWORD` | `secrets/data/postgresql/apps/eav` |
| `YC_S3_ENDPOINT_URL/BUCKET_NAME/ACCESS_KEY_ID/SECRET_ACCESS_KEY` | `secrets/data/minio/apps/eav` |
| `JWT_PRIVATE_KEY` / `JWT_PUBLIC_KEY` | `secrets/data/vault/common/rsa_keys` |
Прямо в `env` деплоймента задаются `KAFKA_ENABLED=False`, `ASSETS_TOPIC=sarex`, `DJANGO_SETTINGS_MODULE=config.settings.production`. Файл `production.py` монтируется из `django-configmap` (переопределяет `production.py` из образа; в нём `DEBUG=True`, `ALLOWED_HOSTS=['*']`, свои CORS/CSRF-домены и имена cookie `eav-sessionid`/`eav-csrftoken`).
## Замечания и потенциальные проблемы
- Приложение **не загружает `.env` автоматически** (нет `read_env`/`load_dotenv`). `python-dotenv` установлен, но не используется в настройках — переменные нужно экспортировать в окружение самому.
- Переменные БД (`DJANGO_POSTGRES_*`) и JWT (`JWT_PRIVATE_KEY`/`JWT_PUBLIC_KEY`) читаются **только** в `config.settings.production`. При `test`/`base` их отсутствие не мешает старту, но БД по умолчанию не сконфигурирована.
- `JWT_PRIVATE_KEY`/`JWT_PUBLIC_KEY` в `production.py` читаются через `env.str(...)` **без дефолта** — их отсутствие приводит к ошибке старта. В infra-варианте (`django-configmap`) используется `get_env_variable` с тем же требованием.
- `DJANGO_CLICKHOUSE_*` присутствуют в Helm-секретах, но **кодом приложения не читаются** (в текущих настройках ClickHouse не используется) — это подготовка/наследие инфраструктуры.
- `KAFKA_ENABLED`: при ложном значении используется `MockProducer` — события EAV в Kafka не публикуются (так сделано в infra-деплое: `KAFKA_ENABLED=False`). Значение разбирается `django-environ` как bool.
- Флаги OTEL (`USE_OTEL`, `USE_INSECURE`) читаются через `os.getenv(..., False)` и трактуются как истинные при **любой непустой строке**, включая `"False"`. Чтобы отключить — переменную нужно не задавать вовсе.
- `SERVICE_NAME` определяется дважды: как имя приложения (`base.py`, дефолт `eav`) и как имя сервиса в OTEL (дефолт `eav.eav-backend`) — фактически одна и та же переменная окружения.
- В `docker-compose.yml` захардкожен пароль БД (`zealot096`) — только для локального окружения.
## Минимальный набор для локального запуска (`config.settings.production`)
- `DJANGO_SETTINGS_MODULE=config.settings.production`
- `DJANGO_POSTGRES_HOST`, `DJANGO_POSTGRES_PORT`, `DJANGO_POSTGRES_DATABASE`, `DJANGO_POSTGRES_USER`, `DJANGO_POSTGRES_PASSWORD`
- `JWT_PRIVATE_KEY`, `JWT_PUBLIC_KEY` (обязательны; можно тестовую RSA-пару)
- `KAFKA_ENABLED=False` (чтобы не поднимать брокер) либо `KAFKA_HOST`/`KAFKA_USERNAME`/`KAFKA_PASSWORD`
- при работе с файлами: `YC_S3_ACCESS_KEY_ID`, `YC_S3_SECRET_ACCESS_KEY`, `YC_S3_BUCKET_NAME`, `YC_S3_ENDPOINT_URL`
- `USE_OTEL` — не задавать (иначе включится трейсинг)
Готовые значения-примеры для всех переменных приведены в `.env.example`.