Реализованы сервисы ВМ2 - проверка сообщений и синхронизация с Б24 (деплой еще без перевода в боевой режим)
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
> Термины — в [`arch-00-glossary.md`](arch-00-glossary.md).
|
||||
> Приоритет документов — в [`README.md`](README.md).
|
||||
> Безопасность размещения на VM, OS-роли, SSH, секреты и production-деплой — в [`arch-06-service-hosting-security.md`](arch-06-service-hosting-security.md).
|
||||
|
||||
## Назначение
|
||||
|
||||
@@ -47,8 +48,8 @@ HAN Chat - приложение для мигрантов, где стартов
|
||||
- SMS Service: internal durable order API, шаблоны и бессрочный журнал SMS; отдельный worker вызывает i-Digital Direct, callback обновляет только журнал.
|
||||
- api-backend: Python-приложение с REST API, realtime-доставкой сообщений и бизнес-логикой.
|
||||
- Notification producers: сервисы приватной сети, создающие/отменяющие персональные уведомления через Internal API с отдельным Bearer token на `source`; `producer_test` используется только для smoke API.
|
||||
- Nginx Reverse Proxy: единая публичная точка входа, HTTPS termination и маршрутизация на Keycloak/API/frontend web/Bitrix24.
|
||||
- Message Safety Service: отдельный сервис проверки входящих сообщений; вызов из API → `200 allow` | `403 deny` | `203 pending` + `task_id` (при `203` api-backend синхронно поллит task до финального вердикта, без очереди анализа на api-backend).
|
||||
- Nginx Reverse Proxy: независимые точки входа ВМ1 и ВМ2; ВМ1 обслуживает приложение/Open Lines, ВМ2 — CRM webhook `bitrix-sync` и private Message Safety API.
|
||||
- Message Safety Service: отдельный сервис ВМ2 проверки исходящих сообщений; target v2 → `200 allow` | `403 deny` | `202 pending` + `Location`.
|
||||
- Bitrix24 Local App: локальное приложение, custom connector `han_mobile_app` для Bitrix24 Open Lines: чат, OAuth, webhook-события, маппинг `dialog_id` ↔ `bitrix_chat_id`.
|
||||
- Bitrix24 sync service: двусторонняя синхронизация App DB ↔ Битрикс24 CRM (Contact на MVP; маппинг ID, очередь через триггеры, webhook от роботов Bitrix24).
|
||||
- Managed PostgreSQL (приватная сеть, одна база): схемы `han_app`, `bitrix_sync`, `bitrix_local`, `keycloak`, `message_safety`, `sms` — отдельный DB-user на схему.
|
||||
@@ -59,26 +60,50 @@ HAN Chat - приложение для мигрантов, где стартов
|
||||
|
||||
## Инфраструктура развёртывания (зафиксировано)
|
||||
|
||||
На первом этапе весь backend-контур работает на **одной VM** в облаке провайдера:
|
||||
Production-like backend разделён на два контура в одной private network/VPC:
|
||||
|
||||
- `nginx`, `api-backend`, `message-safety`, `keycloak`, `sms-service`/worker, `bitrix-sync`, `bitrix-local-app`, `redis`, `otel-collector` — в Docker Compose на VM;
|
||||
- публичный доступ из интернета только через `nginx` (порты 80/443);
|
||||
- внутренние сервисы общаются по Docker-сети на localhost VM.
|
||||
- **ВМ1 HAN Chat**: edge `nginx`, `api-backend`, `keycloak`, `sms-service`/worker, `bitrix-local-app`, Redis DB0/DB1 и локальный `otel-collector`;
|
||||
- **ВМ2 Processing**: собственный public/private `nginx`, `message-safety` API/worker, `clamd`/`freshclam`, `bitrix-sync`, отдельный Redis Safety и локальный `otel-collector`;
|
||||
- каждая VM имеет один root Compose project и отдельный root-owned systemd deployment unit;
|
||||
- ВМ1 и ВМ2 имеют независимые public DNS/TLS ingress на своих nginx; ВМ2 публикует только exact CRM webhook;
|
||||
- ВМ1 вызывает ВМ2 по private HTTPS с проверкой internal CA, service token, cloud SG и host firewall;
|
||||
- Битрикс24 вызывает public nginx ВМ2 напрямую; CRM webhook не проходит через ВМ1 и не создаёт на ней трафик/зависимость.
|
||||
|
||||
ВМ2 является независимым контуром вспомогательных сервисов. При её недоступности отправка пользовательских сообщений и CRM sync приостанавливаются, но чтение истории, auth, realtime и приём сообщений оператора на ВМ1 продолжаются. Недоступность ВМ1 не мешает ВМ2 принимать CRM webhook и выполнять накопленные workflows. Fail-open для Message Safety запрещён.
|
||||
|
||||
Базы данных — **managed PostgreSQL** того же провайдера в **том же облачном кластере/VPC**, **без публичного доступа** из интернета. VM подключается к БД только по приватной сети.
|
||||
|
||||
Размещение нескольких сервисов на одной VM не делает их одним доверенным контуром. Для каждого контейнера сохраняются least privilege, отдельные секреты, минимальные Docker networks и запрет доступа к Docker socket/host root. Обязательный baseline VM и контейнеров — [`arch-06-service-hosting-security.md`](arch-06-service-hosting-security.md).
|
||||
|
||||
Схема данных в managed PostgreSQL (перечень таблиц внутри схем — в модульных спецификациях, не в arch-*):
|
||||
|
||||
| База / схема | Сервисы | Назначение схемы |
|
||||
|---|---|---|
|
||||
| одна база / `han_app` | `api-backend`, `bitrix-sync` (ограниченный GRANT) | прикладные данные приложения, очередь sync, audit |
|
||||
| одна база / `bitrix_sync` | `bitrix-sync` | worker state, retry/dead letter, sync audit |
|
||||
| одна база / `message_safety` | `message-safety` | verdict cache, safety_task, rule config |
|
||||
| одна база / `message_safety` | `message-safety` | verdict caches, safety tasks/audit, immutable versioned runtime config |
|
||||
| одна база / `bitrix_local` | `bitrix-local-app` | OAuth, inbox, `dialog_sessions` |
|
||||
| одна база / `keycloak` | Keycloak | учётные записи, realm, сессии IdP |
|
||||
| одна база / `sms` | `sms-service`, `sms-worker` | шаблоны, runtime settings, бессрочный журнал отправки/доставки SMS |
|
||||
|
||||
Redis на первом этапе остаётся на VM в Docker (ephemeral/coordination). Selectel S3 — внешнее object storage: три бакета (`han-chat-quarantine`, `han-chat-attachments`, `han-chat-documents`); см. [`arch-00-glossary.md`](arch-00-glossary.md).
|
||||
Redis разделён по deployment boundary: DB0/DB1 остаются на ВМ1, отдельный Redis Safety находится на ВМ2. Оба являются ephemeral/coordination слоями; PostgreSQL остаётся durable source of truth. Selectel S3 — внешнее object storage: три бакета (`han-chat-quarantine`, `han-chat-attachments`, `han-chat-documents`); см. [`arch-00-glossary.md`](arch-00-glossary.md).
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
client[Client] --> edge[VM1_EdgeNginx]
|
||||
edge --> api[VM1_ApiBackend]
|
||||
bitrix[Bitrix24] -->|"CRM webhook HTTPS"| publicGateway[VM2_PublicNginx]
|
||||
publicGateway --> sync[BitrixSync]
|
||||
api -->|"HTTPS 8443 + service token"| privateGateway[VM2_PrivateListener]
|
||||
privateGateway --> safety[MessageSafetyApi]
|
||||
safety --> worker[SafetyWorker]
|
||||
worker --> clamd[Clamd]
|
||||
worker --> s3q[S3Quarantine]
|
||||
worker --> pg[ManagedPostgreSQL]
|
||||
sync --> pg
|
||||
sync --> bitrix
|
||||
collector[VM2_OtelCollector] --> signoz[PrivateSigNoz]
|
||||
```
|
||||
|
||||
## Контекстная схема
|
||||
|
||||
@@ -179,10 +204,10 @@ Frontend не должен:
|
||||
- хранение истории диалогов;
|
||||
- запись данных профиля в App DB (синхронизация с Bitrix24 — триггеры → `sync_queue` → `bitrix-sync`, без участия api-backend);
|
||||
- выдачу **presigned URL** на загрузку в S3-quarantine, проверку объекта при `complete`, promote/delete после вердикта;
|
||||
- синхронный вызов Message Safety Service (`POST /internal/safety/v1/messages/check`) и интерпретацию ответа: `200 allow`, `403 deny`, `203 pending` + `task_id`;
|
||||
- вызов Message Safety v2 (`POST /internal/safety/v2/messages/check`) и интерпретацию `200 allow`, `403 deny`, `202 pending`;
|
||||
- при `200`: перенос файлов quarantine → S3-data, сохранение сообщения, отправка в Bitrix24;
|
||||
- при `403`: удаление файлов из quarantine, безопасный ответ клиенту;
|
||||
- при `203`: api-backend **синхронно поллит** `GET /internal/safety/v1/messages/tasks/{task_id}` до финального `200`/`403` (timeout budget — arch-04), затем promote/Bitrix или cleanup, и только после этого отвечает клиенту финальным результатом;
|
||||
- при `202`: api-backend **синхронно поллит** `Location` до финального `200`/`403`, terminal failed или timeout, затем promote/Bitrix или cleanup;
|
||||
- это **ожидание в рамках одного клиентского HTTP-соединения**, а не общая очередь: другие запросы обрабатываются параллельно (workers/async);
|
||||
- решение «быстрая проверка / долгая» принимает только `message-safety`; на api-backend **нет** очереди анализа сообщений;
|
||||
- запись checkpoint в `safety_tasks` (App DB) на время poll — для recovery при timeout/crash (I1);
|
||||
@@ -218,13 +243,15 @@ Frontend не должен:
|
||||
|
||||
### Bitrix24 sync service
|
||||
|
||||
Отвечает за **двустороннюю** синхронизацию данных между App DB и Битрикс24 CRM:
|
||||
Отвечает за асинхронную двустороннюю синхронизацию данных между App DB и Битрикс24 CRM по контракту [`../modules/module-07-bitrix-sync.md`](../modules/module-07-bitrix-sync.md):
|
||||
|
||||
- **маппинг ID** сущностей приложения ↔ Bitrix24 (`bitrix_contact_id`, `entity_external_mapping`);
|
||||
- **App DB → Bitrix24:** обработка очереди `sync_queue` (триггеры App DB) — map/create Contact по телефону, push обновлений полей;
|
||||
- **Bitrix24 → App DB:** приём webhook от роботов Bitrix24, обновление профиля с GUC `han.sync_suppress`;
|
||||
- реестр синхронизируемых сущностей (MVP: Contact; post-MVP: Lead, Deal, Document);
|
||||
- повторные попытки, rate limiting Bitrix REST, dead letter;
|
||||
- **канонический mapping** и его историю в `bitrix_sync.entity_external_mapping`; App DB не хранит CRM Contact ID;
|
||||
- **App DB → Bitrix24:** durable workflow для `contact.map_or_create`, `contact.update`, `contact.deactivate`;
|
||||
- **исправление связи:** audited административный запрос запускает `contact.rebind`; прямой `UPDATE` mapping запрещён;
|
||||
- **Bitrix24 → App DB:** durable webhook inbox, coalescing и reconciliation; запись профиля с transaction-local GUC `han.sync_suppress`;
|
||||
- mastership по полям: телефон — App/Keycloak, `NAME`/citizenship/email — Битрикс24;
|
||||
- batch, общий portal rate limiter, leases/fencing, retry до 24 часов и technical DLQ;
|
||||
- business conflicts через смарт-процесс Битрикс24, technical failures через SigNoz;
|
||||
- прямой доступ к схеме `han_app` и собственной `bitrix_sync`.
|
||||
|
||||
Не отвечает за:
|
||||
@@ -290,12 +317,12 @@ Confidential **backend client** Keycloak (client credentials) в MVP **не об
|
||||
- HTTP-контракт для api-backend:
|
||||
- `200` — синхронная проверка завершена, **allow**;
|
||||
- `403` — синхронная проверка завершена, **deny**;
|
||||
- `203` + `task_id` — нужна async-проверка (обычно файлы), сообщение в обработке;
|
||||
- финальный вердикт async-задачи по `GET /internal/safety/v1/messages/tasks/{task_id}`: `200 allow` | `403 deny` | `203 pending`;
|
||||
- `202` + `task_id`/`Location` — нужна async-проверка;
|
||||
- task GET: `200 allow` | `403 deny` | `202 pending` | terminal failed `503`;
|
||||
- SHA-256 хеширование и lookup кэша вердиктов;
|
||||
- отдельный pipeline проверки ссылок;
|
||||
- запись verdict cache, `safety_task` и audit в схеме `message_safety`;
|
||||
- internal API: `POST /internal/safety/v1/messages/check`, `GET /internal/safety/v1/messages/tasks/{task_id}`.
|
||||
- запись verdict caches, `safety_task`, audit и immutable `config_versions` в схеме `message_safety`; runtime role не активирует config;
|
||||
- target internal API: `POST /internal/safety/v2/messages/check`, `GET /internal/safety/v2/messages/tasks/{task_id}`.
|
||||
|
||||
Не отвечает за:
|
||||
|
||||
@@ -423,7 +450,7 @@ api-backend не решает, sync или async нужна проверка в
|
||||
|
||||
1. Frontend вызывает `POST /api/v1/dialogs` (если `dialog_id` ещё нет), затем отправляет `POST /api/v1/dialogs/{dialog_id}/messages` с непустым `text` (без вложения).
|
||||
2. Nginx и API применяют rate limits.
|
||||
3. API **синхронно** вызывает Message Safety Service (`POST /internal/safety/v1/messages/check`) — шаги текст и ссылки.
|
||||
3. API вызывает Message Safety v2 (`POST /internal/safety/v2/messages/check`) — шаги text/local links.
|
||||
4. Далее — общая ветка вердикта (п. 5–8 ниже).
|
||||
|
||||
**Файловое сообщение:**
|
||||
@@ -437,7 +464,7 @@ api-backend не решает, sync или async нужна проверка в
|
||||
|
||||
5. **`403 deny`**: API удаляет quarantine (если был файл), выставляет `safety_status=blocked`, `delivery_status=rejected`, возвращает клиенту безопасную ошибку; в Bitrix24 ничего не уходит.
|
||||
6. **`200 allow`**: API переносит файл в S3-data attachments (если был), сохраняет сообщение (`safety_status=allowed`, `delivery_status=accepted`) и фиксирует задачу доставки в Open Lines. После успешной отправки через `bitrix-local-app` статус становится `delivery_status=delivered`, API подтверждает клиенту финальный результат; `Dialog.status` → `waiting_for_company`. Если Bitrix24/S3/dependency недоступны после allow, статус становится `delivery_status=failed`, клиент получает безопасную ошибку зависимости.
|
||||
7. **`203 pending` + `task_id`**: api-backend пишет checkpoint в `safety_tasks` и **регулярно синхронно** вызывает `GET /internal/safety/v1/messages/tasks/{task_id}` (backoff), пока не получит финальный вердикт или не истечёт `MESSAGE_SAFETY_TASK_POLL_MAX_SEC`. Пока идёт poll, **этот** клиентский `POST .../messages` ещё не завершён (соединение ждёт). Параллельные запросы других клиентов **не** блокируются — общей очереди анализа на api-backend нет.
|
||||
7. **`202 pending`**: api-backend пишет checkpoint с `Location` и синхронно поллит его с `Retry-After`, пока не получит финальный вердикт/terminal failure или не истечёт budget. Public POST остаётся открытым; другие запросы не блокируются.
|
||||
- финальный **`200 allow`** → как п. 6, затем ответ клиенту;
|
||||
- финальный **`403 deny`** → как п. 5, затем ответ клиенту;
|
||||
- timeout / недоступность safety → `delivery_status=failed`, безопасная ошибка клиенту (`503` / `504`), quarantine не promote; recovery по `safety_tasks` — зона модуля.
|
||||
@@ -448,7 +475,7 @@ api-backend не решает, sync или async нужна проверка в
|
||||
|
||||
- Для доставки в Bitrix24 используется transactional outbox/checkpoint в App DB: запись `Message` и запись намерения доставки фиксируются атомарно, а повторная отправка в `bitrix-local-app` идемпотентна по `message_id` / `Idempotency-Key`.
|
||||
- `delivery_status=accepted` означает, что API принял сообщение и завершил safety allow, но ещё не получил подтверждение доставки в Open Lines. `delivery_status=delivered` выставляется только после успешного ответа `bitrix-local-app` о приёме сообщения для Bitrix24 Open Lines.
|
||||
- Recovery по `han_app.safety_tasks` восстанавливает только сценарии, где Message Safety вернул `203 pending` и клиентский запрос оборвался из-за timeout/crash. Recovery job повторно опрашивает `message-safety` по `task_id`, затем идемпотентно выполняет promote/delete quarantine и обновляет `Message`/`MessageAttachment`.
|
||||
- Recovery по `han_app.safety_tasks` восстанавливает сценарии `202 pending` после timeout/crash, опрашивает сохранённый `Location`, затем идемпотентно выполняет conditional promote/delete и обновляет App DB.
|
||||
- Объекты в S3-quarantine не удаляются при timeout safety до финального verdict; orphan-cleanup удаляет только просроченные объекты без активного `safety_tasks` или attachment metadata.
|
||||
|
||||
## Поток работы с чатом: Битрикс24 -> клиент
|
||||
@@ -495,11 +522,11 @@ Notification Center v1 регистрирует переданные продю
|
||||
|
||||
App DB — **локальный кэш** для UI. Двусторонний sync — `bitrix-sync` (имена полей — [`arch-00-glossary.md`](arch-00-glossary.md)):
|
||||
|
||||
- **Auth-телефон:** master — Keycloak (`UserIdentity.phone_number`); изменения могут инициировать `contact.update` через триггеры.
|
||||
- **Поля профиля для UI:** master — последнее успешно синхронизированное значение; основной входящий поток на MVP — правки сотрудником в Bitrix24 (webhook → App DB).
|
||||
- **App → Bitrix:** триггеры `han_app` → `sync_queue` (`contact.update`).
|
||||
- **Bitrix → App:** webhook робота → `bitrix-sync`; запись с GUC `han.sync_suppress` (без эхо в очередь).
|
||||
- **Конфликт:** побеждает более позднее событие (`updated_at`, audit в `bitrix_sync`).
|
||||
- **Auth-телефон:** master — Keycloak (`UserIdentity.phone_number`); только его фактическое изменение инициирует `contact.update`.
|
||||
- **ФИО, гражданство, email:** master — Битрикс24; App хранит последний успешно полученный snapshot для UI и не отправляет эти поля обратно.
|
||||
- **App → Bitrix:** триггеры `han_app` → `sync_queue` (`contact.map_or_create`, `contact.update`, `contact.deactivate`).
|
||||
- **Bitrix → App:** durable webhook inbox + reconciliation; запись с `SET LOCAL han.sync_suppress='true'` без эхо.
|
||||
- **Конфликт:** универсального правила «последнее событие побеждает» нет; применяется field mastership. Несовпадение identity/mapping создаёт business alert и не перезаписывает профиль.
|
||||
|
||||
## Аудит скачиваний
|
||||
|
||||
@@ -530,6 +557,7 @@ App DB — **локальный кэш** для UI. Двусторонний syn
|
||||
## Принципы безопасности
|
||||
|
||||
- Все защищенные пользовательские API требуют валидный JWT.
|
||||
- Компрометация одного сервиса не должна автоматически давать host root, Docker daemon, секреты или сетевой доступ соседних сервисов; требования к VM и production-деплою — в [`arch-06-service-hosting-security.md`](arch-06-service-hosting-security.md).
|
||||
- Без JWT доступны **только** read-only публичные endpoint: `GET /api/v1/public/*` (rate limit + CORS + кэш). Write-endpoint (`consents`, `session-start`, чат, профиль и т.д.) требуют JWT.
|
||||
- Все внешние пользовательские соединения работают через HTTPS.
|
||||
- HTTP допускается только для веб-домена как вход для редиректа на HTTPS. Для api домена HTTP не допускается.
|
||||
@@ -546,7 +574,7 @@ App DB — **локальный кэш** для UI. Двусторонний syn
|
||||
- Все публичные id создаются в формате UUID.
|
||||
- Сервисные API защищаются внутренней сетью Docker/VPC плюс service token (канонический контракт — [`arch-02-api-contracts.md`](arch-02-api-contracts.md), «Service tokens (internal API)»; значения переменных — [`arch-04-settings-and-content.md`](arch-04-settings-and-content.md)).
|
||||
- Rate limits применяются минимум на двух уровнях: edge-лимиты в `nginx` и пользовательские лимиты в API с состоянием в Redis.
|
||||
- Входящие сообщения пользователя: синхронный `POST /internal/safety/v1/messages/check` → при `203` api-backend синхронно поллит `task_id` до финального `200`/`403` (или timeout); без очереди анализа на api-backend.
|
||||
- Исходящие сообщения пользователя: internal `POST /internal/safety/v2/messages/check` → при `202` api-backend синхронно поллит `Location` до финального `200`/`403`, terminal failed `503` или timeout; public API не становится async.
|
||||
- Файлы пользователя до финального `allow` только в S3-quarantine; в S3-data — после `200 allow`.
|
||||
- У клиента **нет** постоянных S3 credentials. Загрузка — **presigned PUT** в S3-quarantine, выданный `api-backend`; скачивание — **presigned GET**. Байты файла **не** проксируются через `api-backend`.
|
||||
- `message-safety` — read-only к S3-quarantine, без прав записи в бакеты.
|
||||
@@ -559,13 +587,18 @@ App DB — **локальный кэш** для UI. Двусторонний syn
|
||||
|
||||
### Состав backend-контура
|
||||
|
||||
Минимальный целевой real-SMS контур на одной VM: `nginx`, `api-backend`, `message-safety`, `keycloak`, `sms-service`/worker, `bitrix-sync`, `bitrix-local-app`, `redis`, `otel-collector`. До SMS rollout сервисы SMS могут отсутствовать, но Keycloak обязан оставаться в mock mode.
|
||||
Минимальный целевой real-SMS контур разделён на два stack:
|
||||
|
||||
- ВМ1: `nginx`, `api-backend`, `keycloak`, `sms-service`/worker, `bitrix-local-app`, Redis DB0/DB1, `otel-collector`;
|
||||
- ВМ2: nginx с public webhook/private internal server blocks, `message-safety` API/worker, `clamd`/`freshclam`, `bitrix-sync`, Redis Safety, `otel-collector`.
|
||||
|
||||
До SMS rollout сервисы SMS могут отсутствовать, но Keycloak обязан оставаться в mock mode.
|
||||
|
||||
### Предлагаемая структура backend-репозитория
|
||||
|
||||
```text
|
||||
backend/
|
||||
docker-compose.yml # корневой compose: nginx + include сервисов + networks/volumes
|
||||
docker-compose.yml # root compose ВМ1
|
||||
.env.example
|
||||
nginx/
|
||||
docker-compose.yml
|
||||
@@ -579,12 +612,6 @@ backend/
|
||||
tests/
|
||||
pyproject.toml
|
||||
Dockerfile
|
||||
message-safety/
|
||||
app/
|
||||
docker-compose.yml
|
||||
tests/
|
||||
pyproject.toml
|
||||
Dockerfile
|
||||
bitrix-local-app/
|
||||
app/
|
||||
docker-compose.yml
|
||||
@@ -592,12 +619,6 @@ backend/
|
||||
tests/
|
||||
pyproject.toml
|
||||
Dockerfile
|
||||
bitrix-sync/
|
||||
app/
|
||||
docker-compose.yml
|
||||
tests/
|
||||
pyproject.toml
|
||||
Dockerfile
|
||||
keycloak/
|
||||
docker-compose.yml
|
||||
realm/
|
||||
@@ -611,14 +632,23 @@ backend/
|
||||
redis/
|
||||
docker-compose.yml
|
||||
observability/
|
||||
docker-compose.yml # сервис otel-collector
|
||||
docker-compose.yml # collector ВМ1
|
||||
otel-collector.yaml
|
||||
|
||||
processing/
|
||||
docker-compose.yml # root compose ВМ2
|
||||
nginx-internal/
|
||||
message-safety/
|
||||
bitrix-sync/
|
||||
clamav/
|
||||
redis/
|
||||
observability/ # collector ВМ2
|
||||
```
|
||||
|
||||
Детальная внутренняя структура каждого сервиса (`app/`, модули, миграции) определяется в профильных спецификациях модулей (TBD).
|
||||
|
||||
### Compose-контур
|
||||
### Compose-контуры
|
||||
|
||||
Корневой `backend/docker-compose.yml` подключает сервисные compose-файлы через `include`.
|
||||
`backend/docker-compose.yml` является единственным root Compose ВМ1; `processing/docker-compose.yml` — единственным root Compose ВМ2. Оба используют `include` и отдельные root-owned systemd units. Cross-host Docker network не используется.
|
||||
|
||||
Публикация портов наружу разрешена только `nginx` (`80/443`). Остальные сервисы доступны через Docker-сети и private VPC.
|
||||
На каждой VM host ports публикует только её nginx. ВМ1 публикует `80/443` своего application host. ВМ2 публикует `80/443` отдельного webhook host и private `8443`; public server block ВМ2 допускает только exact CRM webhook, private listener доступен только SG ВМ1/ops.
|
||||
|
||||
Reference in New Issue
Block a user