arm-ka-docs/dev/docker-compose.yml
Andrey Epifancev f83052420f docs: dev/README — проверка окружения под склейку ответов ИС (aep_3, aep_6, aep_5)
Раздел «Проверка окружения» приведён в соответствие с доработанным scan-gateway (склейка всех *.json каталога ответа
в raw/{job_id}.json, ошибочные файлы набора в metrics.warnings), по результатам сквозной проверки Task 6 (04.10.2026):
- сценарий 2: размер и формат raw/ (`{"job_id", "files": [...]}`), лог эмулятора с каталогом набора, processing ~10 с
  (задержка эмулятора + SCAN_POLL_SECONDS + SCAN_SETTLE_SECONDS), абзац про фикстуры ИС (успешные ответы есть);
- добавлен сценарий 2а: aep_3 / aep_6 -> успешный ответ ИС -> NOT_IMPLEMENTED, metrics.warnings про aep_3_ofr.json;
- абзац про прогон рецепта: проверены оба пути вставки legal_entity (чистая БД и on conflict);
- «не покрывает»: нормализатор шлюза Среза 0 даёт NOT_IMPLEMENTED, у ошибок scan-gateway в metrics только warnings,
  оговорка, что `down -v` удаляет общие тома postgres-data/minio-data всех worktree;
- dev/docker-compose.yml: комментарий про фикстуры ответов ИС — набор <имя>.json + <имя>_*.json (поведение не менялось).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 16:20:31 +04:00

237 lines
10 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.

# Инфраструктура разработки АРМ КА: PostgreSQL 16, NATS 2.10 (без JetStream, как на платформе), MinIO + бакет.
# Запуск: cp .env.example .env && docker compose up -d (из этого каталога)
# Ожидание готовности: docker compose up -d --wait postgres nats minio. Голый `up -d --wait` возвращает код 1, потому что
# одноразовый minio-init завершается (хотя и с кодом 0) — для скриптов указывайте сервисы явно.
# Все учётные данные, порты хоста и имя бакета берутся из .env (значения по умолчанию — dev).
# Порты публикуются только на 127.0.0.1; адрес привязки меняется через BIND_ADDR (см. .env.example).
# Профиль `services` — сервисы системы, собранные из соседних репозиториев workspace (../../<repo>, Dockerfile в корне):
# docker compose --profile services up -d --build
# docker compose --profile services up -d --wait arm-core tabular-parser scan-gateway scan-emulator
# Одноразовые minio-init и arm-core-migrate (миграции + seed) в список --wait не входят: они завершаются с кодом 0.
# Внутри контейнера каждый сервис слушает 8000; на хост публикуются 8000 (arm-core), 8001 (tabular-parser), 8002 (scan-gateway).
# Фиксированное имя проекта: одинаковые тома и сети из любого worktree (.wt/<срез>/docs/dev).
name: arm-ka
# Общие переменные сервисов профиля `services` (формат шаблона команды; адреса — внутри сети compose, не localhost).
x-service-env: &service-env
DEBUG: "true"
OPENBAO__MINIO__MINIO_URL: minio:9000
OPENBAO__MINIO__MINIO_ADMIN_LOGIN: ${MINIO_ROOT_USER:-minioadmin}
OPENBAO__MINIO__MINIO_ADMIN_PASSWORD: ${MINIO_ROOT_PASSWORD:-minioadmin}
OPENBAO__MINIO__MINIO_BUCKET: ${MINIO_BUCKET:-arm-ka}
OPENBAO__MINIO__MINIO_SECURE: "false"
OPENBAO__NATS__NATS_URL: nats://nats:4222
NATS_ENABLED: "true"
# arm-core и его одноразовые миграции: те же переменные плюс БД и dev-эмитент токенов.
x-arm-core-env: &arm-core-env
<<: *service-env
OPENBAO__DATABASE__DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:-armka}:${POSTGRES_PASSWORD:-armka}@postgres:5432/${POSTGRES_DB:-armka}
# Dev-эмитент JWT (POST /api/v1/dev/token) — только при DEBUG=true; секрет публичный, только для dev.
# Порт хоста по умолчанию на 127.0.0.1 (BIND_ADDR): при BIND_ADDR=0.0.0.0 токен может получить любой в сети.
AUTH_DEV_ISSUER: "true"
AUTH_DEV_SECRET: dev-only-secret-do-not-use-in-production-0123456789
services:
postgres:
image: postgres:16.10-alpine
environment:
POSTGRES_DB: ${POSTGRES_DB:-armka}
POSTGRES_USER: ${POSTGRES_USER:-armka}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-armka}
ports:
- "${BIND_ADDR:-127.0.0.1}:${POSTGRES_PORT:-5432}:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 3s
timeout: 3s
retries: 20
start_period: 5s
# Core NATS без JetStream: флаг --jetstream не передаётся. Мониторинг — порт 8222 (/varz, /healthz).
nats:
image: nats:2.10.29-alpine
command: ["-m", "8222"]
ports:
- "${BIND_ADDR:-127.0.0.1}:${NATS_PORT:-4222}:4222"
- "${BIND_ADDR:-127.0.0.1}:${NATS_MONITOR_PORT:-8222}:8222"
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:8222/healthz || exit 1"]
interval: 3s
timeout: 3s
retries: 20
start_period: 2s
# Образы minio/minio и minio/mc сняты с Docker Hub и quay.io; используется сборка alpine/minio с RELEASE-тегом.
minio:
image: alpine/minio:RELEASE.2025-10-15T17-29-55Z
# Образ по умолчанию работает от пользователя minio и не может писать в свежий именованный том — в dev запускаем от root.
user: "0:0"
command: ["server", "/data", "--console-address", ":9001"]
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minioadmin}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-minioadmin}
ports:
- "${BIND_ADDR:-127.0.0.1}:${MINIO_API_PORT:-9000}:9000"
- "${BIND_ADDR:-127.0.0.1}:${MINIO_CONSOLE_PORT:-9001}:9001"
volumes:
- minio-data:/data
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:9000/minio/health/live || exit 1"]
interval: 3s
timeout: 3s
retries: 20
start_period: 3s
# Одноразовое создание бакета; идемпотентно (--ignore-existing), при повторном up снова завершается с кодом 0.
minio-init:
image: bitnamilegacy/minio-client:2025.7.21
depends_on:
minio:
condition: service_healthy
restart: "no"
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minioadmin}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-minioadmin}
MINIO_BUCKET: ${MINIO_BUCKET:-arm-ka}
entrypoint: ["/bin/sh", "-c"]
command:
- >-
mc alias set local http://minio:9000 "$$MINIO_ROOT_USER" "$$MINIO_ROOT_PASSWORD" &&
mc mb --ignore-existing "local/$$MINIO_BUCKET"
# --- Профиль `services` -------------------------------------------------------------------------------------------
# Одноразово: миграции arm-core (alembic upgrade head) и справочники с dev-пользователями (seed --dev).
# Оба шага идемпотентны; при каждом `up` профиля контейнер снова выполняется и завершается с кодом 0.
# Образ собирает сервис arm-core (build только у него): две сборки одного тега дают разные ID образа, и каждый
# следующий `up` пересоздавал бы arm-core-migrate и arm-core. pull_policy: never — образ локальный, не из реестра.
arm-core-migrate:
profiles: ["services"]
image: arm-core:dev
pull_policy: never
restart: "no"
depends_on:
postgres:
condition: service_healthy
environment: *arm-core-env
command: ["sh", "-c", "alembic upgrade head && python -m scripts.seed --dev"]
arm-core:
profiles: ["services"]
build:
context: ../../arm-core
image: arm-core:dev
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
nats:
condition: service_healthy
minio:
condition: service_healthy
minio-init:
condition: service_completed_successfully
arm-core-migrate:
condition: service_completed_successfully
environment: *arm-core-env
ports:
- "${BIND_ADDR:-127.0.0.1}:${ARM_CORE_PORT:-8000}:8000"
healthcheck:
# curl в python:3.11-slim нет; /healthcheck всегда отвечает 200, поэтому читаем поле nats
test:
- CMD
- python
- -c
- "import json,sys,urllib.request as u; d=json.load(u.urlopen('http://127.0.0.1:8000/healthcheck', timeout=3)); sys.exit(0 if d['nats']=='ok' else 1)"
interval: 5s
timeout: 5s
retries: 12
start_period: 10s
tabular-parser:
profiles: ["services"]
build:
context: ../../tabular-parser
image: tabular-parser:dev
restart: unless-stopped
depends_on:
nats:
condition: service_healthy
minio:
condition: service_healthy
minio-init:
condition: service_completed_successfully
environment: *service-env
ports:
- "${BIND_ADDR:-127.0.0.1}:${TABULAR_PARSER_PORT:-8001}:8000"
healthcheck:
test:
- CMD
- python
- -c
- "import json,sys,urllib.request as u; d=json.load(u.urlopen('http://127.0.0.1:8000/healthcheck', timeout=3)); sys.exit(0 if d['nats']=='ok' else 1)"
interval: 5s
timeout: 5s
retries: 12
start_period: 10s
# Эмулятор ИС Сканирование: тот же образ, что у шлюза (собирает сервис scan-gateway, см. arm-core-migrate); общий
# том hotfolder с шлюзом. Переменные MinIO/NATS не нужны.
# Фикстуры ответов ИС — ../../fixtures/ocr (только чтение): набор <имя>.json + <имя>_*.json для входного файла UUID_<имя>.ext.
scan-emulator:
profiles: ["services"]
image: scan-gateway:dev
pull_policy: never
command: ["python", "-m", "src.scan_emulator"]
restart: unless-stopped
environment:
SCAN_HOTFOLDER_PATH: /data/hotfolder
SCAN_FIXTURES_DIR: /fixtures/ocr
SCAN_EMULATOR_DELAY: "2"
volumes:
- hotfolder:/data/hotfolder
- ../../fixtures/ocr:/fixtures/ocr:ro
scan-gateway:
profiles: ["services"]
build:
context: ../../scan-gateway
image: scan-gateway:dev
restart: unless-stopped
depends_on:
nats:
condition: service_healthy
minio:
condition: service_healthy
minio-init:
condition: service_completed_successfully
environment:
<<: *service-env
SCAN_HOTFOLDER_MODE: local
SCAN_HOTFOLDER_PATH: /data/hotfolder
volumes:
- hotfolder:/data/hotfolder
ports:
- "${BIND_ADDR:-127.0.0.1}:${SCAN_GATEWAY_PORT:-8002}:8000"
healthcheck:
# /healthcheck всегда отвечает 200, поэтому читаем поля nats и hotfolder
test:
- CMD
- python
- -c
- "import json,sys,urllib.request as u; d=json.load(u.urlopen('http://127.0.0.1:8000/healthcheck', timeout=3)); sys.exit(0 if d['nats']=='ok' and d['hotfolder']=='ok' else 1)"
interval: 5s
timeout: 5s
retries: 12
start_period: 10s
volumes:
postgres-data:
minio-data:
# Общая горячая папка scan-gateway и scan-emulator (Input/, Output/)
hotfolder: