iac/apps/mapper/CONFIGURATION.md

16 KiB
Raw Permalink Blame History

Конфигурация проекта mapper (flows mapper)

Документ описывает все переменные окружения и способы конфигурирования сервиса mapper — mini-HTTP-сервиса, который объединяет (мапит) данные сервисов документации (documentations) и процессов (flows), а также заметок (notes) и Django-бэкенда Sarex.

Способы конфигурирования

Сервис настраивается только через переменные окружения. Разбор выполняется в src/app/config.py через библиотеку pydantic-settings.

В отличие от многих сервисов, здесь нет единого корневого префикса и нет вложенного делимитера (env_nested_delimiter). Вместо этого каждая секция описана отдельным классом BaseSettings со своим env_prefix (задаётся во вложенном классе Config):

Класс env_prefix Секция
Settings — (без префикса) Корневые настройки (API_PREFIX)
LoggerSettings LOG_ Логирование
RedisSettings REDIS_ Кеш Redis
DocumentationSettings DOCUMENTATION_ HTTP-клиент сервиса документации
FlowSettings FLOW_ HTTP-клиент сервиса процессов
DjangoSettings DJANGO_ HTTP-клиент Django-бэкенда
NoteSettings NOTE_ HTTP-клиент сервиса заметок

DocumentationSettings, FlowSettings, DjangoSettings и NoteSettings наследуются от общего класса AsyncSessionManager (поля host, timeout, retries), поэтому у каждого из них одинаковый набор из трёх переменных: <PREFIX>_HOST, <PREFIX>_TIMEOUT, <PREFIX>_RETRIES.

Отдельного конфиг-файла (yaml/toml) у приложения нет. Приложение не загружает .env автоматически (в config.py не задан env_file, зависимости python-dotenv нет) — переменные нужно экспортировать в окружение самому, напр. set -a && . ./.env && set +a, либо пробрасывать через контейнер/оркестратор.

Источники переменных по способам запуска:

Способ запуска Откуда берутся переменные
Локально (uvicorn/gunicorn) Переменные окружения процесса. Redis поднимается через docker-compose.yaml (только сервис redis)
Контейнер Dockerfile → entrypoint.sh: gunicorn -w 4 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000 app.main:app
Kubernetes (Helm, из репозитория сервиса) .helm/values.yaml, блок universal-chart.services.backend.envs; деплой из .gitlab-ci.yml
Kubernetes (GitOps, инфра-репозиторий) iac/apps/mapper/*: Kustomize-база base/deployment.yaml (env + секреты Vault) и Flux HelmRelease в overlay'ах brusnika-*

Точки входа:

Команда Назначение
uvicorn main:app / python app/main.py Локальный запуск (в main.py порт 8002, host 0.0.0.0)
gunicorn -w 4 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000 app.main:app Прод-запуск (entrypoint.sh, порт 8000)

Стек: Python 3.10 (python:3.10-slim-buster), FastAPI, httpx (асинхронные клиенты), Redis (кеш), PyJWT (разбор токенов).

Переменные приложения

Дефолт — означает, что значение обязательно (иначе ошибка старта). Все дефолты ниже соответствуют коду config.py.

App (класс Settings)

Переменная Тип Значение по умолчанию Назначение
API_PREFIX string /api/v1 Префикс маршрутов API

Logger (LOG_*)

Переменная Тип Значение по умолчанию Назначение
LOG_LEVEL string INFO Уровень логирования (имя уровня logging; при неизвестном значении используется INFO)
LOG_FORMAT string [%(asctime)s] [%(levelname)s] [%(filename)s]: %(message)s Формат строки лога

Redis (REDIS_*)

Кеширует JSON-ответы внешних сервисов (по ключу "{user_id}_{url}").

Переменная Тип Значение по умолчанию Назначение
REDIS_USE bool True Включить кеш. При True на старте выполняется PING (падение при недоступном Redis)
REDIS_HOST string localhost Хост Redis
REDIS_PORT int 6379 Порт Redis
REDIS_DB int 0 Номер базы Redis
REDIS_EXPIRE_DAYS int 1 TTL записей кеша в днях (в секундах — expire_days * 24 * 3600)

HTTP-клиенты внешних сервисов

Все четыре клиента наследуют AsyncSessionManager (host, timeout, retries). Клиент httpx создаётся с verify=False (проверка TLS-сертификата отключена) и транспортом с числом ретраев retries. Токены пробрасываются заголовками Authorization (всегда) и Identity (в режиме Zitadel).

Секция / префикс Назначение Дефолт HOST
DOCUMENTATION_* Сервис документации (диски, документы, бандлы) https://stage-api.sarex.io/documentations/api/v1
FLOW_* Сервис процессов (flows, review-данные) https://stage-api.sarex.io/flows/api/v1
DJANGO_* Django-бэкенд Sarex (target-links) https://stage.sarex.io/api
NOTE_* Сервис заметок (notes) https://stage-api.sarex.io/notes/api/v1

Для каждого — три переменные (пример для FLOW):

Переменная Тип Значение по умолчанию Назначение
FLOW_HOST string см. выше Базовый URL сервиса
FLOW_TIMEOUT int 30 Таймаут запроса (сек)
FLOW_RETRIES int 3 Число повторов транспорта httpx

Аутентификация

Аутентификация выполняется в src/app/dependensies.py (get_user_data) на основе заголовков запроса и без проверки подписи токена (jwt.decode(..., options={"verify_signature": False})). Публичный ключ не используется, отдельных переменных для ключа нет.

Условие Режим Как извлекается user_id
Есть заголовки Authorization и Identity zitadel Из payload Identity-токена, поле urn:zitadel:iam:user:metadata.user_id (base64)
Есть только Authorization sarex Из payload основного токена, поле user_id
Заголовков нет — 401 Unauthorized

Переменные инфраструктуры и сборки

Не читаются кодом приложения, но участвуют в сборке/запуске.

Переменная Где используется Назначение
SERVICE_NAME .gitlab-ci.yml Имя сервиса (mapper), используется как CHART_NAME
DOCKERFILE_PATH .gitlab-ci.yml Путь к Dockerfile
BUILD_ARGS, CI_TRIGGER_SOURCE .gitlab-ci.yml Аргументы сборки / источник триггера (app)
IMAGE_NAME, CI_COMMIT_SHA, CI_PROJECT_URL, CI_JOB_URL, CI_PROJECT_NAMESPACE .gitlab-ci.yml (HELM_SET_ARGS) Прокидываются в universal-chart (образ, commit, ссылки, owner)

Переменные из Helm-чарта репозитория сервиса (.helm/values.yaml)

Чарт зависит от universal-chart (oci://cr.yandex/.../charts, версия 0.1.7). Переменные приложения задаются в блоке services.backend.envs с разбивкой по окружениям (_default/stage/preprod/production).

Переменная stage preprod production
DOCUMENTATION_HOST https://stage-api.sarex.io/documentations/api/v1 https://api.preprod.sarex.io/documentations/api/v1 https://api.sarex.io/documentations/api/v1
FLOW_HOST https://stage-api.sarex.io/flows/api/v1 https://api.preprod.sarex.io/flows/api/v1 https://api.sarex.io/flows/api/v1
DJANGO_HOST https://stage.sarex.io/api https://preprod.sarex.io/api https://lk.sarex.io/api
NOTE_HOST https://stage-api.sarex.io/notes/api/v1 https://api.preprod.sarex.io/notes/api/v1 https://api.sarex.io/notes/api/v1
REDIS_USE 0 0 0
TIMEOUT 120 120 120

Прочие параметры чарта (не переменные приложения): deployment.* (имя, порт 8000, replicaCount 1/1/3/3, ресурсы, probes.liveness/readiness — отключены), image.name (cr.yandex/.../mapper), service.* (ClusterIP, порт 8000), imagePullSecrets (dockerhub), labels.monitoring=prometheus.

Переменные из инфра-репозитория (iac/apps/mapper)

GitOps-деплой через Kustomize + Flux, namespace mapper. Здесь же лежит настоящий документ.

Структура:

Путь Назначение
base/ Базовый Kustomize (namespace, serviceaccount mapper-vault, deployment, service)
yc-k8s-test/ Overlay поверх base (патч replicas: 1)
brusnika-stage/ Flux HelmRelease (universal-chart), хосты test.sarex.brusnika.tech, imagePullSecrets: dockerhub
brusnika-prod/ Flux HelmRelease (universal-chart), хосты cde.brusnika.ru, imagePullSecrets: regcred

Обычные env в base/deployment.yaml (production-хосты Sarex):

Переменная Значение
DOCUMENTATION_HOST https://api.sarex.io/documentations/api/v1
FLOW_HOST https://api.sarex.io/flows/api/v1
DJANGO_HOST https://lk.sarex.io/api
NOTE_HOST https://api.sarex.io/notes/api/v1
REDIS_USE 0
TIMEOUT 120

Секреты монтируются через HashiCorp Vault Agent (аннотации vault.hashicorp.com/*, роль mapper) как файлы в /vault/secrets/*, которые перед стартом экспортируются в окружение (set -a && . /vault/secrets/... && set +a):

Файл секрета Источник (Vault path) Экспортируемые переменные
mapper-django-auth secrets/data/vault/common/django_auth MAPPER_DJANGO_TOKEN
mapper-db secrets/data/postgresql/apps/mapper MAPPER_DB_USER, MAPPER_DB_PASSWORD, MAPPER_DB_HOST, MAPPER_DB_PORT, MAPPER_DB_NAME
mapper-rabbitmq secrets/data/rabbitmq/apps/mapper MAPPER_RABBITMQ_VHOST, MAPPER_RABBITMQ_USERNAME, MAPPER_RABBITMQ_PASSWORD, MAPPER_RABBITMQ_HOST, MAPPER_RABBITMQ_PORT
mapper-s3 secrets/data/minio/apps/mapper MAPPER_S3_ENDPOINT, MAPPER_S3_REGION, MAPPER_S3_BUCKET, MAPPER_S3_ACCESS_KEY_ID, MAPPER_S3_SECRET_ACCESS_KEY
mapper-kafka secrets/data/kafka/apps/mapper MAPPER_KAFKA_BOOTSTRAP_SERVERS, MAPPER_KAFKA_SECURITY_PROTOCOL, MAPPER_KAFKA_SASL_MECHANISM, MAPPER_KAFKA_USERNAME, MAPPER_KAFKA_PASSWORD

Переменные в CI (.gitlab-ci.yml)

Пайплайн подключает шаблоны generic/common-ci (common-security-scan.yaml, universal-pipeline.yaml@apps-business) и переключает окружение по ветке/тегу:

Условие STAND Namespace CHART_VERSION
ветка stage stage platform 0.0.1-stage
ветка master preprod mapper-preprod 0.0.1-preprod
тег (CI_COMMIT_TAG) production mapper-prod 0.0.1-prod
merge request — (сборка образа отключена) — —

Стадия test: job linter (flake8 src/app, max-line-length=120) и typechecker (mypy src/app с types-redis; disallow_untyped_defs=True).

Замечания и потенциальные проблемы

  • TIMEOUT не читается приложением. В Helm/Kustomize задаётся TIMEOUT=120, но клиенты читают DOCUMENTATION_TIMEOUT/FLOW_TIMEOUT/DJANGO_TIMEOUT/NOTE_TIMEOUT (каждый со своим префиксом). Без префикса переменная игнорируется — реальный таймаут остаётся 30. Чтобы поднять таймаут, задавайте <PREFIX>_TIMEOUT.
  • Секреты Vault не используются кодом. MAPPER_DB_*, MAPPER_RABBITMQ_*, MAPPER_S3_*, MAPPER_KAFKA_*, MAPPER_DJANGO_TOKEN монтируются и экспортируются в окружение (base/deployment.yaml), но текущая версия приложения ни PostgreSQL, ни RabbitMQ, ни S3, ни Kafka, ни MAPPER_DJANGO_TOKEN не читает (в config.py таких настроек нет). Похоже, инфраструктура заготовлена наперёд либо унаследована из шаблона.
  • Кеш отключён во всех окружениях (REDIS_USE=0). При этом в get_response (utils.py) при не-200 ответе апстрима и выключенном кеше возвращается None, а роутер отдаёт 400 Bad Request. То есть при выключенном Redis запасного кеша нет.
  • Подпись JWT не проверяется (verify_signature=False) ни в режиме zitadel, ни в sarex. Доверие к токену — на сетевом слое (Istio/ingress). Публичный ключ не настраивается.
  • TLS-проверка апстримов отключена (httpx.AsyncClient(verify=False)) для всех четырёх клиентов.
  • Нет healthcheck-эндпоинта. Пробы liveness/readiness в чарте выключены — это согласовано.
  • Порты различаются: локально main.py слушает 8002, в контейнере gunicorn — 8000 (проброшен в k8s Service).
  • docker-compose.yaml поднимает только Redis (redis-stack-server); само приложение в compose не описано.

Минимальный набор для локального запуска

Поднять Redis (docker compose up redis) либо задать REDIS_USE=False, затем uvicorn main:app из src. Минимально стоит задать (у остальных есть рабочие дефолты для stage):

  • REDIS_USE (False, если Redis не поднят) и при необходимости REDIS_HOST/REDIS_PORT
  • при работе против нестандартных стендов — DOCUMENTATION_HOST, FLOW_HOST, DJANGO_HOST, NOTE_HOST
  • LOG_LEVEL (по желанию)

Готовые значения-примеры приведены в .env.example.