iac/apps/pm/CONFIGURATION.md

281 lines
23 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.

# Конфигурация проекта pm-backend
Документ описывает все переменные окружения и способы конфигурирования сервиса.
## Способы конфигурирования
Сервис — это Django-приложение (Django 5.1 + Django REST Framework), запускаемое как ASGI (`config.asgi_root:application`) через gunicorn с воркерами `uvicorn.workers.UvicornWorker`. Настройки читаются из переменных окружения через набор классов [`pydantic-settings`](https://docs.pydantic.dev/latest/concepts/pydantic_settings/), объявленных в `config/settings/base.py` и `config/settings/deps/*`.
Особенности разбора:
- **у каждой секции свой префикс** (`env_prefix`), напр. `SERVER_`, `DB_`, `S3_`, `CACHE_`, `CLICKHOUSE_`, `KAFKA_`, `CELERY_RABBITMQ_`, `CELERY_REDIS_`, `AUTH_`, `GATEWAY_`, `EAV_`, `DOCUMENTATION_`, `USERS_`, `RESOURCES_`, `TRACING_`, `SENTRY_`;
- **вложенного делимитера нет** — каждая настройка задаётся плоской переменной вида `<PREFIX><FIELD>`, напр. `DB_HOST`, `CELERY_RABBITMQ_VHOST`;
- **`extra='ignore'`** — все классы игнорируют посторонние переменные, поэтому один общий `.env` без ошибок разбирается всеми секциями;
- **`env_file='.env'`** — в отличие от эталонного сервиса, здесь `.env` **загружается автоматически** каждым классом настроек (у `SentrySettings``.env.base` и `.env`). Значения из реального окружения процесса имеют приоритет над файлом.
Отдельного конфиг-файла (yaml/toml) у приложения нет. `DJANGO_SETTINGS_MODULE` по умолчанию — `config.settings.base` (см. `manage.py`).
Источники переменных по способам запуска:
| Способ запуска | Откуда берутся переменные |
| --- | --- |
| Локально (manage.py / gunicorn) | Переменные окружения процесса + файл `.env` в корне репозитория (загружается pydantic-settings) |
| Локально (docker-compose) | `docker-compose.yaml` поднимает зависимости (postgres, redis, rabbit, clickhouse, minio, pgadmin); переменные приложения задаются через окружение/`.env` |
| Kubernetes (Helm) | `.helm/values.yaml`: блок `envs` (обычные значения) и `secretEnvs` (значения из k8s-секретов) для сервисов `api` и `celery`; чарт-зависимость `universal-chart` |
| CI/CD (GitLab) | `.gitlab-ci.yml`: переменные пайплайна (`workflow.rules`) и job-ы `linter`/`typechecker`/`linter_src` |
Способы запуска процессов:
| Процесс | Точка входа | Назначение |
| --- | --- | --- |
| HTTP API | `docker/entrypoint.sh``gunicorn config.asgi_root:application` (uvicorn worker, порт 8000) | REST API |
| Celery worker/beat | `celery -A config worker -B -Q pm …` (см. `.helm/values.yaml`, сервис `celery`) | Фоновые задачи и периодические (beat) |
| `manage.py migrate` | `manage.py` | Миграции БД |
| `manage.py clean_db` / `import_data` | `manage.py` | Служебные команды (см. `README.md`) |
## Переменные приложения
Ниже перечислены все секции настроек с их префиксами. Дефолт `—` означает отсутствие значения по умолчанию в коде.
### Server (`SERVER_*`)
Класс `ServerSettings` (`config/settings/base.py`).
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `SERVER_HOST` | string | `https://lk.sarex.io` | Внешний базовый URL (личный кабинет); из него формируется `SERVER_MEDIA_HOST` |
| `SERVER_API_HOST` | string | `https://api.sarex.io` | Базовый URL API-шлюза (используется внешними клиентами по умолчанию) |
| `SERVER_MEDIA_ROOT` | string | `sarex/media` | Каталог медиафайлов |
| `SERVER_DEBUG` | bool | `False` | Django DEBUG. При `True` также включает `FAKE_CELERY` и обход аутентификации в `JWTAuthentication` |
| `SERVER_ENABLE_SILK` | bool | `False` | Подключить профайлер django-silk (только при `DEBUG`) |
| `SERVER_ALLOWED_HOSTS` | list[str] (JSON) | `["*"]` | Django `ALLOWED_HOSTS` |
| `SERVER_SECRET_KEY` | string | `secret` | Django `SECRET_KEY` |
| `SERVER_USE_OTEL` | bool | `False` | Включить OpenTelemetry-трейсинг и OTel-логгер (см. секцию `TRACING_*`) |
| `SERVER_VERIFY_SSL` | bool | `True` | Проверять TLS-сертификаты при обращении к внешним сервисам |
| `SERVER_LOG_LEVEL` | enum | `INFO` | `DEBUG`/`INFO`/`WARNING`/`CRITICAL`/`FATAL` |
| `SERVER_ENABLE_SYNC_RESOURCES` | bool | `False` | Включить синхронизацию ресурсов |
| `SERVER_DELETED_TASK_MAX_AGE_DAYS` | int | `30` | Срок хранения удалённых задач (дней) |
| `SERVER_EXPIRED_TASK_NOTIFICATION_HOUR` | int | `9` | Час отправки уведомлений о просроченных задачах |
| `SERVER_EXPIRED_TASK_NOTIFICATION_MAX_DAYS` | int | `7` | Горизонт уведомлений о просрочке (дней) |
| `SERVER_SEND_UPDATED_PROJECTS_INFO_INTERVAL` | int | `5` | Интервал отправки информации об обновлённых проектах |
### Auth (`AUTH_*`)
Класс `AUTHSettings` (`config/settings/deps/auth.py`).
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `AUTH_ALGORITHM` | string | `RS512` | Алгоритм проверки подписи JWT |
| `AUTH_PUBLIC_KEY` | string | `''` | Публичный RSA-ключ для проверки JWT в режиме sarex-backend |
| `AUTH_PUBLIC_TOKEN_URL` | string | `https://lk.sarex.io/api/token/public/` | URL получения публичного ключа/токена |
Аутентификация DRF (`REST_FRAMEWORK.DEFAULT_AUTHENTICATION_CLASSES`) — по очереди `ZitadelJWTAuthentication`, затем `JWTAuthentication`; доступ по умолчанию `IsAuthenticated`. Zitadel-режим требует одновременно заголовки `Authorization` и `Identity`.
### Database (`DB_*`)
Класс `DBSettings` (`config/settings/deps/db.py`). PostgreSQL.
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `DB_ENGINE` | string | `django.db.backends.postgresql` | Движок Django ORM |
| `DB_HOST` | string | `localhost` | Хост PostgreSQL |
| `DB_PORT` | int | `5432` | Порт PostgreSQL |
| `DB_DATABASE` | string | `sarex_db` | Имя базы данных |
| `DB_USERNAME` | string | `sarex` | Пользователь БД |
| `DB_PASSWORD` | string | `sarex` | Пароль пользователя БД |
### S3 (`S3_*`)
Класс `S3Settings` (`config/settings/deps/s3.py`). Хранилище через django-storages (boto3), по умолчанию Yandex Object Storage.
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `S3_HOST` | string | `https://storage.yandexcloud.net` | Endpoint S3 |
| `S3_LOGIN` | string | `''` | Access key |
| `S3_PASSWORD` | string | `''` | Secret key |
| `S3_BUCKET` | string | `sarex-media-storage` | Бакет по умолчанию |
| `S3_VERIFY` | bool | `True` | Проверять TLS-сертификат |
### Cache (`CACHE_*`)
Класс `CacheSettings` (`config/settings/deps/cache.py`). Redis-кеш, включается отдельно.
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `CACHE_ENABLE` | bool | `False` | Включить кеш (иначе `CACHE_CLIENT=None`) |
| `CACHE_EXPIRATION` | int | `300` | TTL записей (сек) |
| `CACHE_HOST` | string | `localhost` | Хост Redis |
| `CACHE_PORT` | int | `6379` | Порт Redis |
| `CACHE_PASSWORD` | string \| null | `None` | Пароль |
| `CACHE_SSL` | bool | `False` | Подключение по TLS |
| `CACHE_SSL_CA_CERTS` | string \| null | `None` | Путь к CA-сертификату |
| `CACHE_QUEUE` | string | `default` | Имя очереди кеша |
### ClickHouse (`CLICKHOUSE_*`)
Класс `ClickHouseSettings` (`config/settings/deps/click_house.py`). Хранилище значений, включается отдельно.
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `CLICKHOUSE_ENABLE` | bool | `False` | Включить ClickHouse |
| `CLICKHOUSE_HOST` | string | `rc1d-…​.mdb.yandexcloud.net` | Хост |
| `CLICKHOUSE_PORT` | int | `9000` | Порт |
| `CLICKHOUSE_USER` | string | `''` | Пользователь |
| `CLICKHOUSE_PASSWORD` | string | `''` | Пароль |
| `CLICKHOUSE_DATABASE` | string | `values_db` | База данных |
| `CLICKHOUSE_TABLE` | string | `values` | Таблица |
| `CLICKHOUSE_SECURE` | bool | `False` | Защищённое подключение |
| `CLICKHOUSE_VERIFY` | bool | `False` | Проверять сертификат |
| `CLICKHOUSE_CERT` | string | `''` | Путь к CA-сертификату |
### Kafka (`KAFKA_*`)
Класс `KafkaSettings` (`config/settings/deps/kafka.py`). Продюсер сообщений, включается отдельно.
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `KAFKA_ENABLE` | bool | `False` | Включить продюсер (иначе `get_producer()` вернёт `None`) |
| `KAFKA_BOOTSTRAP_SERVERS` | list[str] (JSON) | `["localhost:9092"]` | Список брокеров |
| `KAFKA_SECURITY_PROTOCOL` | string | `''` | Протокол безопасности |
| `KAFKA_SASL_MECHANISM` | string | `''` | SASL-механизм |
| `KAFKA_SASL_PLAIN_USERNAME` | string | `user` | SASL-логин |
| `KAFKA_SASL_PLAIN_PASSWORD` | string | `password` | SASL-пароль |
| `KAFKA_SSL_CAFILE` | string | `''` | Путь к CA-сертификату |
| `KAFKA_TOPICS` | dict (JSON) | `{}` | Карта топиков, напр. `{"planning": "message-hub-stage"}` |
### Celery — RabbitMQ (`CELERY_RABBITMQ_*`)
Класс `CeleryRabbitMQ` (`config/settings/deps/celery.py`). Брокер задач; из полей собирается `BROKER_URL` (`amqp://…?heartbeat=30`).
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `CELERY_RABBITMQ_HOST` | string | `localhost` | Хост |
| `CELERY_RABBITMQ_PORT` | int | `5672` | Порт |
| `CELERY_RABBITMQ_USER` | string | `rabbit` | Пользователь |
| `CELERY_RABBITMQ_PASSWORD` | string | `rabbit` | Пароль |
| `CELERY_RABBITMQ_VHOST` | string | `api` | Виртуальный хост (в `.env`/helm — `pm`) |
### Celery — Redis (`CELERY_REDIS_*`)
Класс `CeleryRedis` (`config/settings/deps/celery.py`). Result backend; при `SSL=true` используется `rediss://` и `ssl_cert_reqs`.
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `CELERY_REDIS_HOST` | string | `redis` | Хост |
| `CELERY_REDIS_PORT` | int | `6379` | Порт |
| `CELERY_REDIS_DATABASE` | int | `0` | Номер БД Redis |
| `CELERY_REDIS_PASSWORD` | string \| null | `None` | Пароль (используется при SSL) |
| `CELERY_REDIS_SSL` | bool | `False` | Подключение по TLS (`rediss://`) |
| `CELERY_REDIS_SSL_CA_CERTS` | string \| null | `None` | Путь к CA-сертификату |
| `CELERY_REDIS_SSL_CERT_REQS` | string \| null | `required` | Требования к сертификату |
### HTTP-клиенты внешних сервисов
Общий базовый класс `BaseApiServiceMixin` (`config/settings/base.py`): поля `host` (по умолчанию `SERVER_API_HOST`), `api_prefix`, `internal_host`, `internal_prefix`, `timeout` (`10`), `enable` (`True`). Наследники задают собственные префиксы и дефолтные значения prefix.
| Секция / префикс | Класс | Назначение | Особенности |
| --- | --- | --- | --- |
| `GATEWAY_*` | `GateWaySetttings` | API-шлюз | `api_prefix=/gateway/api/v1` |
| `EAV_*` | `EAVSettings` | Сервис атрибутов (EAV) | `api_prefix=/eav/api/v0`, доп. `EAV_API_PREFIX_V1=/eav/api/v1` |
| `DOCUMENTATION_*` | `DocumentationSettings` | Сервис документаций | `api_prefix=/documentations/api/v1` |
| `USERS_*` | `UsersSettings` | Сервис пользователей (core) | `host=SERVER_HOST`, `api_prefix=/api/core`, `internal_host=http://localhost:8001`, `internal_prefix=/internal` |
| `RESOURCES_*` | `ResourceSettings` | Сервис ресурсов (IAM) | `internal_host=http://localhost:8001`, `internal_prefix=/api/v1` |
Для каждого клиента доступны переменные `<PREFIX>HOST`, `<PREFIX>API_PREFIX`, `<PREFIX>INTERNAL_HOST`, `<PREFIX>INTERNAL_PREFIX`, `<PREFIX>TIMEOUT`, `<PREFIX>ENABLE` (плюс `EAV_API_PREFIX_V1`).
### Tracing / OpenTelemetry (`TRACING_*`)
Класс `TracingConfig` (`config/settings/base.py`). Применяется только при `SERVER_USE_OTEL=true`.
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `TRACING_SERVICE_NAME` | string | `pm-backend.pm-pord` | Имя сервиса в трейсах |
| `TRACING_ENDPOINT` | string | `localhost:4317` | Адрес OTLP-коллектора |
| `TRACING_INSECURE` | bool | `False` | Небезопасное (без TLS) подключение |
| `TRACING_ENVIRONMENT` | string | `prod` | Окружение (атрибут трейса) |
| `TRACING_MODULE` | string | `planning` | Модуль (атрибут трейса) |
| `TRACING_TEAM` | string | `team_planning` | Команда (атрибут трейса) |
| `TRACING_COMPONENT` | string | `backend` | Компонент (атрибут трейса) |
### Sentry (`SENTRY_*`)
Класс `SentrySettings` (`config/settings/deps/sentry.py`). Читает `.env.base` и `.env`. Инициализируется при `SENTRY_USE=true`.
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `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` | Доля профилей |
## Переменные инфраструктуры, сборки и деплоя
Не читаются кодом приложения напрямую, но участвуют в запуске/сборке/деплое.
| Переменная | Где используется | Назначение |
| --- | --- | --- |
| `GUNICORN_WORKERS` | `docker/entrypoint.sh` | Число воркеров gunicorn (по умолчанию `4`) |
| `TIMEOUT` | `docker/entrypoint.sh` | Таймаут воркера gunicorn (по умолчанию `60`) |
| `NEXUS_USERNAME`, `NEXUS_PASSWORD` | `docker/Dockerfile` (build-arg), `.gitlab-ci.yml` | Доступ к приватному индексу пакетов Nexus |
| `SETTINGS_BASE_HOST` | `.helm/values.yaml` (env) | Базовый хост окружения (`stage`/`preprod`/`lk`) |
Порядок запуска контейнера (`docker/entrypoint.sh`): миграции закомментированы, сразу стартует gunicorn с ASGI-приложением `config.asgi_root:application`.
## Переменные из Helm-чарта (`.helm/values.yaml`)
Чарт зависит от `universal-chart` (`oci://cr.yandex/crp3ccidau046kdj8g9q/charts`). Значения задаются для двух сервисов — `api` и `celery`с ключами по окружениям `_default`/`stage`/`preprod`/`production`.
Обычные значения (блок `envs`) включают: `USERS_INTERNAL_HOST`, `CELERY_REDIS_HOST`, `RESOURCES_INTERNAL_HOST`, `EAV_HOST`, `EAV_API_PREFIX`, `EAV_API_PREFIX_V1`, `TRACING_ENDPOINT`, `TRACING_INSECURE`, `SERVER_ENABLE_SYNC_RESOURCES`, `SERVER_DELETED_TASK_MAX_AGE_DAYS`, `SERVER_EXPIRED_TASK_NOTIFICATION_HOUR`, `SETTINGS_BASE_HOST` (различаются адресами сервисов по окружениям).
Значения из секретов (блок `secretEnvs`, монтируются как env через `secretKeyRef`):
| Секрет (`secretName`) | Переменные |
| --- | --- |
| `ya-pg-secret-pm` | `DB_USERNAME`, `DB_PASSWORD`, `DB_DATABASE`, `DB_HOST`, `DB_PORT` |
| `ya-s3-secret-pm` | `S3_HOST`, `S3_LOGIN`, `S3_PASSWORD`, `S3_BUCKET` |
| `cache-secret-pm` | `CACHE_HOST`, `CACHE_PORT`, `CACHE_PASSWORD`, `CACHE_SSL`, `CACHE_SSL_CA_CERTS`, `CACHE_ENABLE` |
| `clickhouse-secret-pm` | `CLICKHOUSE_HOST`, `CLICKHOUSE_PORT`, `CLICKHOUSE_USER`, `CLICKHOUSE_PASSWORD`, `CLICKHOUSE_DATABASE`, `CLICKHOUSE_TABLE`, `CLICKHOUSE_SECURE`, `CLICKHOUSE_VERIFY`, `CLICKHOUSE_CERT`, `CLICKHOUSE_ENABLE` |
| `ya-kafka-secret-pm` | `KAFKA_ENABLE`, `KAFKA_BOOTSTRAP_SERVERS`, `KAFKA_SECURITY_PROTOCOL`, `KAFKA_SASL_MECHANISM`, `KAFKA_SASL_PLAIN_USERNAME`, `KAFKA_SASL_PLAIN_PASSWORD`, `KAFKA_SSL_CAFILE`, `KAFKA_TOPICS` |
| `rabbit-secret-pm` | `CELERY_RABBITMQ_HOST`, `CELERY_RABBITMQ_PORT`, `CELERY_RABBITMQ_USER`, `CELERY_RABBITMQ_PASSWORD`, `CELERY_RABBITMQ_VHOST` |
| `server-secret-pm` | `AUTH_PUBLIC_TOKEN_URL`, `SERVER_HOST`, `SERVER_API_HOST`, `SERVER_DEBUG`, `SERVER_ALLOWED_HOSTS`, `SERVER_VERIFY_SSL`, `SERVER_LOG_LEVEL` |
Дополнительно чарт монтирует CA-сертификат ClickHouse (configMap `ch-cert`, ключ `CA.pem`) как файл `/root/clickhouse/RootCA.crt` и `tmp-volume` в `/tmp`. Прочие значения чарта (не переменные приложения): `deployment.*` (имя, реплики, ресурсы, probes на `/api/health/`), `image.*`, `service.*`, `affinity`, `owner`.
## Переменные в CI (`.gitlab-ci.yml`)
Пайплайн подключает общие шаблоны из `generic/common-ci` (`common-security-scan.yaml`, `universal-pipeline.yaml@apps-business`) и переключает окружение по ветке/тегу через `workflow.rules`:
| Условие | STAND | NAMESPACE | CHART_VERSION |
| --- | --- | --- | --- |
| ветка `stage` | `stage` | `planning` | `0.0.1-stage` |
| ветка `master` | `preprod` | `pm-preprod` | `0.0.1-preprod` |
| тег (`CI_COMMIT_TAG`) | `production` | `pm-prod` | `0.0.1-prod` |
| merge request | — | — | сборка образа отключена (`ENABLE_BUILD_IMAGE=false`) |
Ключевые переменные пайплайна: `SERVICE_NAME=pm-backend`, `DOCKERFILE_PATH=docker/Dockerfile`, `RELEASE_NAME`, `CHART_NAME`, `K8S_HUSTLER_BRANCH`, `IMAGE_NAME`, `HELM_SET_ARGS` (`--set universal-chart.services.{api,celery}.image.name…` и метаданные коммита). Джобы стадии `test`: `linter` (flake8 по `sarex`), `typechecker` (mypy по `src`), `linter_src` (ruff check/format по `src`).
## Замечания и потенциальные проблемы
- При `SERVER_DEBUG=true` `JWTAuthentication` возвращает анонимного пользователя и **аутентификация обходится** — использовать только локально.
- Все секции читают `.env` автоматически (`env_file='.env'`), поэтому один общий `.env` в корне достаточен для локального запуска. `SentrySettings` дополнительно читает `.env.base`.
- Sentry инициализируется по умолчанию (`SENTRY_USE=true`), но при пустом `SENTRY_HOST` DSN не задан — задайте `SENTRY_USE=false` локально, чтобы отключить.
- `CELERY_RABBITMQ_VHOST` в коде по умолчанию `api`, тогда как в `.env.example`/helm используется `pm` — для корректной работы очереди значение должно совпадать с брокером.
- Переменные `CACHE_PASSWORD`/`CACHE_SSL_CA_CERTS`/`CELERY_REDIS_PASSWORD` допускают `None`; в `.env` для «пустого» значения используйте `None` или закомментируйте строку.
- Список-переменные (`SERVER_ALLOWED_HOSTS`, `KAFKA_BOOTSTRAP_SERVERS`) и dict (`KAFKA_TOPICS`) задаются в формате JSON.
## Минимальный набор для локального запуска
Зависимости (postgres, redis, rabbit, clickhouse, minio) поднимаются через `docker-compose up`. Минимально необходимо задать:
- `DB_HOST`, `DB_PORT`, `DB_DATABASE`, `DB_USERNAME`, `DB_PASSWORD`
- `S3_HOST`, `S3_BUCKET`, `S3_LOGIN`, `S3_PASSWORD`, `S3_VERIFY`
- `CELERY_RABBITMQ_*` (host/port/user/password/vhost) и `CELERY_REDIS_HOST`/`CELERY_REDIS_PORT`
- `SERVER_DEBUG=true` (локально), `SERVER_ALLOWED_HOSTS`, `SERVER_LOG_LEVEL`
- `AUTH_PUBLIC_KEY` (можно пустой при `SERVER_DEBUG=true`)
- адреса внешних сервисов при необходимости: `USERS_INTERNAL_HOST`, `RESOURCES_INTERNAL_HOST`, `EAV_HOST`
- `SENTRY_USE=false`, `SERVER_USE_OTEL=false` — чтобы не подключать Sentry/OTel локально
- опциональные подсистемы по флагам: `CACHE_ENABLE`, `CLICKHOUSE_ENABLE`, `KAFKA_ENABLE` (`0` по умолчанию)
Готовые значения-примеры приведены в `.env.example`.