Files
han-app/architectory/arch-03-docker-compose-blueprint.md
T
2026-07-09 12:39:52 +03:00

33 KiB
Raw Blame History

arch-03. Docker Compose blueprint

Термины (имена бакетов S3, идентификаторы) — в arch-00-glossary.md. Контракт Message Safety Service — в arch-02-api-contracts.md, раздел «api-backend ↔ message-safety». Переменные окружения и настройки — в arch-04-settings-and-content.md.

Назначение

Этот документ описывает целевой Docker Compose контур для первой production-like среды. Он не заменяет будущий docker-compose.yml, но задает требования, которым он должен соответствовать.

Требования к безопасности на уровне приложения и данных — в arch-01-system-architecture.md, раздел «Принципы безопасности». Настоящий документ описывает только инфраструктурную реализацию этих принципов в compose/nginx: TLS, маршрутизация, сетевые границы, rate limits на edge. Значения переменных окружения — в arch-04-settings-and-content.md. Дублировать прикладные требования (JWT, валидация, CORS в API, PII в логах и т.п.) здесь не нужно — они остаются в arch-01.

Единый compose-контур (обязательно)

Это зафиксированное архитектурное требование, а не рекомендация.

Принцип единого входа

  • Весь backend-контур поднимается одной командой docker compose up -d из корня репозитория (backend/).
  • Корневой docker-compose.yml — единственный источник правды для production-like среды. Отдельных compose-файлов для production-деплоя отдельных сервисов не должно быть.
  • Один nginx поднимается из корневого docker-compose.yml и является единой публичной точкой входа с маршрутизацией на все сервисы:
    • /api/*api-backend (REST и WS /api/v1/realtime; отдельный path /realtime/* не используется);
    • /auth/*keycloak;
    • /bitrix/* (public: /bitrix/handler, /bitrix/install, /bitrix/placement, /health/* для bitrix-local-app) → bitrix-local-app;
    • /bitrix/sync/* (public: webhook CRM sync для bitrix-sync) → bitrix-sync;
    • web-сборка frontend или прокси на dev-сервер;
    • /internal/openlines/*, /internal/safety/*, /internal/sync/* не публикуются наружу — доступны только из внутренней Docker-сети.
  • Никакой другой nginx (ни в контейнере сервиса, ни на хосте) не терминирует внешний HTTPS для backend-контура. Site-конфиг tohin.ru на хосте, если используется, должен проксировать весь трафик на корневой nginx контейнера, а не на порты отдельных сервисов напрямую.

Структура compose через include

Каждый сервис описывается в собственном docker-compose.yml внутри папки сервиса и подключается в корневой файл директивой include:

backend/
  docker-compose.yml                 # корневой: nginx + include сервисов + общие networks/volumes
  .env
  nginx/
    docker-compose.yml               # описание сервиса nginx (или секция в корневом)
    nginx.conf
    conf.d/
    certs/
      .gitkeep
  api-backend/
    docker-compose.yml               # описание сервиса api-backend
  message-safety/
    docker-compose.yml               # описание сервиса message-safety
  bitrix-sync/
    docker-compose.yml               # описание сервиса bitrix-sync
  bitrix-local-app/
    docker-compose.yml               # описание сервиса bitrix-local-app
  keycloak/
    docker-compose.yml               # описание сервиса keycloak (или секция в корневом)
  observability/
    docker-compose.yml               # otel-collector и т.п.

Корневой backend/docker-compose.yml (принципиальная схема):

name: han-chat

include:
  - nginx/docker-compose.yml
  - api-backend/docker-compose.yml
  - message-safety/docker-compose.yml
  - bitrix-sync/docker-compose.yml
  - bitrix-local-app/docker-compose.yml
  - keycloak/docker-compose.yml
  - redis/docker-compose.yml
  - observability/docker-compose.yml

networks:
  public:
  backend:
  observability:

volumes:
  redis-data:
  nginx-certs:

Правила для сервисных compose-файлов

  • Сервисный docker-compose.yml описывает только сервис(ы) своего модуля: образ, build context, environment (через ${VAR} из корневого .env), порты (только внутренние, кроме случаев ниже), depends_on, healthcheck, подключение к сетям public/backend/observability (объявленным в корневом файле).
  • Сервисный файл не объявляет сети и volumes верхнего уровня — они объявляются в корневом docker-compose.yml. Сервис только ссылается на них через networks: / volumes: (external-стиль не нужен, т.к. include объединяет файлы в один проект).
  • Публикация портов наружу (ports:) разрешена только для nginx (80/443). Все остальные сервисы используют expose: для внутренних портов и общаются через Docker-сети.
  • bitrix-local-app не публикует 8080 на хост (даже на 127.0.0.1) — он доступен api-backend и nginx через сеть backend/public. Ранее применявшийся 127.0.0.1:8080:8080 считаем устаревшим; проверки через curl на 127.0.0.1:8080 заменяются на docker compose exec bitrix-local-app или прокси через nginx.
  • Каждый сервисный compose-файл должен запускаться и в составе корневого контура, и автономно (docker compose -f bitrix-local-app/docker-compose.yml up) для локальной разработки сервиса — при условии, что переменные окружения заданы. Для автономного запуска сервис может объявлять заглушки сетей/volumes, но в составе корневого контура они переопределяются общими.

Команды разработки

docker compose up -d
docker compose logs -f nginx
docker compose logs -f api-backend
docker compose logs -f message-safety
docker compose logs -f bitrix-sync
docker compose logs -f bitrix-local-app
docker compose exec api-backend alembic upgrade head
docker compose exec api-backend pytest
docker compose exec api-backend ruff check .
docker compose exec api-backend ruff format .

Сервисы

nginx

Reverse proxy и единственная публичная точка входа в Docker Compose контур.

Требования:

  • публикует наружу только 80 и 443 (см. политику HTTP ниже);
  • принимает внешний HTTPS-трафик;
  • выполняет TLS termination на reverse proxy; внутренний HTTP между контейнерами — только в закрытой Docker-сети backend;
  • политика HTTP/HTTPS по доменам (каноническое правило — arch-01-system-architecture.md, «Принципы безопасности»):
    • веб-домен (frontend, SPA, статика): listen 80 допускается только для безусловного редиректа 301/308 на HTTPS; обработка бизнес-логики по HTTP запрещена;
    • API-домен (если выделен отдельный host, напр. api.example.ru): не слушает порт 80; только listen 443 ssl; HTTP-запросы к API-домену недоступны;
    • единый домен MVP (напр. tohin.ru с путями /api/*, /auth/*, web): считается веб-доменом; порт 80 — только redirect на HTTPS для всего server block; после редиректа весь пользовательский трафик — HTTPS;
    • auth на том же host, что API (/auth/*): следует политике host (redirect-only на :80 или HTTPS-only для выделенного API-host);
    • Bitrix callbacks (/bitrix/*, /bitrix/sync/*): только HTTPS; порт 80 не обслуживает эти location — только redirect;
  • маршрутизирует /api/* в api-backend (включая WebSocket upgrade для /api/v1/realtime);
  • маршрутизирует /auth/* в keycloak или проксирует отдельный auth-домен;
  • маршрутизирует публичные /bitrix/* endpoint в bitrix-local-app;
  • маршрутизирует /bitrix/sync/* webhook endpoint в bitrix-sync;
  • закрывает /internal/* (в т.ч. bitrix-local-app, message-safety, bitrix-sync ops) от публичного доступа — только private network Docker/VPC;
  • не публикует message-safety наружу;
  • production-like / production: отдаёт статическую сборку Expo web из volume или каталога (/usr/share/nginx/html или аналог); index.html + assets, SPA fallback try_files $uri /index.html;
  • local dev (опционально): при FRONTEND_DEV_PROXY_ENABLED=true проксирует / на Expo dev server (EXPO_DEV_SERVER_URL, напр. http://host.docker.internal:8081);
  • передает upstream-сервисам Host, X-Real-IP, X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host, X-Request-ID;
  • если входящий запрос без X-Request-ID, nginx генерирует UUID и устанавливает заголовок до proxy_pass (I3);
  • задает разумные proxy_connect_timeout, proxy_read_timeout, client_max_body_size;
  • применяет edge rate limits для auth, API и download endpoints;
  • ограничивает частоту соединений и размер тела запроса;
  • разрешает только TLS 1.2/1.3 и запрещает слабые шифры;
  • добавляет HSTS и базовые security headers;
  • скрывает заголовки, раскрывающие внутренние технологии;
  • кэширует публичные endpoint настроек и контента;
  • не проксирует наружу managed PostgreSQL, redis, otel-collector (БД вне compose, в VPC);

api-backend

Python FastAPI backend.

Требования:

  • запускается после доступности managed PostgreSQL, keycloak, redis;
  • применяет настройки из .env;
  • отдает /health/live и /health/ready;
  • корректно работает за reverse proxy и доверяет proxy headers только от nginx;
  • применяет API-level rate limits с состоянием в Redis;
  • вызывает message safety pipeline для сообщений до отправки в Open Lines;
  • вызывает bitrix-local-app для отправки сообщений в Open Lines;
  • принимает forward нормализованных событий оператора от bitrix-local-app;
  • поддерживает realtime endpoint для сообщений оператора;
  • работает с Selectel S3 для файлов и документов;
  • экспортирует traces/logs в otel-collector;
  • не хранит состояние внутри контейнера.

message-safety

Отдельный backend-сервис проверки входящих сообщений пользователя. HTTP-контракт — в arch-02-api-contracts.md, раздел «api-backend ↔ message-safety».

Требования:

  • запускается после доступности managed PostgreSQL (схема message_safety), redis;
  • не публикуется через nginx — доступен только из внутренней Docker-сети;
  • отдаёт /health/live и /health/ready (ready проверяет PostgreSQL, Redis, workers, read-доступ к S3-quarantine);
  • exposing endpoints: POST /internal/safety/v1/messages/check, GET /internal/safety/v1/messages/tasks/{task_id} (internal Docker network + X-Service-Token / MESSAGE_SAFETY_SERVICE_TOKEN);
  • read-only доступ к S3-quarantine (отдельный access key без прав записи);
  • использует отдельную схему message_safety в managed PostgreSQL и отдельный DB-user;
  • использует Redis (отдельная DB, напр. redis://redis:6379/2) для verdict cache и rate limits;
  • запускает async workers для file scan из S3-quarantine;
  • экспортирует traces/logs в otel-collector;
  • таймауты: POST check 5 s, GET task 2 s, file scan 60 s (см. arch-04-settings-and-content.md, переменные MESSAGE_SAFETY_*).

bitrix-sync

Python worker/service двусторонней синхронизации App DB ↔ Bitrix24 CRM.

Требования:

  • запускается после готовности managed PostgreSQL, redis;
  • читает задачи из han_app.sync_queue (заполняется триггерами App DB);
  • имеет прямой доступ к han_app (BITRIX_SYNC_APP_DATABASE_URL) и схеме bitrix_sync;
  • выполняет map/create Contact по телефону (интервал BITRIX_SYNC_CONTACT_MAP_INTERVAL_SEC, default 60);
  • push обновлений Contact (интервал BITRIX_SYNC_CONTACT_UPDATE_INTERVAL_SEC, default 30);
  • принимает webhook POST /bitrix/sync/webhook/contact от роботов Bitrix24;
  • при записи в App DB от Bitrix использует GUC han.sync_suppress=true;
  • поддерживает graceful shutdown и rate limiting Bitrix REST;
  • не блокирует пользовательский API при ошибках Битрикс24;
  • не участвует в OTP-flow, не создаёт UserIdentity/ClientProfile;
  • не участвует в hot path чата Open Lines;
  • включается/отключается флагом BITRIX_SYNC_ENABLED в .env (default true): при false сервис не стартует или работает в no-op (синхронизация с Bitrix24 CRM не выполняется).

bitrix-local-app

Локальное приложение Bitrix24 и custom connector han_mobile_app.

Требования:

  • публикует наружу только /bitrix/handler, /bitrix/install, /bitrix/placement, /health/live, /health/ready;
  • принимает ONAPPINSTALL и ONIMCONNECTOR* события от Bitrix24;
  • регистрирует и активирует connector han_mobile_app для открытой линии 8;
  • хранит OAuth-токены Bitrix24, inbox событий и dialog_sessions в managed PostgreSQL, схема bitrix_local;
  • предоставляет internal API POST /internal/openlines/v1/messages и GET /internal/openlines/v1/dialogs/{external_chat_id} для api-backend;
  • защищает internal API через Authorization: Bearer {BITRIX_INTERNAL_API_TOKEN};
  • forward-ит нормализованные события Open Lines в API, если задан BITRIX_API_FORWARD_URL;
  • не хранит бизнес-данные приложения и не пишет напрямую в App DB.

Managed PostgreSQL

Во всех средах (production, production-like, local dev) данные хранятся в managed PostgreSQL провайдера. Контейнер PostgreSQL в Docker Compose не используется — ни для production, ни для локальной разработки.

Прикладные данные, Keycloak, bitrix-sync, bitrix-local-app и message-safety подключаются к одной managed базе по URL из .env (HAN_PG_HOST, HAN_PG_PORT, HAN_PG_DATABASE и схемо-специфичные *_DATABASE_URL).

Требования:

  • подключение только из приватной сети VPC (VM → managed PostgreSQL);
  • одна managed база: схемы han_app, bitrix_sync, message_safety, bitrix_local, keycloak;
  • отдельные DB-пользователи с доступом только к своей схеме; исключение: bitrix_sync_user дополнительно имеет ограниченный GRANT на han_app (sync_queue, entity_external_mapping, tracked columns профиля — детали схемы TBD в спецификации database);
  • TLS к managed PostgreSQL обязателен;
  • миграции Alembic выполняются отдельной командой при деплое;
  • бэкапы и PITR — на стороне провайдера.

keycloak

Identity provider. Обязателен в compose-контуре с первого запуска.

Требования:

  • отдельный realm для приложения;
  • отдельный frontend client с PKCE (обязателен);
  • confidential backend client — optional (не используется в hot path MVP; S2S между сервисами — service tokens);
  • публичный issuer должен соответствовать HTTPS URL, видимому frontend-приложению;
  • включены proxy settings для работы за nginx;
  • импорт realm в local/dev;
  • использует managed PostgreSQL, схема keycloak (см. раздел «Managed PostgreSQL» выше);
  • OTP mock / SMS SPI — см. arch-04;
  • healthcheck;
  • взаимодействия — arch-02-api-contracts.md, «Frontend ↔ Keycloak», и arch-01-system-architecture.md, «Keycloak».

redis

Кэш, rate limiting, coordination (не единственное хранилище бизнес-событий).

Требования:

  • не использовать как единственное надежное хранилище бизнес-событий;
  • хранить счетчики API-level rate limits и idempotency keys (api-backend);
  • поддерживать TTL для лимитных и idempotency ключей;
  • не хранить OTP counters для api-backend (OTP — зона Keycloak/SPI);
  • sync_queue хранится в PostgreSQL (han_app), Redis может использоваться для wake-up/locking/queue optimization;
  • разделение DB index (I4): см. arch-04 (REDIS_URL, MESSAGE_SAFETY_REDIS_URL).

otel-collector

Принимает telemetry от сервисов.

Требования:

  • OTLP HTTP/gRPC receiver;
  • экспорт traces/logs в stdout или платформенный collector;
  • единые resource attributes: service.name, deployment.environment.

Networks

Рекомендуемые сети:

  • public: nginx, keycloak (для прокси /auth/*), frontend static/dev access, внешний HTTPS entrypoint.
  • backend: api-backend, message-safety, bitrix-sync, bitrix-local-app, keycloak, redis (managed PostgreSQL — вне compose, в VPC).
  • observability: otel-collector + сервисы, экспортирующие telemetry.

Базы данных, Redis, Keycloak internal port и API internal port не должны публиковаться наружу. message-safety доступен только внутри сети backend. Основной пользовательский путь должен идти через nginx и HTTPS.

Volumes

Минимальные volumes (production на одной VM):

  • redis-data (опционально, если нужна персистентность);
  • certbot / TLS volumes для nginx.

Данные PostgreSQL не хранятся в Docker volumes — только managed PostgreSQL вне compose.

Переменные окружения

Корневой backend/.env читается всеми сервисами compose через ${VAR} в сервисных docker-compose.yml. Канонический .env.example, service tokens, app_settings — в arch-04-settings-and-content.md.

HTTPS и TLS

Соответствует arch-01-system-architecture.md, «Принципы безопасности» (HTTPS, TLS, HSTS). Инфраструктурная реализация:

Домены и HTTP

Host Порт 80 Порт 443 Примечание
Веб-домен (frontend) только 301/308 → HTTPS HTTPS, бизнес-логика MVP: tohin.ru / app.example.ru
API-домен (если выделен) не слушает только HTTPS Post-MVP: api.example.ru
Bitrix callbacks (/bitrix/*, /bitrix/sync/*) не обслуживает API; только redirect на том же host HTTPS webhook и install URL

Правила:

  • все внешние пользовательские соединения — HTTPS;
  • HTTP допускается только на веб-домене как вход для редиректа на HTTPS;
  • для выделенного API-домена HTTP не допускается (нет listener на :80);
  • при едином домене MVP redirect на :80 применяется ко всему host, включая /api/* и /auth/*, после редиректа — только HTTPS.

TLS и заголовки

  • cookies в web-клиенте: Secure, HttpOnly, корректный SameSite;
  • OIDC redirect URI в Keycloak — HTTPS;
  • KEYCLOAK_PUBLIC_URL, issuer и frontend auth discovery URL совпадают по схеме, host и path;
  • backend формирует внешние ссылки с учётом X-Forwarded-Proto=https;
  • HSTS включается в production-like среде после проверки доменов и сертификатов;
  • TLS 1.0/1.1 запрещены; минимум TLS 1.2, предпочтительно TLS 1.3;
  • слабые шифры запрещены на уровне nginx;
  • nginx скрывает Server, X-Powered-By и аналогичные технологические заголовки;
  • security headers: Strict-Transport-Security, X-Content-Type-Options, Referrer-Policy, Content-Security-Policy для web-приложения;
  • секретный ключ сертификата не коммитится в репозиторий;
  • использовать сертификаты доверенного CA; автоматизировать выпуск и продление (Let's Encrypt + reload nginx);
  • закрыть прямой доступ к внутренним портам контейнеров извне.

Nginx routing для Bitrix24 Local App

nginx должен поддерживать отдельные server/location rules для bitrix-local-app.

Рекомендуемая схема:

  • веб-домен (MVP: tohin.ru или app.example.ru): /api/* (REST + WS realtime), /auth/*, web frontend; :80 → redirect HTTPS; :443 — TLS + маршрутизация;
  • выделенный API-домен (post-MVP, опционально): отдельный server { listen 443 ssl; ... } без listen 80; только /api/*;
  • для location WebSocket (/api/v1/realtime): proxy_http_version 1.1, Upgrade/Connection headers, увеличенный proxy_read_timeout;
  • домен или path /bitrix/*bitrix-local-app; /bitrix/sync/*bitrix-sync;
  • GET/POST /bitrix/handler и GET/POST /bitrix/install доступны публично для Bitrix24;
  • /bitrix/placement доступен публично как заглушка UI настроек коннектора;
  • /health/live и /health/ready для bitrix-local-app доступны только там, где это нужно для healthcheck и проверки Bitrix form URL;
  • /internal/openlines/v1/* не публикуется наружу или защищается allowlist/private network плюс Authorization: Bearer {BITRIX_INTERNAL_API_TOKEN};
  • для /bitrix/* callbacks кэширование отключено;
  • для /bitrix/* callbacks включены отдельные rate limits, но они не должны блокировать легитимные webhook-повторы Bitrix24.

Nginx routing для bitrix-sync (CRM webhook)

nginx маршрутизирует публичные webhook CRM sync в bitrix-sync:

  • POST /bitrix/sync/webhook/contact — исходящий webhook от роботов Bitrix24 при изменении Contact;
  • проверка BITRIX_SYNC_WEBHOOK_TOKEN выполняется в bitrix-sync;
  • кэширование отключено; rate limits не должны блокировать легитимные повторы Bitrix24;
  • /internal/sync/v1/* не публикуется наружу (только internal network + BITRIX_SYNC_SERVICE_TOKEN).

Rate limits и защита от abuse

Rate limits должны быть распределены по двум слоям.

nginx:

  • ограничивает частоту запросов до попадания в API;
  • держит отдельные зоны лимитов для /auth, /api, public endpoints, fallback polling и download endpoints;
  • ограничивает client_max_body_size;
  • ограничивает загрузку файлов лимитом 5 МБ; client_max_body_size должен быть чуть выше бизнес-лимита для учета overhead запроса;
  • применяет limit_req для endpoint авторизации и fallback polling;
  • для публичных endpoint использует лимит не выше 60 запросов в минуту с одного IP, если настройки не говорят иначе;
  • возвращает 429 при превышении лимитов;
  • не должен использоваться для сложных пользовательских правил, завязанных на user_id.

API:

  • применяет лимиты после проверки JWT;
  • считает лимиты по user_id, IP, route, dialog id и service client;
  • хранит быстрые счетчики в Redis;
  • пишет значимые превышения в audit/App DB;
  • возвращает Retry-After, если клиент может повторить запрос позже.

Проверка сообщений на prompt injection и вредоносные действия не должна выполняться в nginx: это задача отдельного сервиса message-safety, вызываемого из api-backend (см. arch-02-api-contracts.md).

WAF

WAF можно подключить внешним слоем перед nginx без изменения бизнес-кода, если соблюдены требования:

  • nginx и API корректно работают с цепочкой proxy headers и доверяют real IP только от доверенных прокси;
  • CORS разрешает только доверенные домены;
  • публичные endpoint имеют rate limits и кэширование даже без WAF;
  • схема TLS termination согласована с тем, где завершается TLS: WAF/CDN, load balancer или nginx;
  • WAF не должен подменять тело запросов и ответы API без явной необходимости.

WAF не заменяет обязательные лимиты, валидацию схем, авторизацию и аудит внутри приложения.

Публичные endpoint

GET /api/v1/public/app-config и GET /api/v1/public/content являются публичными, поэтому для них обязательны:

  • limit_req на уровне nginx, базово 60 запросов в минуту с одного IP;
  • агрессивное кэширование на уровне nginx или CDN;
  • заголовок Cache-Control: public, max-age=3600;
  • строгая DTO-схема ответа на backend, без сериализации всех строк таблицы настроек;
  • CORS только для доверенных доменов приложения;
  • отсутствие секретов, внутренних URL, service tokens и приватных feature flags в ответе.

Подробнее — arch-04-settings-and-content.md, разделы «Публичный config endpoint» и «Публичный content endpoint».

Healthchecks

Минимальные проверки:

  • nginx: на веб-домене — 301 с :80 на HTTPS; на API-домене (если выделен) — :80 не слушает; :443 — HTTP 200/301 и успешная TLS handshake;
  • api-backend: HTTP 200 от /health/ready;
  • message-safety: HTTP 200 от /health/ready (проверяет PostgreSQL, Redis, workers, read S3-quarantine);
  • bitrix-sync: HTTP 200 от /health/live и /health/ready (ready — PostgreSQL + доступ к sync_queue);
  • bitrix-local-app: HTTP 200 от /health/live, readiness показывает наличие OAuth-токенов после установки приложения;
  • keycloak: health endpoint Keycloak; readiness — подключение к managed PostgreSQL;
  • redis: redis-cli ping;

Порядок запуска

  1. redis (managed PostgreSQL должна быть доступна до старта зависимых сервисов).
  2. keycloak.
  3. otel-collector.
  4. message-safety.
  5. api-backend.
  6. bitrix-local-app.
  7. bitrix-sync.
  8. nginx.

depends_on не заменяет проверку готовности. Сервисы должны уметь ждать зависимости или корректно завершаться с понятной ошибкой. api-backend должен ждать готовности message-safety (healthcheck), т.к. отправка сообщения синхронно зависит от POST /internal/safety/v1/messages/check.

Развёртывание на одной VM

Production-контур на tohin.ru:

  1. VM и managed PostgreSQL в одном VPC/кластере провайдера.
  2. Managed PostgreSQL без публичного IP; security group разрешает подключение только с VM.
  3. docker compose up -d на VM поднимает все сервисы кроме БД.
  4. Сервисы подключаются к managed PostgreSQL по приватному FQDN/IP.

Production-замечания

Frontend (Expo web)

Режим Поведение nginx
production-like / production Статика Expo web (expo export / EAS web build), FRONTEND_DEV_PROXY_ENABLED=false
local dev Опционально proxy на Expo dev server, FRONTEND_DEV_PROXY_ENABLED=true

Переменные — arch-04-settings-and-content.md, блок «Frontend (nginx)».

Docker Compose на одной VM — production-контур первого этапа. Позже при росте нагрузки можно отдельно решить:

  • вынос Redis в managed cache;
  • managed object storage;
  • secret manager;
  • TLS, reverse proxy или managed ingress;
  • backup и restore;
  • централизованный мониторинг;
  • горизонтальное масштабирование API и worker.