iac/apps/rfi/CONFIGURATION.md

212 lines
17 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.

# Конфигурация проекта rfi-backend
Документ описывает все переменные окружения и способы конфигурирования сервиса.
## Способы конфигурирования
Сервис — это Django-приложение (Django 5.1, Django REST Framework). Настройки лежат в пакете `src/config/settings/`:
- `base.py` — общие настройки (`DEBUG = True`), читает переменные через `os.getenv(...)`;
- `prod.py` — наследует `base.py` (`from .base import *`), выключает `DEBUG` и добавляет S3-хранилище (`django-storages` + `boto3`). Активируется через `DJANGO_SETTINGS_MODULE=config.settings.prod` (см. `docker/http/entrypoint.sh`).
Часть настроек уведомлений вынесена в отдельные классы `pydantic-settings` (`src/notifications/config.py`): `MailerConfig` (`env_prefix="MAILER_"`), `SarexBackendConfig` (`env_prefix="SAREX_BACKEND_"`), `NotificationsConfig` (`env_prefix="NOTIFICATIONS_"`). Эти классы имеют значения по умолчанию и переопределяются переменными окружения с соответствующим префиксом.
Отдельного конфиг-файла (yaml/toml) для приложения нет. Все настройки — переменные окружения процесса.
Источники переменных по способам запуска:
| Способ запуска | Откуда берутся переменные |
| --- | --- |
| Локально | `Makefile` через `SET_ENV`: `set -a; source .env; set +a`. Файл `.env` создаётся из `.env.template` вручную. `PYTHONPATH=src` обязателен |
| Docker (prod) | `docker/http/Dockerfile` + `entrypoint.sh`: миграции и `uwsgi` под `DJANGO_SETTINGS_MODULE=config.settings.prod`. Переменные пробрасываются рантаймом (Helm) |
| Kubernetes (Helm) | `.helm/values.yaml`: блоки `services.api.envs` / `services.api.secretEnvs` (и аналогичные для `services.celery`) universal-chart. Значения различаются по окружению (`_default`/`stage`/`preprod`/`production`) |
| CI/CD (GitLab) | `.gitlab-ci.yml`: `workflow.rules` переключают `STAND`/`NAMESPACE`, job `lint` гоняет ruff |
Точки входа и процессы:
| Процесс | Команда | Назначение |
| --- | --- | --- |
| HTTP API | `uv run src/manage.py runserver` (`make run`) / `uwsgi --ini uwsgi.ini` (prod) | Django REST API |
| Celery worker | `uv run celery -A config worker -l info` | Асинхронные задачи уведомлений (`notifications.tasks`) |
| Миграции | `uv run src/manage.py migrate` (`make migrate`) | Применение миграций (в контейнере — в `entrypoint.sh` перед стартом uwsgi) |
Приложение по умолчанию слушает порт **8000** (uwsgi `http = 0.0.0.0:8000`; Django `runserver` — тоже 8000). Внутрикластерный Service слушает порт 80 → targetPort 8000.
## Переменные приложения
Дефолт `—` означает, что значение обязательно (читается `os.getenv` без дефолта; при отсутствии будет `None`, что приведёт к ошибке подключения/старта соответствующей подсистемы).
### Django core
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `PYTHONPATH` | string | — | Должна быть `src` — корень пакета исходников |
| `DJANGO_SECRET_KEY` | string | — | Секретный ключ Django (`SECRET_KEY`) |
| `DJANGO_SETTINGS_MODULE` | string | `config.settings.base` | Модуль настроек. В контейнере — `config.settings.prod` |
Значения `DEBUG`, `ALLOWED_HOSTS = ["*"]`, `LANGUAGE_CODE = ru-ru`, `TIME_ZONE = UTC` заданы в коде и не читаются из окружения.
### Auth (`JWT_AUTH_ENABLE`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `JWT_AUTH_ENABLE` | bool (`True`/`true`) | `false` | Режим аутентификации. `true` — включаются `ZitadelJWTStatelessUserAuthentication` и `JWTStatelessUserAuthentication`; `false``DefaultUserAuthentication` (демо-пользователь `DefaultUser`, только для локальной разработки) |
Алгоритм JWT фиксирован в `SIMPLE_JWT``RS512`. Класс пользователя токена — `core.auth.User`.
### Database (`DB_*`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `DB_HOST` | string | — | Хост PostgreSQL |
| `DB_PORT` | int | — | Порт PostgreSQL |
| `DB_NAME` | string | — | Имя базы данных |
| `DB_USER` | string | — | Пользователь БД |
| `DB_PASSWORD` | string | — | Пароль пользователя БД |
Движок фиксирован: `django.db.backends.postgresql`.
### Sarex backend (`SAREX_BACKEND_*`)
Используется в `core/services.py` (получение пользователей `core/users/`, `users_by_sa/`) и в `notifications` (`SarexBackendConfig`). Авторизация — Basic (`Authorization: Basic <SAREX_BACKEND_AUTH>`).
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `SAREX_BACKEND_URL` | string | `https://stage.sarex.io` | Базовый URL sarex-backend |
| `SAREX_BACKEND_AUTH` | string (base64) | — | Basic-auth в виде `base64(username:password)` |
| `SAREX_BACKEND_TIMEOUT` | int | `30` | Таймаут запроса (используется `SarexBackendConfig`) |
### Внешние сервисы (EAV, Gateway, Resources)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `EAV_URL` | string | — | Базовый URL EAV-сервиса атрибутов (`core/services.get_attributes`) |
| `GATEWAY_URL` | string | — | Базовый URL gateway (`resources/`) для получения имени/списка ресурсов |
| `RESOURCES_API_HOST` | string | — | Адрес IAM/resources API. Задаётся в Helm (в `.env.template` отсутствует) |
### S3 / Object Storage (`YC_S3_*`)
Читаются только в `config/settings/prod.py` (backend хранилища — `storages.backends.s3boto3.S3Boto3Storage`, ACL `public-read`).
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `YC_S3_ACCESS_KEY_ID` | string | — | Access key (`AWS_ACCESS_KEY_ID`) |
| `YC_S3_SECRET_ACCESS_KEY` | string | — | Secret key (`AWS_SECRET_ACCESS_KEY`) |
| `YC_S3_BUCKET_NAME` | string | — | Бакет (`AWS_STORAGE_BUCKET_NAME`) |
| `YC_S3_ENDPOINT_URL` | string | — | Эндпоинт S3 (`AWS_S3_ENDPOINT_URL`) |
### Mailer (`MAILER_*`)
Настройки клиента почтового сервиса (`MailerConfig`).
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `MAILER_URL` | string | `http://mailer-service.mailer:8000` | URL mailer-сервиса |
| `MAILER_TIMEOUT` | int | `30` | Таймаут запроса (сек) |
### Notifications (`NOTIFICATIONS_*`)
Настройки подсистемы уведомлений (`NotificationsConfig`).
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `NOTIFICATIONS_ENABLE` | bool | `True` | Включить отправку уведомлений |
| `NOTIFICATIONS_EMAIL_FROM` | string | `hello@sarex.io` | Адрес отправителя |
| `NOTIFICATIONS_SERVICE_URL` | string | `https://stage.sarex.io/rfi` | Внешний URL сервиса (для ссылок в письмах) |
### RabbitMQ (`RABBITMQ_*`)
Используются при сборке `CELERY_BROKER_URL` в `settings/base.py`. У всех заданы дефолты.
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `RABBITMQ_USERNAME` | string | `mcc` | Пользователь |
| `RABBITMQ_PASSWORD` | string | `mcc` | Пароль |
| `RABBITMQ_HOST` | string | `rabbitmq-service` | Хост |
| `RABBITMQ_PORT` | int | `5672` | Порт (задаётся в Helm через `envs`) |
| `RABBITMQ_VHOST` | string | `api` | Виртуальный хост |
К итоговому URL добавляется `?heartbeat=30` (`BROKER_HEARTBEAT`). Прочие параметры брокера/Celery заданы в коде: `BROKER_POOL_LIMIT=10`, очередь `default`, `CELERY_TASK_SERIALIZER=json`, `CELERY_TIMEZONE=Europe/Moscow`, `CELERY_IMPORTS=("notifications.tasks",)`.
### Celery-поведение (`USE_ASYNC_FUNCTIONS`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `USE_ASYNC_FUNCTIONS` | bool | `True` | `True` — уведомления отправляются через `apply_async` (нужен работающий воркер и брокер); `False` — синхронно внутри запроса |
## Переменные из Helm-чарта (`.helm/values.yaml`)
Чарт — обёртка над `universal-chart` (`oci://cr.yandex/.../charts`, версия 0.1.7). Описаны два сервиса: `api` и `celery` (одинаковый образ `cr.yandex/crp3ccidau046kdj8g9q/rfi-backend`, разные команды и ресурсы). Значения выбираются по ключу `global.env` (`_default`/`stage`/`preprod`/`production`).
Обычные значения (`services.<svc>.envs`): `JWT_AUTH_ENABLE`, `SAREX_BACKEND_URL`, `EAV_URL`, `GATEWAY_URL`, `NOTIFICATIONS_ENABLE`, `NOTIFICATIONS_EMAIL_FROM`, `NOTIFICATIONS_SERVICE_URL`, `RABBITMQ_PORT`, `RABBITMQ_HOST`, `RESOURCES_API_HOST`.
Значения из секретов (`services.<svc>.secretEnvs`, монтируются как env через `secretKeyRef`):
| Переменная | Секрет (`_default`) | Секрет (`production`) | Ключ |
| --- | --- | --- | --- |
| `DJANGO_SECRET_KEY` | `rfi-backend-api-django-secret` | `django-secret` | `django_secret_key` |
| `DB_HOST` | `rfi-backend-api-ya-pg-secret` | `ya-pg-secret` | `host` |
| `DB_PORT` | `rfi-backend-api-ya-pg-secret` | `ya-pg-secret` | `port` |
| `DB_NAME` | `rfi-backend-api-ya-pg-secret` | `ya-pg-secret` | `dbname` |
| `DB_USER` | `rfi-backend-api-ya-pg-secret` | `ya-pg-secret` | `user` |
| `DB_PASSWORD` | `rfi-backend-api-ya-pg-secret` | `ya-pg-secret` | `password` |
| `SAREX_BACKEND_AUTH` | `django-secret` | `django-secret` | `token` |
| `YC_S3_ACCESS_KEY_ID` | `rfi-backend-api-yc-s3-secret` | `yc-s3-secret` | `key_id` |
| `YC_S3_SECRET_ACCESS_KEY` | `rfi-backend-api-yc-s3-secret` | `yc-s3-secret` | `access_key` |
| `YC_S3_BUCKET_NAME` | `rfi-backend-api-yc-s3-secret` | `yc-s3-secret` | `storage_bucket_name` |
| `YC_S3_ENDPOINT_URL` | `rfi-backend-api-yc-s3-secret` | `yc-s3-secret` | `endpoint_url` |
| `RABBITMQ_VHOST` | `rfi-backend-api-rabbitmq-secret` | `rabbitmq-secret` | `vhost` |
| `RABBITMQ_USERNAME` | `rfi-backend-api-rabbitmq-secret` | `rabbitmq-secret` | `username` |
| `RABBITMQ_PASSWORD` | `rfi-backend-api-rabbitmq-secret` | `rabbitmq-secret` | `password` |
Значения `envs` по окружениям (ключевые различия):
| Переменная | stage | preprod | production |
| --- | --- | --- | --- |
| `SAREX_BACKEND_URL` | `https://stage.sarex.io` | `https://perprod.sarex.io` | `https://lk.sarex.io` |
| `EAV_URL` | `http://eav-service.eav-stage` | `http://eav-service.eav-preprod` | `http://eav-service.eav-prod` |
| `GATEWAY_URL` | `https://stage-api.sarex.io/gateway` | `https://api.perprod.sarex.io/gateway` | `https://api.sarex.io/gateway` |
| `NOTIFICATIONS_SERVICE_URL` | `https://stage.sarex.io/rfi` | `https://perprod.sarex.io/rfi` | `https://lk.sarex.io/rfi` |
| `RABBITMQ_HOST` | `rabbitmq.rabbitmq.svc.cluster.local` | `rabbitmq.rabbitmq.svc.cluster.local` | `default-rabbit-cluster.rabbitmq.svc` |
| `RESOURCES_API_HOST` | `http://iams.platform.svc.cluster.local:8080` | `http://sarex-resources-service.resources-preprod` | `http://iams.iam.svc.cluster.local:8080` |
Прочие параметры чарта (не переменные приложения): `deployment.*` (имя, реплики — prod: api 2 / celery 2, ресурсы — api 1024Mi/1cpu, celery 512Mi/1cpu), `image.*`, `service.*` (ClusterIP, 80→8000), `imagePullSecrets: dockerhub`, `probes` (liveness/readiness выключены).
## Переменные в CI (`.gitlab-ci.yml`)
Пайплайн подключает общие шаблоны `generic/common-ci` (`common-security-scan.yaml`, `universal-pipeline.yaml`, ref `apps-business`). Общие переменные: `SERVICE_NAME=rfi-backend`, `DOCKERFILE_PATH=./docker/http/Dockerfile`, `CI_TRIGGER_SOURCE=app`.
Переключение окружения (`workflow.rules`):
| Условие | STAND | NAMESPACE | CHART_VERSION |
| --- | --- | --- | --- |
| ветка `stage` | `stage` | `proc` | `0.0.1-stage` |
| ветка `master` | `preprod` | `rfi-preprod` | `0.0.1-preprod` |
| тег (`CI_COMMIT_TAG`) | `production` | `rfi-prod` | `0.0.1-prod` |
| merge request | — | — | сборка образа отключена (`ENABLE_BUILD_IMAGE=false`) |
Через `HELM_SET_ARGS` в чарт прокидываются образ (`services.api.image.name.<env>`, `services.celery.image.name.<env>`), `global.env`, а также метаданные коммита/джобы (`commitSha`, `gitlabUri`, `gitlabJobUrl`, `owner`). Job `lint` (образ `ghcr.io/astral-sh/uv`) прогоняет `ruff check` и `ruff format --check`.
## Замечания и потенциальные проблемы
- `PYTHONPATH=src` обязателен: без него не находятся пакеты (`config`, `core`, `request` и т.д.). Задан в `.env.template` и в `Dockerfile` (`ENV PYTHONPATH=src`).
- Приложение не загружает `.env` автоматически: Django-настройки читают `os.getenv`, а `.env` подхватывается только через `Makefile` (`set -a; source .env`). При ручном запуске переменные нужно экспортировать самому.
- `JWT_AUTH_ENABLE=false` включает `DefaultUser` с захардкоженными `id=356`, `company_ids=[1, 38]` и полным набором прав — это только для локальной отладки, в проде должно быть `true`.
- S3 (`YC_S3_*`) читается только в `config.settings.prod`. При запуске с `config.settings.base` (локально) хранилище S3 не используется — файлы (аватар RFI) сохраняются локально.
- В `.env.template` переменные `RABBITMQ_*` и `RESOURCES_API_HOST` отсутствуют — для Celery используются дефолты из кода (`mcc`/`rabbitmq-service`/`api`), в кластере они приходят из Helm (`envs` + `secretEnvs`).
- В values.yaml значения preprod для sarex/gateway записаны как `perprod` (`https://perprod.sarex.io`, `.../api.perprod.sarex.io/...`) — так в исходнике; при необходимости свериться с фактическими адресами.
- `USE_ASYNC_FUNCTIONS` через `os.getenv("USE_ASYNC_FUNCTIONS", True)` возвращает строку при заданной переменной; пустая/незаданная даёт `True`. Любая непустая строка (в т.ч. `"False"`) трактуется как истинное значение в условии `if settings.USE_ASYNC_FUNCTIONS`.
## Минимальный набор для локального запуска
С включённым `config.settings.base` и `JWT_AUTH_ENABLE=false` минимально необходимо:
- `PYTHONPATH=src`, `DJANGO_SECRET_KEY`
- `DB_HOST`, `DB_PORT`, `DB_NAME`, `DB_USER`, `DB_PASSWORD` (поднять PostgreSQL)
- `SAREX_BACKEND_URL`, `SAREX_BACKEND_AUTH` (для обращений к sarex-backend)
- `EAV_URL`, `GATEWAY_URL` (для атрибутов и ресурсов)
- `NOTIFICATIONS_ENABLE=False` — чтобы не требовался mailer/брокер; либо `True` + `MAILER_URL` и работающий RabbitMQ
- `USE_ASYNC_FUNCTIONS=False` — чтобы уведомления шли синхронно без Celery-воркера
Порядок: `make migrate``make run` (API) и при необходимости `uv run celery -A config worker -l info` (воркер). Готовые значения-примеры — в `.env.example`.