Перейти к содержанию

Деплой, мониторинг и нагрузочное тестирование

Деплой

Exchange Engine

Расположение файлов: /exchange/deployment/ (23 файла)

Docker-образы

Используется multi-stage build: golang:1.25.10-alpinealpine:3.20. Dockerfile находится в корне репозитория.

Build args:

Аргумент Описание
APP_NAME Имя собираемого бинарника
VERSION Версия образа (используется в метаданных)

Тегирование: формат YYYYMMDD-COMMITHASH, например 20260306-0f1b10b

Собираемые образы (12 штук)

Группа Образы
Основные admin, api, engine
Topup Scan topupscan-btc, topupscan-evm, topupscan-tron, topupscan-processor, topupscan-aml-poller, topupscan-elliptic-check, topupscan-refund-processor
TX Processor txprocessor-btc, txprocessor-evm, txprocessor-tron
Hot Manager hotmanager-btc, hotmanager-evm, hotmanager-tron

Build-инструменты

  • Skaffold — конфигурация в skaffold.yaml, используется для локальной разработки и сборки
  • Makefile — основные цели:
make all      # сборка + lint + тесты
make build    # только сборка образов
make lint     # golangci-lint
make test-go  # запуск Go-тестов

Secrets

Секреты управляются через Sealed Secrets — зашифрованные манифесты хранятся в /deployment/sealed-secrets/.

CI/CD

GitHub Actions (.github/workflows/tests.yml) выполняет при каждом PR и пуше:

  • Go unit-тесты
  • golangci-lint — статический анализ кода
  • buf — lint и breaking-change проверки для Protobuf-схем

Kubernetes-ресурсы

resources:
  requests:
    cpu: 500m
    memory: 512Mi
  limits:
    cpu: 1000m
    memory: 1Gi

Метрики: каждый pod экспортирует Prometheus-метрики на порту 8081 по пути /metrics.


Univex Monorepo

Расположение: у каждого микросервиса свой подкаталог deployments/; актуальные stage-манифесты — в /stage-deployments/.

Docker-образы

Используется multi-stage build: golang:1.25.10 → минимальный runtime-образ. Dockerfile расположен внутри каждого микросервиса.

Kubernetes namespace: stage

Kubernetes-ресурсы

Параметр Requests Limits
CPU 100–200m 300m–1000m
Memory 256–512Mi 512Mi–2Gi

Диапазон зависит от нагрузки конкретного микросервиса.

Миграции БД

Для каждой базы данных запускается отдельный Kubernetes Job (migrator-job.yaml) с настройкой backoffLimit: 3. Миграция выполняется до старта основного Deployment.

Temporal Workers

Workers Temporal вынесены в отдельные Deployment-ресурсы и масштабируются независимо от HTTP/gRPC-сервисов.

Service mesh и hardening

Stage namespace stage включён в Istio mesh. Целевое состояние:

  • namespace и workload PeerAuthentication работают в STRICT mTLS;
  • DestinationRule stage-mesh-mtls использует ISTIO_MUTUAL для *.stage.svc.cluster.local;
  • privileged destinations закрыты AuthorizationPolicy allowlist-ами по service account и порту;
  • application pods запускаются non-root, с allowPrivilegeEscalation: false, RuntimeDefault seccomp, dropped capabilities и automountServiceAccountToken: false.

Быстрая проверка:

KUBECONFIG=../config kubectl -n stage get peerauthentication,destinationrule,authorizationpolicy

Важно

PeerAuthentication STRICT шифрует и аутентифицирует mesh-трафик, но сам по себе не ограничивает, какой workload может обращаться к destination. Для privileged services обязательно проверять наличие AuthorizationPolicy.


Базы данных stage

Docker Compose файл: /univex/ops/docker-compose-prod.yml

На DB-хосте nsc-db-1 развёрнуто 10 сервисных PostgreSQL баз данных, каждая с выделенным PgBouncer в режиме transaction pooling (max 100 connections на пул). PgBouncer слушает только tailnet-IP 100.123.97.86, требует TLS и доступен для k8s nodes на портах 6100-6110.

База данных PgBouncer-порт
univex-id 6100
exchange 6101
sms 6102
email 6103
sumsub 6104
p2p 6105
bot 6107
casbin 6108
exchange_int 6109
ledger 6110

Temporal использует отдельный PostgreSQL контейнер prod_temporal_psql на 100.123.97.86:6120 с direct PostgreSQL TLS и без PgBouncer.

Temporal

Temporal server развёрнут как Helm release temporal в namespace temporal. Он использует dedicated PostgreSQL на DB-хосте и имеет три реплики каждого основного компонента: frontend, history, matching, worker и web.

Операторские endpoints доступны только через Tailscale:

Endpoint Назначение
univex-temporal:7233 Temporal frontend gRPC через Tailscale
https://univex-temporal-ui.tailb72375.ts.net Temporal Web UI через Tailscale

Внутри кластера новый frontend доступен как temporal-frontend.temporal.svc.cluster.local:7233.

App deployments используют k8s Temporal напрямую. Legacy Temporal dev-server в tmux на nsc-db-1 выведен из эксплуатации и не должен запускаться для stage.


Ingress-паттерн

Все HTTP/WebSocket-сервисы используют единый шаблон ingress:

  • Ingress class: nginx
  • TLS: cert-manager с cluster-issuer letsencrypt (автоматическое получение сертификатов Let's Encrypt)
  • CORS: настраивается через аннотацию configuration-snippet с more_set_headers

WebSocket выносится в отдельный ingress с увеличенными таймаутами:

nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-buffering: "off"

Текущие публичные stage-домены:

Домен Назначение
univex.nostress.dev in-cluster product frontend
univex-admin.nostress.dev in-cluster admin frontend
api.univex.nostress.dev public gateway API
api.exchange.nostress.dev exchange REST API
ws.exchange.nostress.dev exchange WebSocket API
admapi.univex.nostress.dev admin gateway API
docs.univex.nostress.dev docs UI
hawk.univex.nostress.dev temporary Hawk placeholder

Frontend images are built in univex-web and deployed by stage-deployments/frontend-domains.yaml in the backend repo. They run as non-root containers with explicit resource requests/limits and cannot call stage services directly through the mesh.


Мониторинг (Grafana + Prometheus)

Расположение всех манифестов: /univex/monitoring/

Prometheus

Файл Назначение
prometheus-config.yaml Основная конфигурация: scrape jobs, targets
prometheus-deployment.yaml Kubernetes Deployment
prometheus-ingress.yaml Внешний доступ к UI
prometheus-rbac.yaml ServiceAccount + ClusterRole для service discovery

Scrape interval: 15 секунд

Prometheus автоматически собирает метрики со всех микросервисов:

  • Univex — порт метрик 8000
  • Exchange Engine — порт метрик 8081

Grafana

Файл Назначение
grafana-deployment.yaml Dev-окружение
grafana-prod-deployment.yaml Продакшн
grafana-ingress.yaml / grafana-prod-ingress.yaml Ingress для dev / prod
grafana-datasource.yaml Datasource: Prometheus
grafana-dashboard-provisioning.yaml Автоматическая загрузка дашбордов

Дашборды (16 штук)

Все дашборды хранятся как Kubernetes ConfigMap и подгружаются через provisioning при старте Grafana.

Дашборд Файл Ключевые метрики
Overview grafana-dashboard-overview.yaml Все сервисы: RPS, SLA, ошибки
Gateway grafana-dashboard-gateway.yaml univex_grpc, ledger_rpc, p2p_rpc
Admin Gateway grafana-dashboard-admin-gateway.yaml Admin gateway запросы
UnivexID grafana-dashboard-univex-id.yaml id_service RPC-метрики
Ledger grafana-dashboard-ledger.yaml ledger_rpc: запросы/мин, SLA%, ошибки
P2P grafana-dashboard-p2p.yaml p2p_rpc: запросы, длительность, ошибки
Exchange grafana-dashboard-exchange.yaml exchange_rpc, grpc_server
Exchange Integration grafana-dashboard-exchange-integration.yaml exchange_integration_rpc
Trades Aggregator grafana-dashboard-trades-aggregator.yaml trades_rpc
Email grafana-dashboard-email.yaml email_rpc
SMS Gate grafana-dashboard-sms-gate.yaml sms_rpc
Sumsub grafana-dashboard-sumsub-integration.yaml sumsub_rpc
Business grafana-dashboard-business.yaml Бизнес-метрики Univex
Exchange Business grafana-business-dashboard.yaml Exchange бизнес-метрики

Отслеживаемые метрики

На каждом дашборде отображаются:

  • RPC requests/min — количество запросов в минуту
  • Success rate (SLA%) — доля успешных ответов
  • Error rate — доля ошибочных ответов (4xx, 5xx, gRPC errors)
  • Latency percentiles — p50, p95, p99

Нагрузочное тестирование

Exchange Engine

ghz (gRPC benchmarking)

Файлы конфигураций: /exchange/deployment/loadtest-*.yaml (5 конфигураций)
Docker-образ: ghcr.io/bojand/ghz:latest
Тестируемый RPC: EngineService/AddOrder

Сценарий Описание Конкурентность Длительность
S3 local Локальный стакан 5 60s
S3 remote Удалённый стакан 5 60s
S5 BID Только BID-ордера 10 60s
S5 ASK Только ASK-ордера 10 60s
S5 prefill Prefill 30 000 ордеров + смешанная нагрузка 20 60s

cmd/bench (кастомный Go-инструмент)

Утилита находится в cmd/bench и позволяет гибко настраивать нагрузку:

./bench \
  -addr 127.0.0.1:1337 \
  -account-id <UUID> \
  -c 10 \
  -d 10s \
  -ticker BTCUSDT
Флаг Описание
-addr Адрес gRPC-сервера (TCP)
-unix Путь к Unix-сокету (альтернатива TCP)
-account-id UUID торгового аккаунта
-c Конкурентность (количество горутин)
-d Длительность теста
-ticker Торговая пара (например BTCUSDT)
-seed Сид для воспроизводимой генерации ордеров

Результат сравнения транспортов:

Транспорт RPS Latency
TCP базовый базовый
Unix socket +24% RPS −19% latency

Unix-сокет даёт существенный прирост производительности при локальном деплое (engine + клиент на одном узле).


Univex — Yandex.Tank

Phantom (GET-запросы)

Файл: /univex/load-testing/tank-pod.yaml

Target: gateway.<namespace>.svc.cluster.local:80
Instances: 3000
Timeout: 6s
Профиль нагрузки: line(1, 500, 60s) → const(500, 240s)
Итого: ~20 минут
Эндпоинтов: 29 GET-маршрутов

BFG (мутирующие операции)

Файл: /univex/load-testing/tank-bfg.yaml
Python-скрипт: load_script.py

Instances: 50
Профиль нагрузки: line(1, 70, 15s) → const(70, 15s)
Итого: ~10 минут

Тестируемые сценарии:

  • Payment methods — CRUD-операции
  • Blacklist — управление списком
  • Advertisements — создание и удаление объявлений

Autostop-условия

Тест автоматически останавливается при:

Условие Порог Окно
HTTP 5xx > 10% 30 сек
Сетевые ошибки > 25% 30 сек
Средняя задержка > 5 сек 30 сек

Запуск

# Phantom
kubectl apply -f tank-pod.yaml -n stage

# BFG
kubectl create configmap tank-bfg-script \
  --from-file=load_script.py -n stage
kubectl create configmap tank-bfg-ammo \
  --from-file=ammo.txt -n stage
kubectl apply -f tank-bfg.yaml -n stage

Результаты нагрузочного тестирования (4 марта 2026)

Метрика Значение
Всего запросов 541 148
Целевой RPS 500
Ошибок 0
Avg latency 11.6 мс
p95 latency 33 мс
p99 latency 47 мс
Оценка DAU ~1.2–1.4 млн пользователей