Files
Deal/deploy/compose.dev.yml
T
Rustam Khalimov 9e07568ddd Инициализировать репозиторий «Дейл»
Первый коммит: модульный монолит ядра (.NET 10) и gRPC-сервисы
ai/ml/telegram, фронтенд Vue 3/Vite/Tailwind, документация (ТЗ,
инструкция пользователя, техдокументация, код-стайл), бэклог,
скрипты развёртывания и архив прототипа LeadRadar.
2026-09-11 02:50:17 +03:00

214 lines
12 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# compose.dev.yml — dev-стек Дейла (этап 6, Task 20; Ruling 12).
#
# Полный стек: postgres + minio (хранилища), три автономных сервиса этапа 6
# (telegram-service :5101, ai-service :5102, ml-service :5103) и core (deal-api:
# HTTP :5080 + gRPC-ингресс :5082).
#
# Режимы интеграций core — флагами SERVICES__{ML,AI,TELEGRAM}__USELOCAL (Ruling 6):
# * этот файл — сквозной gRPC-режим ВСЕГО стека «по-настоящему»: UseLocal=false заданы env
# core-сервиса ниже, интеграции ходят в ml/ai/telegram-сервисы этой же compose-сети
# (MlOutboxFlushScheduler → TrainBatch, GrpcAiClassifier/GrpcAiTools, GrpcTelegramClient).
# Подъём всего стека одной командой: docker compose -f deploy/compose.dev.yml up -d --build
# (см. также scripts/dev-smoke.sh — сквозная проверка с авто-очисткой).
# * Local-заглушки (дефолт КОДА — appsettings.json, UseLocal:true) сохраняются для запуска core
# с хоста БЕЗ сервисов (обычная dev-разработка, curl-приёмки этапов 2–5): поднимаются только
# postgres/minio, core — dotnet run из src/core/Deal.Api. Код-дефолт не меняется — режим
# переключает этот compose-файл (env ниже).
#
# Секреты dev (переопределяются .env/экспортом, шаблон ${VAR:-default}):
# DEAL_SERVICE_TOKEN — единый service-token всех процессов (metadata gRPC, Ruling 1/2/13)
# DEAL_ENCRYPTION_KEY — ключ AES-256-GCM шифрования секретов настроек core (32 байта base64)
# DEAL_TELEGRAM_SESSION_KEY — ключ AES-256-GCM файлов сессий telegram-service (32 байта base64)
# минио/БД creds — dev-значения ниже (в проде — этап 7, compose-prod + mTLS).
#
# Core в этом файле — «весь стек в docker» (эндпоинты — имена compose-сети). Альтернатива — core
# с хоста (Ruling 12): поднимаются только postgres/minio и (по желанию) сервисы, core запускается
# dotnet run, и сервисы ходят в ингресс хоста через DEAL_CORE_INGRESS=http://host.docker.internal:5082
# (см. env telegram-service ниже).
services:
postgres:
image: postgres:16-alpine
container_name: deal-postgres
environment:
POSTGRES_DB: deal
POSTGRES_USER: deal
POSTGRES_PASSWORD: deal_dev_password
ports:
- "5433:5432" # 5432 может быть занят LeadRadar-стеком
volumes:
- deal_pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U deal -d deal"]
interval: 5s
timeout: 3s
retries: 10
# MinIO для файлов проектных карточек (Ruling 4, план Task 6; образца-прототипа object_store.py).
# Опционально: API работает и без него — LocalFileStorage (data/attachments) выбирается, пока MinIO не
# сконфигурирован (Storage__Minio__* / DEAL_MINIO_*). Бакет deal-files создаётся приложением лениво при
# первом upload (Ruling 4: EnsureBucket на первом put), отдельный init-контейнер не нужен.
# Консоль: http://localhost:9001 (root deal_minio / deal_minio_secret).
# Если 9000/9001 заняты LeadRadar-minio — поменяйте на 9100/9101 (и endpoint в конфигурации API).
minio:
image: minio/minio
container_name: deal-minio
environment:
MINIO_ROOT_USER: deal_minio
MINIO_ROOT_PASSWORD: deal_minio_secret
ports:
- "9000:9000" # S3 API
- "9001:9001" # Web-консоль
volumes:
- deal_minio_data:/data
command: server /data --console-address ":9001"
# core (deal-api) — HTTP :5080 + gRPC-ингресс telegram-service :5082 (план Task 12/20, Ruling 7/12).
# Здесь core поднимается в сквозном gRPC-режиме (UseLocal=false ниже): сервисы этой же сети
# вызываются по-настоящему; MlOutbox копится в БД и выгружается MlOutboxFlushScheduler (10 с).
# Local-режим (дефолт appsettings.json) остаётся для запуска core с хоста без сервисов.
core:
build:
context: ..
dockerfile: src/core/Deal.Api/Dockerfile
container_name: deal-core
environment:
ASPNETCORE_ENVIRONMENT: Development
ASPNETCORE_URLS: http://0.0.0.0:5080
GRPC_INGRESS_PORT: "5082"
ConnectionStrings__DealPostgres: Host=postgres;Port=5432;Database=deal;Username=deal;Password=deal_dev_password
DEAL_SERVICE_TOKEN: ${DEAL_SERVICE_TOKEN:-deal_dev_service_token}
DEAL_ENCRYPTION_KEY: ${DEAL_ENCRYPTION_KEY:-MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY=}
# gRPC-режим всего стека (Ruling 6): Local-заглушки кода (appsettings default true)
# переключаются на gRPC-клиентов сервисов compose-сети. Хост-запуск core без compose
# остаётся на Local (код-дефолт не менялся).
Services__Ml__UseLocal: "false"
Services__Ai__UseLocal: "false"
Services__Telegram__UseLocal: "false"
Services__Ml__Endpoint: http://ml-service:5103
Services__Ai__Endpoint: http://ai-service:5102
Services__Telegram__Endpoint: http://telegram-service:5101
Storage__Minio__Endpoint: minio:9000
Storage__Minio__AccessKey: deal_minio
Storage__Minio__SecretKey: deal_minio_secret
Storage__Minio__Bucket: deal-files
Storage__Minio__Secure: "false"
ports:
- "5080:5080"
- "5082:5082" # gRPC-ингресс telegram-service (сервисы ходят на http://core:5082 внутри сети)
volumes:
- deal_api_data:/app/data # data/encryption.key + data/attachments (Local-фолбэк файлов)
depends_on:
postgres:
condition: service_healthy
healthcheck:
test: ["CMD", "/bin/grpc_health_probe", "-addr=localhost:5082"]
interval: 10s
timeout: 3s
retries: 10
start_period: 15s
# telegram-service — gRPC-сервер Telegram (этап 6, Ruling 12; план Task 2). Отдельный процесс,
# отдельное sln (src/telegram-service/Deal.Telegram.sln). Команды ядра приходят на localhost:5101
# (SERVICES__Telegram__Endpoint — задачи 9–12), исходящий поток — в core-ингресс :5082
# (SERVICES__CORE__INGRESS, Ruling 7; внутри compose — http://core:5082; при core на хосте задайте
# DEAL_CORE_INGRESS=http://host.docker.internal:5082). Plaintext gRPC без mTLS (Ruling 2 — dev):
# защита — общий service-token (DEAL_SERVICE_TOKEN, env хоста и контейнеров). Сессии тенантов —
# файлы /data/sessions (Ruling 3), шифруются AES-256-GCM ключом DEAL_TELEGRAM_SESSION_KEY
# (fail-closed: без ключа сервис не стартует). Контекст сборки — корень репозитория: csproj
# ссылается на src/contracts/Deal.Proto.csproj (общий проект кодогенерации, Task 1).
telegram-service:
build:
context: ..
dockerfile: src/telegram-service/Deal.Telegram/Dockerfile
container_name: deal-telegram-service
environment:
GRPC_PORT: "5101"
DEAL_SERVICE_TOKEN: ${DEAL_SERVICE_TOKEN:-deal_dev_service_token}
DEAL_TELEGRAM_SESSION_KEY: ${DEAL_TELEGRAM_SESSION_KEY:-ZmVkY2JhOTg3NjU0MzIxMGZlZGNiYTk4NzY1NDMyMTA=}
DEAL_TELEGRAM_SESSION_DIR: /data/sessions
SERVICES__CORE__INGRESS: ${DEAL_CORE_INGRESS:-http://core:5082}
ports:
- "5101:5101"
volumes:
- deal_tg_sessions:/data/sessions
healthcheck:
test: ["CMD", "/bin/grpc_health_probe", "-addr=localhost:5101"]
interval: 5s
timeout: 3s
retries: 10
# ai-service — gRPC-сервер ИИ-фасада (этап 6, Ruling 12; план Task 4). Отдельный процесс,
# отдельное sln (src/ai-service/Deal.Ai.sln). Промпты/классификацию/фильтр/ключи ядро шлёт на
# localhost:5102 (SERVICES__Ai__Endpoint — задачи 7/8/15). Plaintext gRPC без mTLS (Ruling 2 —
# dev): защита — общий service-token (DEAL_SERVICE_TOKEN, env хоста и контейнеров). Сервис без БД
# (Ruling 5): конфиг провайдера (id/base/model/apiKey/api_style) приходит в теле каждого запроса
# от ядра, персистентных файлов нет — volume не нужен. Контекст сборки — корень репозитория:
# csproj ссылается на src/contracts/Deal.Proto.csproj (общий проект кодогенерации, Task 1).
ai-service:
build:
context: ..
dockerfile: src/ai-service/Deal.Ai/Dockerfile
container_name: deal-ai-service
environment:
GRPC_PORT: "5102"
DEAL_SERVICE_TOKEN: ${DEAL_SERVICE_TOKEN:-deal_dev_service_token}
ports:
- "5102:5102"
healthcheck:
test: ["CMD", "/bin/grpc_health_probe", "-addr=localhost:5102"]
interval: 5s
timeout: 3s
retries: 10
# ml-service — gRPC-сервер ML (этап 6, Ruling 12; план Task 3). Отдельный процесс, отдельное sln
# (src/ml-service/Deal.Ml.sln). Обучение и предсказания ядро шлёт на localhost:5103
# (SERVICES__Ml__Endpoint — задачи 5/6/16). Plaintext gRPC без mTLS (Ruling 2 — dev): защита —
# общий service-token (DEAL_SERVICE_TOKEN, env хоста и контейнеров). Модели тенантов — файлы
# SQLite /data/ml/<tenantId>.sqlite (Ruling 4). Контекст сборки — корень репозитория: csproj
# ссылается на src/contracts/Deal.Proto.csproj (общий проект кодогенерации, Task 1).
ml-service:
build:
context: ..
dockerfile: src/ml-service/Deal.Ml/Dockerfile
container_name: deal-ml-service
environment:
GRPC_PORT: "5103"
DEAL_SERVICE_TOKEN: ${DEAL_SERVICE_TOKEN:-deal_dev_service_token}
DEAL_ML_DATA_DIR: /data/ml # файлы моделей data/ml/<tenantId>.sqlite на volume deal_ml_data (Ruling 4/12)
ports:
- "5103:5103"
volumes:
- deal_ml_data:/data/ml
healthcheck:
test: ["CMD", "/bin/grpc_health_probe", "-addr=localhost:5103"]
interval: 5s
timeout: 3s
retries: 10
# Prometheus (профиль observability, этап 12/пакет A) — сбор /metrics всех 4 процессов (:9464)
# внутри dev-сети. Подъём: docker compose -f deploy/compose.dev.yml --profile observability up -d.
# Конфиг — общий deploy/observability/prometheus.yml (те же имена сервисов и таргеты). UI — 9090.
prometheus:
image: prom/prometheus:v3.5.0
container_name: deal-prometheus
profiles: ["observability"]
command:
- --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.path=/prometheus
- --storage.tsdb.retention.time=15d
ports:
- "9090:9090"
volumes:
- ./observability/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./observability/prometheus-rules.yml:/etc/prometheus/prometheus-rules.yml:ro
- deal_prometheus_data:/prometheus
volumes:
deal_pgdata:
deal_minio_data:
deal_tg_sessions:
deal_ml_data:
deal_api_data:
deal_prometheus_data: