187 lines
17 KiB
Markdown
187 lines
17 KiB
Markdown
# Конфигурация проекта 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`.
|