Архитектура масштабирования
Mockarty изначально спроектирован как распределённая система. Независимо от того, запускаете ли вы один экземпляр для локальной разработки или разворачиваете десятки узлов в нескольких дата-центрах, архитектура остаётся той же – вы просто добавляете новые компоненты.
Аналогия: Представьте Mockarty как сеть пиццерий. Одна точка (один Admin Node) справляется со всем. Но по мере роста заказов вы добавляете курьеров (Mock Resolver), чтобы быстрее обслуживать клиентов, а основная кухня (Admin Node) занимается управлением меню и координацией. Если нужно тестировать новые рецепты (запускать тесты), вы организуете тестовую кухню (Runner Agent), чтобы не замедлять основную работу.
В этом руководстве описано, как компоненты взаимодействуют друг с другом, как их масштабировать и за чем наблюдать после запуска.
Примечание о Docker-образах: Официальные образы публикуются в Docker Hub как
mockarty/mockarty(admin),mockarty/resolver,mockarty/runner,mockarty/generatorиmockarty/cli. В сниппетах ниже могут встречаться другие реестры (например,ghcr.io/...) для иллюстрации — заменяйте их на реестр, который зеркалит ваша организация.
URL-адреса в примерах: Во всех примерах используется
localhost:5770как адрес Mockarty по умолчанию. Если ваш экземпляр работает на удалённом сервере, заменитеlocalhost:5770на реальный адрес (например,https://mockarty.company.comилиhttp://192.168.1.50:5770). Подробнее — в разделе Полезные функции и советы.
Обзор архитектуры
Mockarty состоит из четырёх типов компонентов, которые взаимодействуют по HTTP и gRPC:
Роли компонентов
| Компонент | Порт по умолчанию | Роль |
|---|---|---|
| Admin Node | 5770 (HTTP), 5773 (gRPC) | Центральный узел. Управляет моками, обслуживает UI, координирует раннеров, выполняет миграции. В каждом развёртывании ровно один Admin Node. |
| Mock Resolver | 5780+ | Лёгкие узлы, обрабатывающие входящие запросы к мокам. Читают определения моков из базы данных (с кешированием), но никогда не пишут. Можно запускать сколько угодно. |
| Runner Agent | 6770+ | Распределённые воркеры для выполнения API-тестов и нагрузочных тестов. Регистрируются у Координатора по gRPC и забирают задачи из очереди. |
| Coordinator | 5773 (gRPC, встроен в Admin) | gRPC-сервис, встроенный в Admin Node. Раннеры и резолверы регистрируются здесь, получают задачи и отправляют heartbeat-сигналы. |
Ключевая идея: Admin Node – единственный компонент, который пишет в базу данных. Резолверы только читают. Такое разделение позволяет масштабировать обработку запросов к мокам (чтение) независимо от нагрузки на Admin Node.

Как работает разрешение моков
Когда клиент отправляет запрос на узел-резолвер, происходит следующее:
Паттерн Composite Repository
Каждый узел (Admin и резолвер) использует Composite Repository, объединяющий три уровня хранения:
- Ristretto (кеш в памяти) — поиск за микросекунды. Всегда доступен, без внешних зависимостей. Хранит недавно запрошенные моки в ограниченном LRU-кеше.
- Redis (опционально, только admin-нода) — общий кеш на admin-ноде. Поиск за доли миллисекунды. Резолверы не используют Redis — они работают только с Ristretto.
- PostgreSQL (обязателен) — источник истины. Все записи сначала идут сюда. Чтение проваливается до PostgreSQL, если кеши не содержат нужных данных.
Путь чтения следует паттерну read-through:
Запись всегда идёт сначала в PostgreSQL, затем кеши обновляются синхронно, чтобы избежать устаревших данных сразу после записи. Composite-слой также обрабатывает конфликты сериализации с автоматическими повторами (до 3 попыток) для сценариев с высокой конкурентностью.
Горизонтальное масштабирование с помощью резолверов
Зачем нужны резолверы?
Admin Node выполняет множество задач: обслуживает UI, запускает фоновые процессы (очистка, бэкапы, планирование), координирует раннеров и обрабатывает запросы к мокам. При высокой нагрузке разрешение моков — самая частая операция — может «вытеснить» административные функции.
Резолверы решают эту проблему, перенося обработку моков на выделенные лёгкие процессы. Каждый резолвер:
- Обрабатывает только запросы к мокам (HTTP, gRPC, GraphQL, SOAP, SSE, WebSocket)
- Подключается напрямую к PostgreSQL (только чтение, требуется
DB_DSN) - Имеет собственный кеш Ristretto в памяти (без поддержки Redis)
- Регистрируется у Координатора для отслеживания состояния
Практическая ценность: добавление 3 резолверов позволяет обработать примерно в 4 раза больше трафика моков, не затрагивая Admin Node. Admin остаётся отзывчивым для работы с UI, управления API и оркестрации тестов.
Когда добавлять резолверы
| Симптом | Действие |
|---|---|
| Задержка ответа моков растёт под нагрузкой | Добавьте узлы-резолверы за балансировщиком нагрузки |
| UI Admin становится медленным во время нагрузочных тестов | Перенаправьте трафик моков на резолверы, оставьте Admin для UI/API |
| Нужна географическая распределённость | Разверните резолверы ближе к потребляющим сервисам |
| Нужно обновление моков без простоя | Резолверы подхватывают изменения из БД; перезапускайте их без остановки Admin |
Пример: 3 резолвера за Nginx
# docker-compose.scaling.yml
version: "3.8"
services:
postgres:
image: postgres:17-alpine
environment:
POSTGRES_DB: mockarty
POSTGRES_USER: mockarty
POSTGRES_PASSWORD: secret
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
ports:
- "6379:6379"
admin:
image: mockarty/admin:latest
environment:
DB_DSN: "postgres://mockarty:secret@postgres:5432/mockarty?sslmode=disable"
CACHE_TYPE: redis
REPO_REDIS_HOST: redis
REPO_REDIS_PORT: "6379"
HTTP_PORT: "5770"
RUNNER_GRPC_PORT: "5773"
ports:
- "5770:5770"
- "5773:5773"
depends_on:
- postgres
- redis
resolver-1:
image: mockarty/resolver:latest
environment:
DB_DSN: "postgres://mockarty:secret@postgres:5432/mockarty?sslmode=disable"
HTTP_PORT: "5780"
GRPC_PORT: "4780"
COORDINATOR_ADDR: admin:5773
API_TOKEN: "${RESOLVER_TOKEN}"
depends_on:
- admin
resolver-2:
image: mockarty/resolver:latest
environment:
DB_DSN: "postgres://mockarty:secret@postgres:5432/mockarty?sslmode=disable"
HTTP_PORT: "5780"
GRPC_PORT: "4780"
COORDINATOR_ADDR: admin:5773
API_TOKEN: "${RESOLVER_TOKEN}"
depends_on:
- admin
resolver-3:
image: mockarty/resolver:latest
environment:
DB_DSN: "postgres://mockarty:secret@postgres:5432/mockarty?sslmode=disable"
HTTP_PORT: "5780"
GRPC_PORT: "4780"
COORDINATOR_ADDR: admin:5773
API_TOKEN: "${RESOLVER_TOKEN}"
depends_on:
- admin
nginx:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- resolver-1
- resolver-2
- resolver-3
volumes:
pgdata:
nginx.conf для балансировки нагрузки:
events {
worker_connections 1024;
}
http {
upstream resolvers {
least_conn;
server resolver-1:5780;
server resolver-2:5780;
server resolver-3:5780;
}
server {
listen 80;
# Трафик разрешения моков → резолверы
location / {
proxy_pass http://resolvers;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
}
# Проверка работоспособности
location /health {
proxy_pass http://resolvers;
}
}
}
Ваши потребляющие сервисы обращаются к nginx:8080 для разрешения моков, а разработчики заходят на admin:5770 для работы с UI и управления API.
Архитектура Runner Agent
Runner Agent — это распределённые воркеры, выполняющие долгие задачи: коллекции API-тестов и нагрузочные тесты.
Возможности (Capabilities)
Каждый раннер объявляет свои возможности при регистрации:
| Возможность | Что выполняет |
|---|---|
api_test |
Коллекции API-тестов, запланированные тестовые наборы |
performance |
Скрипты нагрузочного/перформанс-тестирования |
Раннер может иметь несколько возможностей. Задаются через переменную окружения CAPABILITIES:
CAPABILITIES="api_test,performance"
Общие и пространственные раннеры
Раннеры могут работать в двух режимах:
- Общие раннеры (scope:
admin) — принимают задачи из любого пространства имён. Создаются с токенами интеграции административного уровня. Подходят для общей инфраструктуры. - Пространственные раннеры — принимают задачи только из назначенного пространства имён. Создаются с токенами интеграции, привязанными к пространству имён. Подходят для изоляции команд.
Процесс распределения задач
Настройка Runner Agent
# Обязательные
COORDINATOR_ADDR=mockarty:5773 # gRPC-адрес Координатора
API_TOKEN=mki_xxxxx # Токен интеграции (формат mki_*)
RUNNER_NAME=runner-1 # Уникальное имя раннера
# Опциональные
CAPABILITIES=api_test,performance # Что умеет этот раннер
SHARED=true # Принимать задачи из всех пространств имён
NAMESPACE=team-alpha # Только если SHARED=false
MAX_CONCURRENT_TASKS=3 # Макс. параллельных задач (по умолчанию: 3)
Heartbeat-сигналы и отказоустойчивость
Раннеры отправляют heartbeat-сигналы Координатору каждые несколько секунд (настраивается через RUNNER_HEARTBEAT_TIMEOUT, по умолчанию 30 секунд). Если раннер перестаёт отвечать:
- Координатор помечает его как офлайн после истечения таймаута heartbeat
- Все выполняемые задачи возвращаются в очередь для других раннеров
- Когда раннер возвращается, он автоматически перерегистрируется
Таймаут задачи по умолчанию — 30 минут (RUNNER_TASK_TIMEOUT), что предотвращает блокировку очереди зависшими задачами.
Уровни базы данных и кеширования
PostgreSQL — источник истины
PostgreSQL обязателен для любого продуктивного развёртывания. В нём хранятся:
- Все определения моков и их условия
- Данные хранилищ (Global, Chain, Mock stores)
- Коллекции API-тестов, результаты и расписания
- Учётные записи пользователей, сессии, политики RBAC
- Журналы аудита и конфигурации вебхуков
- Очередь задач раннеров и результаты
Рекомендуемая версия: PostgreSQL 14+ (улучшенная производительность JSON и оптимизация запросов).
SQLite поддерживается как альтернатива для одноузловых развёртываний (разработка, desktop, встраиваемые инсталляции). SQLite нельзя использовать при CLUSTER_MODE=true — advisory locks для выбора лидера требуют PostgreSQL.
MySQL не поддерживается. Константа
DB_USE=mysqlсуществует в коде как placeholder для будущего драйвера, но миграции и bootstrap реализованы только для PostgreSQL и SQLite. Не пытайтесь запускать Mockarty поверх MySQL — процесс завершится с ошибкой при применении миграций.
Redis — общий слой кеширования
Redis опционален и доступен только на admin-ноде. При включении (CACHE_TYPE=redis):
- Admin-нода использует Redis как общий слой кеширования наряду с Ristretto
- Инвалидация кеша работает через систему уведомлений об изменениях в БД
- Задержка разрешения моков на admin-ноде снижается до долей миллисекунды для закешированных моков
Примечание: Резолверы не поддерживают Redis. Они используют исключительно кеш Ristretto в памяти, а данные загружаются напрямую из PostgreSQL (требуется DB_DSN).
Настройка:
CACHE_TYPE=redis
REPO_REDIS_HOST=redis
REPO_REDIS_PORT=6379
REPO_REDIS_PASSWORD=secret # если включена аутентификация
Ristretto — кеш в памяти
На каждом узле (admin и резолвер) всегда используется кеш Ristretto в памяти. Это основной слой кеширования для резолверов. Он обеспечивает:
- Поиск с нулевой задержкой для часто используемых моков (микросекунды)
- Отсутствие внешних зависимостей
- Ограниченное потребление памяти с вытеснением по LRU
На admin-ноде, когда Redis также настроен, Ristretto работает как L1-кеш, а Redis как L2:
Выбор стратегии кеширования
| Развёртывание | CACHE_TYPE |
Почему |
|---|---|---|
| Один узел, разработка/тестирование | inmemory (по умолчанию) |
Redis не нужен. Ristretto справляется сам. |
| Продуктивная admin-нода | redis |
Admin-нода получает преимущество от Redis как L2-кеша наряду с Ristretto. |
| Несколько резолверов | inmemory |
Резолверы прогревают кеш Ristretto из PostgreSQL при запуске и периодически обновляют. |
Паттерны развёртывания
Паттерн 1: один узел (разработка / небольшие команды)
# Минимальный запуск с SQLite
DB_USE=sqlite ./mockarty
- Когда: локальная разработка, демонстрации, небольшие команды (< 5 человек), < 100 моков
- Плюсы: нулевая инфраструктура, один бинарник, мгновенный запуск
- Минусы: нет горизонтального масштабирования, ограничения SQLite при конкурентной записи
Паттерн 2: небольшая команда (PostgreSQL, Admin + 1 резолвер)
- Когда: команда из 5-20 человек, умеренный трафик моков, нужно сохранить отзывчивость UI
- Плюсы: Admin разгружен от трафика моков, простая настройка
- Минусы: резолвер — единая точка отказа для разрешения моков
Паттерн 3: средний (PostgreSQL + Redis, 2 резолвера, 1 раннер)
- Когда: 20-100 пользователей, сотни моков, автоматизированные тестовые пайплайны
- Плюсы: резервирование резолверов, общий Redis-кеш, распределённое выполнение тестов
- Рекомендуемые ресурсы: 2 CPU / 4 ГБ RAM на резолвер, 4 CPU / 8 ГБ RAM для Admin
Паттерн 4: крупный / корпоративный
- Когда: 100+ пользователей, тысячи моков, многокомандные пространства имён, требования к SLA
- Инфраструктура: PostgreSQL HA (primary + реплики), Redis Sentinel или Cluster, N резолверов за L7-балансировщиком, M раннеров (общие + по пространствам имён)
- Плюсы: отказоустойчивость, независимое масштабирование каждого уровня, изоляция пространств имён
Сетевая топология
Порты и протоколы
| Компонент | Порт | Протокол | Направление | Назначение |
|---|---|---|---|---|
| Admin Node | 5770 | HTTP/HTTPS | Входящий | Web UI, REST API, разрешение моков |
| Coordinator | 5773 | gRPC | Входящий | Регистрация раннеров/резолверов, распределение задач |
| Resolver | 5780+ | HTTP/HTTPS | Входящий | Только разрешение моков |
| Runner Agent | 6770+ | HTTP | Входящий (опционально) | Панель мониторинга раннера |
| PostgreSQL | 5432 | TCP | Внутренний | Подключения к БД от Admin и резолверов |
| Redis | 6379 | TCP | Внутренний | Подключения к кешу только от Admin |
TLS между компонентами
Координатор (gRPC) поддерживает TLS для связи раннер-Admin:
# Admin Node (TLS Координатора)
RUNNER_GRPC_TLS_ENABLED=true
RUNNER_GRPC_TLS_CERT_FILE=/path/to/server.crt
RUNNER_GRPC_TLS_KEY_FILE=/path/to/server.key
RUNNER_GRPC_TLS_DIR=.mockarty/tls
# Опционально: mTLS (взаимный TLS) — требовать клиентские сертификаты
RUNNER_GRPC_TLS_CLIENT_CA_CERT=/path/to/ca.crt
Если RUNNER_GRPC_TLS_ENABLED=true, но файлы сертификата/ключа не указаны, Mockarty автоматически генерирует самоподписанный сертификат в директории TLS.
Для продуктивных развёртываний используйте сертификаты, подписанные центром сертификации вашей организации, особенно если раннеры взаимодействуют через недоверенные сети.
Правила межсетевого экрана (минимум)
Admin → PostgreSQL :5432 (обязательно)
Admin → Redis :6379 (если CACHE_TYPE=redis)
Resolver → PostgreSQL :5432 (обязательно, только чтение)
Resolver → Admin :5773 (gRPC-регистрация)
Runner → Admin :5773 (gRPC, распределение задач + heartbeat)
Clients → Resolver :5780 (запросы к мокам, через балансировщик)
Developers → Admin :5770 (UI и управление API)
⚠️ Критично: Load Balancer обязателен для интеграций в кластерном режиме
ВАЖНОЕ ОГРАНИЧЕНИЕ: При запуске нескольких Admin-нод в кластерном режиме Runner Agent и Mock Resolver подключаются к координатору через gRPC по конкретному адресу ноды. При смене лидера (failover) интеграция теряет соединение и не может автоматически обнаружить нового лидера.
Проблема
Runner Agent и Mock Resolver настраиваются со статическим COORDINATOR_ADDR (например, mockarty-1:5773). При смене лидера новый координатор запускается на другой ноде (например, mockarty-2:5773). Runner/Resolver продолжает бесконечно пытаться подключиться к старому адресу.
Обязательное решение
Установите TCP/gRPC балансировщик нагрузки перед gRPC-портами всех Admin-нод (по умолчанию: 5773):
Runner Agent → Load Balancer :5773 → Admin Node 1 :5773 (лидер)
→ Admin Node 2 :5773 (follower)
→ Admin Node 3 :5773 (follower)
Пример конфигурации Nginx для gRPC:
upstream mockarty_coordinator {
server mockarty-1:5773;
server mockarty-2:5773;
server mockarty-3:5773;
}
server {
listen 5773 http2;
location / {
grpc_pass grpc://mockarty_coordinator;
grpc_next_upstream error timeout;
}
}
Без балансировщика
| Сценарий | Результат |
|---|---|
| 1 Admin-нода | ✅ Работает — failover не нужен |
| Несколько нод, без LB | ⚠️ Интеграции отключаются при смене лидера |
| Несколько нод, с LB | ✅ Автоматический failover через балансировщик |
По этой же причине Web UI (HTTP) также должен быть за балансировщиком при нескольких Admin-нодах.
Задачи, выполняемые только лидером
В кластерном режиме (CLUSTER_MODE=true) перечисленные ниже задачи запускаются только на лидере. Подчинённые ноды остаются живыми, обслуживают API-чтения и готовы перехватить лидерство при потере advisory lock в PostgreSQL, но не выполняют эти задачи:
| Задача | Почему только лидер |
|---|---|
| gRPC Coordinator (раннеры и резолверы) | Единая точка диспатча для очереди задач и heartbeat |
| Обработчик очереди задач | Исключает двойное назначение задачи разным раннерам |
| Монитор heartbeat раннеров | Единый источник истины о живости раннеров |
| Запланированные прогоны API Tester | Предотвращает дублирующиеся запланированные прогоны |
| Расписания фаззинга и performance-тестов | Аналогично — расписание должно срабатывать ровно один раз |
| Планировщик обслуживания БД | VACUUM / ANALYZE / retention cleanup |
| Планировщик очистки (устаревших прогонов и результатов) | Идемпотентен, но дешевле как singleton |
| Планировщик глобальной очистки | Межнеймспейсная очистка |
| Планировщик бэкапов | Только одна нода пишет артефакты бэкапа |
Каждая из этих задач обёрнута в leaderElector.RunWhileLeader(start, stop) — при смене лидера вызывается stop() на старом лидере и start() на новом. Это значит, что задержка failover = TTL advisory-lock + время раскрутки задачи на новом лидере. Учитывайте это при планировании ёмкости: одна хорошо размеренная admin-нода должна уметь нести все эти нагрузки, потому что в кластере из 3 нод только одна выполняет их в каждый момент времени.
Видимость для операторов: endpoint /health на лидере показывает эти планировщики как OK; на подчинённых нодах — как standby. Это нормальное поведение.
Планирование ёмкости
Ниже приведены ориентировочные значения для типичных нагрузок с моками. Реальные цифры зависят от сложности моков (количество условий, функции Faker, обращения к хранилищам, размер ответа).
Пропускная способность разрешения моков
| Конфигурация | Прибл. запросов/сек | Примечания |
|---|---|---|
| 1 Admin Node (без резолвера) | ~2 000 | Достаточно для разработки и небольших команд |
| 1 резолвер | ~5 000 | Кеш Ristretto обрабатывает большинство чтений |
| 3 резолвера + Nginx | ~15 000 | Почти линейное масштабирование с least_conn |
| 10 резолверов + LB | ~50 000+ | Продуктивный уровень для крупных организаций |
Рекомендации по ресурсам
| Компонент | CPU | RAM | Диск | Примечания |
|---|---|---|---|---|
| Admin Node | 2-4 ядра | 4-8 ГБ | 20 ГБ | Больше CPU при большом числе фоновых задач |
| Resolver | 1-2 ядра | 2-4 ГБ | Минимум | Без состояния; масштабируется горизонтально |
| Runner Agent | 2-4 ядра | 4-8 ГБ | 10 ГБ | Больше для нагрузочных тестов |
| PostgreSQL | 2-8 ядер | 8-32 ГБ | SSD | Размер зависит от количества моков и истории |
Когда масштабировать
| Метрика | Действие |
|---|---|
| p95 ответа моков > 100 мс | Добавить больше резолверов |
| Ответ UI Admin > 2 сек | Перенести трафик моков на резолверы |
| Исчерпание пула соединений БД | Добавить PgBouncer или увеличить max_connections |
| Очередь задач раннеров растёт | Добавить Runner Agent |
Мониторинг состояния
Эндпоинт /health
Каждый компонент предоставляет эндпоинт /health, возвращающий подробный статус:
curl -s http://localhost:5770/health | jq .
{
"status": "pass",
"releaseId": "1.2.3",
"uptime": "72h15m30s",
"system": {
"goVersion": "go1.24.1",
"goroutines": 142,
"cpus": 4,
"memAllocMb": "85.3",
"memSysMb": "210.7"
},
"components": {
"database": {
"status": "up",
"latency": "1.2ms"
},
"redis": {
"status": "up",
"latency": "0.3ms"
},
"scheduler": {
"status": "up"
},
"coordinator": {
"status": "up"
}
}
}
Поле status содержит "pass", когда все критические компоненты работоспособны, или "fail", если какой-либо обязательный компонент (например, база данных) недоступен. Некритические компоненты (например, Redis) возвращают "not_configured", если отключены.
Метрики Prometheus
Mockarty предоставляет метрики в формате Prometheus по адресу /metrics:
curl http://localhost:5770/metrics
Ключевые метрики для мониторинга:
| Метрика | Что показывает |
|---|---|
mockarty_http_request_duration_seconds |
Распределение задержки разрешения моков |
mockarty_http_requests_total |
Количество запросов по методу, эндпоинту, коду статуса |
mockarty_mock_requests_total |
Количество запросов к мокам по ID мока, неймспейсу, протоколу |
mockarty_db_query_duration_seconds |
Производительность запросов к БД |
mockarty_cache_hits_total / mockarty_cache_misses_total |
Эффективность кеширования по типу кеша |
mockarty_errors_total |
Количество ошибок по типу и компоненту |
Рекомендации по алертам
# Пример правил алертинга Prometheus
groups:
- name: mockarty
rules:
- alert: MockartyDown
expr: up{job="mockarty-admin"} == 0
for: 1m
labels:
severity: critical
- alert: HighMockLatency
expr: histogram_quantile(0.95, http_request_duration_seconds_bucket) > 0.5
for: 5m
labels:
severity: warning
annotations:
summary: "p95 ответа моков превышает 500 мс — рассмотрите добавление резолверов"
- alert: DatabaseSlow
expr: db_query_duration_seconds{quantile="0.99"} > 1
for: 5m
labels:
severity: warning
Лучшие практики
1. Разделяйте трафик моков и административный трафик
Самое важное решение при масштабировании: направляйте трафик тестируемых сервисов на выделенные резолверы, а не на Admin. Admin должен обрабатывать только доступ к UI и управление API.
2. Начинайте просто, масштабируйте по необходимости
Не усложняйте заранее. Один Admin Node с PostgreSQL обрабатывает тысячи запросов в секунду. Добавляйте резолверы только при обнаружении проблем с задержкой или пропускной способностью.
3. Масштабируйте резолверы горизонтально
Каждый резолвер прогревает свой кеш Ristretto независимо из PostgreSQL. Координатор отправляет обновления моков всем подключённым резолверам в реальном времени, поэтому кеши остаются консистентными. Добавляйте больше резолверов для обработки возросшего трафика.
4. Синхронизируйте версии резолверов с версией Admin
Все компоненты используют единую версию. При обновлении сначала обновляйте Admin Node (он выполняет миграции), затем накатывайте резолверы и раннеры. Никогда не запускайте резолверы с версией новее, чем у Admin.
5. Используйте пространственные раннеры для изоляции команд
В многокомандных средах выделяйте каждой команде раннер с привязкой к пространству имён. Это предотвращает ситуацию, когда дорогой нагрузочный тест одной команды блокирует набор API-тестов другой команды.
6. Мониторьте очередь задач
Растущая очередь задач означает, что раннеры не справляются с нагрузкой. Либо добавьте больше Runner Agent, либо проверьте, не зависают ли тесты (проверьте RUNNER_TASK_TIMEOUT).
7. Используйте пул соединений для PostgreSQL
В крупных развёртываниях с множеством резолверов каждый резолвер открывает собственный пул соединений. Используйте PgBouncer между резолверами и PostgreSQL для мультиплексирования соединений и предотвращения исчерпания max_connections.
8. Масштабируйте резолверы, а не CPU Admin
Если проблема в задержке моков, добавление CPU к Admin Node даёт убывающую отдачу, поскольку Admin выполняет множество задач. Выделенный резолвер использует все ресурсы для разрешения моков. Два небольших резолвера превосходят один мощный Admin Node по обработке трафика моков.
Частые ошибки
- Запуск резолверов на более новой версии, чем Admin Node. Всегда обновляйте Admin Node первым (он выполняет миграции БД), затем обновляйте резолверы и раннеры. Резолвер на более новой версии может ожидать изменения схемы БД, которые ещё не применены.
- Забыли
DB_DSNдля резолверов. Резолверы читают данные моков напрямую из PostgreSQL. Без валидногоDB_DSNони не могут разрешать моки. Это отличается от Admin Node, гдеDB_DSNочевидно обязателен. - Использование
mki_*токенов для REST API вызовов. Токены интеграции предназначены только для регистрации у gRPC-координатора (resolver/runner). Для автоматизации REST API (CI/CD, скрипты) используйте пользовательские API-токены (mk_*). - Направление трафика моков на Admin Node в продакшене. Admin Node обрабатывает UI, фоновые задачи, координацию И разрешение моков. Под нагрузкой разрешение моков вытеснит административные функции. Всегда используйте выделенные резолверы для продуктивного трафика моков.
- Отсутствие health check на балансировщике нагрузки. Без health check мёртвый резолвер продолжит получать трафик. Настройте балансировщик на проверку
GET /healthна каждом резолвере.
Kubernetes Operator и конфигурация на основе CRD
Kubernetes-оператор Mockarty управляет полным жизненным циклом кластера через пользовательский CRD MockartyCluster. Admin Node записывает желаемое состояние в CR, оператор приводит его в соответствие с ресурсами Kubernetes (Deployments, Services, ConfigMaps, NetworkPolicies), а стандартные контроллеры Kubernetes делают всё остальное.
Спецификация CRD MockartyCluster
CRD поддерживает следующие секции верхнего уровня:
| Секция | Назначение |
|---|---|
adminNode |
Развёртывание Admin Node (реплики, образ, ресурсы, переменные окружения) |
resolverNodes |
Пул Mock Resolver (реплики, образ, ресурсы, конфигурация HPA) |
runnerAgents |
Пул Runner Agent (реплики, образ, ресурсы) |
orchestrator |
Оркестратор Server Generator (опционально, реплики, образ) |
database |
Подключение к PostgreSQL (ссылка на секрет с DSN, размер пула) |
cache |
Подключение к Redis (хост, порт, ссылка на секрет) или in-memory |
tokenBootstrap |
Автоматическое создание токенов интеграции (включено/выключено) |
Минимальный пример
apiVersion: mockarty.io/v1alpha1
kind: MockartyCluster
metadata:
name: mockarty
namespace: mockarty
spec:
adminNode:
replicas: 1
image: ghcr.io/mockarty/mockarty:latest
resolverNodes:
replicas: 2
image: ghcr.io/mockarty/mockarty-resolver:latest
database:
dsnSecretRef:
name: mockarty-db
key: dsn
tokenBootstrap:
enabled: true
Полный пример с HPA и сетевыми политиками
apiVersion: mockarty.io/v1alpha1
kind: MockartyCluster
metadata:
name: mockarty-production
namespace: mockarty
spec:
adminNode:
replicas: 1
image: ghcr.io/mockarty/mockarty:1.3.0
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "2"
memory: "2Gi"
env:
- name: LOG_LEVEL
value: "info"
- name: COOKIE_SECURE
value: "true"
resolverNodes:
replicas: 3
image: ghcr.io/mockarty/mockarty-resolver:1.3.0
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "1"
memory: "1Gi"
hpa:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilization: 70
runnerAgents:
replicas: 2
image: ghcr.io/mockarty/mockarty-runner:1.3.0
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "1"
memory: "1Gi"
orchestrator:
replicas: 1
image: ghcr.io/mockarty/orchestrator:1.3.0
database:
dsnSecretRef:
name: mockarty-db
key: dsn
maxOpenConns: 25
cache:
type: redis
host: redis-master.mockarty.svc.cluster.local
port: 6379
passwordSecretRef:
name: mockarty-redis
key: password
tokenBootstrap:
enabled: true
networkPolicy:
enabled: true
allowIngressFrom:
- namespaceSelector:
matchLabels:
mockarty-access: "true"
Архитектурный поток
- Admin Node – пользователь настраивает кластер через Admin UI или REST API. Admin Node обновляет CR
MockartyClusterв Kubernetes, записывая желаемое состояние. - Оператор – отслеживает ресурсы
MockartyCluster. При каждом изменении приводит желаемое состояние в соответствие с конкретными объектами Kubernetes: Deployments, Services, ConfigMaps, HPA и NetworkPolicies. - Kubernetes – стандартные контроллеры (Deployment controller, HPA controller) управляют планированием, масштабированием и проверками здоровья.
Такое разделение означает, что Admin Node никогда не обращается к Kubernetes API для повседневных операций – он только записывает желаемое состояние. Оператор берёт на себя все императивные взаимодействия с Kubernetes.
Автоматическое создание токенов (Token Bootstrap)
Когда tokenBootstrap.enabled: true, оператор автоматически:
- Создаёт токены интеграции через API Admin Node после того, как Admin Node станет готов
- Сохраняет токены как Kubernetes Secrets (
mockarty-resolver-token,mockarty-runner-token) - Монтирует секреты в поды Resolver и Runner как переменные окружения
Для ручного управления токенами установите tokenBootstrap.enabled: false и создайте токены через Admin UI, затем укажите их в собственных Secrets.
Конфигурация HPA
Секция hpa в resolverNodes создаёт HorizontalPodAutoscaler:
minReplicas/maxReplicas– границы масштабированияtargetCPUUtilization– порог для масштабирования вверх (в процентах)
Резолверы – основная цель масштабирования, так как обрабатывают весь продуктивный трафик моков. Runner-агенты обычно масштабируются вручную в зависимости от тестовой нагрузки.
Сетевые политики
Когда networkPolicy.enabled: true, оператор создаёт ресурсы NetworkPolicy, которые:
- Разрешают входящий трафик к Admin Node только из указанных пространств имён или pod-селекторов
- Разрешают входящий трафик к резолверам от любого пода в кластере (трафик моков)
- Ограничивают исходящий трафик резолверов и раннеров до порта координатора Admin Node (5773) и базы данных
- Разрешают всем подам доступ к кешу (Redis)
Используйте allowIngressFrom, чтобы указать, какие пространства имён могут отправлять трафик моков к резолверам.
Связанная документация
- Руководство по развёртыванию в Docker — сборка и развёртывание контейнеров Mockarty
- Интеграции — настройка токенов интеграции для резолверов и раннеров
- Справочник API — полная документация REST API
- Руководство по настройке Admin — первоначальная настройка и первый запуск
- Нагрузочное тестирование — распределённое нагрузочное тестирование с помощью Runner Agent
- Фаззинг — автоматизированное тестирование безопасности API
- Контрактное тестирование — валидация моков по спецификациям API
- Хаос-тестирование — внедрение сбоев и задержек для проверки устойчивости системы