From e5d35046465fd8f7847ee58ff6ce896e1432afa2 Mon Sep 17 00:00:00 2001 From: Erico Almeida Date: Wed, 2 Sep 2026 21:02:31 -0300 Subject: [PATCH] =?UTF-8?q?compose:=20vers=C3=A3o=20internet=20(infra=20Do?= =?UTF-8?q?cker=20Hub=20+=20app=20gitea.externo)=20p/=20servidor=20com=20a?= =?UTF-8?q?cesso=20externo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- docker-compose.yml | 229 ++++++++------------------------------------- 1 file changed, 41 insertions(+), 188 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 0233557..bab8c52 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,31 +1,21 @@ # ============================================================================ -# Rastro — Docker Compose para o COOLIFY (máquina nova). -# -# Derivado do deploy/stack.yml (Swarm). Diferenças: -# - Sem labels do Traefik: no Coolify você define os DOMÍNIOS pela UI (por serviço), -# e o proxy do Coolify gera o roteamento. Ver deploy/MIGRACAO-COOLIFY.md. -# - Sem rede `erico-net` externa: o Coolify põe todos os serviços do compose na -# MESMA rede — eles se acham pelo nome do serviço (db, rabbitmq, minio, osrm…). -# - `shm_size` no db (o Compose respeita, diferente do Swarm que exigia tmpfs). -# - `deploy.resources.limits` mantidos (o `docker compose` do Coolify honra) — -# ajuste conforme a capacidade da máquina nova. -# - `migrate` roda só o SCHEMA (sem seed/bootstrap): os usuários/config vêm do -# dump data-migration/rastro-userdata.sql (restaurado depois). Ver runbook. -# - As imagens custom vêm do Gitea; as de infra, do Docker Hub. -# -# Variáveis ${...} → configure no ambiente do recurso no Coolify (ou .env). +# Rastro — Compose "INTERNET" (servidor com acesso externo). +# • Infra (db/rabbitmq/minio/gotenberg): direto do Docker Hub. +# • App (rastro-node/analytics): do Gitea EXTERNO (gitea.externo.utic.app.br) — +# pacotes públicos, pull anônimo (sem login). +# Uso: coloque este arquivo + o .env na mesma pasta e rode `docker compose up -d` +# (ou aponte o Coolify para ele). Depois: restaurar o dump + ajustar domínios. # ============================================================================ x-app-env: &app-env DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public RABBITMQ_URL: amqp://${RABBITMQ_DEFAULT_USER}:${RABBITMQ_DEFAULT_PASS}@rabbitmq:5672 - RASTRO_EXCHANGE: ${RASTRO_EXCHANGE:-rastro.passagens} - RASTRO_QUEUE: ${RASTRO_QUEUE:-rastro.passagens.processar} + RASTRO_EXCHANGE: rastro.passagens + RASTRO_QUEUE: rastro.passagens.processar services: - # ------------------------------------------------------------------ Infra db: - image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/timescaledb-ha:pg16 + image: timescale/timescaledb-ha:pg16 restart: unless-stopped environment: POSTGRES_USER: ${POSTGRES_USER} @@ -39,12 +29,9 @@ services: interval: 10s timeout: 5s retries: 15 - deploy: - resources: - limits: { cpus: '4.0', memory: 6G } rabbitmq: - image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/rabbitmq:3-management + image: rabbitmq:3-management restart: unless-stopped environment: RABBITMQ_DEFAULT_USER: ${RABBITMQ_DEFAULT_USER} @@ -56,12 +43,9 @@ services: interval: 15s timeout: 5s retries: 10 - deploy: - resources: - limits: { cpus: '1.0', memory: 640M } minio: - image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/minio:latest + image: minio/minio:latest restart: unless-stopped command: server /data --console-address ":9001" environment: @@ -69,47 +53,22 @@ services: MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD} volumes: - minio_data:/data - deploy: - resources: - limits: { cpus: '1.0', memory: 640M } gotenberg: - image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/gotenberg:8 + image: gotenberg/gotenberg:8 restart: unless-stopped - command: - - gotenberg - - --chromium-disable-javascript=false - - --api-timeout=60s - deploy: - resources: - limits: { cpus: '2.0', memory: 1536M } + command: [gotenberg, --chromium-disable-javascript=false, --api-timeout=60s] - # OSRM (roteamento por vias) — OPCIONAL na 1ª subida. Precisa do grafo do Brasil - # (~12-15GB) em OSRM_DATA_DIR. Sem ele, deixe COMENTADO e o app sobe sem rotas; - # o processor/dfe-worker caem para no-op de roteamento. Habilite quando levar o grafo. - # osrm: - # image: osrm/osrm-backend:latest - # restart: unless-stopped - # command: ['osrm-routed', '--algorithm', 'mld', '--mmap', '--max-matching-size', '2000', '/data/brazil.osrm'] - # volumes: - # - ${OSRM_DATA_DIR:-/data/rastro/osrm}:/data:ro - # deploy: - # resources: - # limits: { cpus: '2.0', memory: 6G } - - # ------------------------------------------------------------- Init (roda 1x) - # SÓ SCHEMA (sem seed/bootstrap): os usuários/config vêm do dump. Roda uma vez e sai. + # Init: cria só o SCHEMA (usuários/config vêm do dump). Roda 1x e sai. migrate: - image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/rastro-node:${TAG:-latest} + image: gitea.externo.utic.app.br/ericoalmeida/rastro-node:latest restart: "no" depends_on: - db: - condition: service_healthy + db: { condition: service_healthy } environment: <<: *app-env NODE_ENV: production - DB_CONNECTION_LIMIT: ${DB_CONNECTION_LIMIT_MIGRATE:-5} - DB_POOL_TIMEOUT: ${DB_POOL_TIMEOUT:-15} + DB_CONNECTION_LIMIT: '5' command: > sh -c "wait-for-db && pnpm --filter @rastro/db migrate && @@ -117,180 +76,74 @@ services: pnpm --filter @rastro/db timescale && pnpm --filter @rastro/db intel && pnpm --filter @rastro/db analyze" - deploy: - resources: - limits: { cpus: '2.0', memory: 1536M } - - # ---------------------------------------------------------------- Drenagem - # OBS: para migração inicial LEVE, deixe ingestor/dfe-worker parados (scale 0 no - # Coolify) até querer puxar dados. O sistema serve os dados existentes sem eles. - ingestor: - image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/rastro-node:${TAG:-latest} - restart: unless-stopped - depends_on: { db: { condition: service_healthy } } - environment: - <<: *app-env - NODE_ENV: production - DB_CONNECTION_LIMIT: ${DB_CONNECTION_LIMIT_INGESTOR:-5} - DB_POOL_TIMEOUT: ${DB_POOL_TIMEOUT:-15} - ONE_TP_AMB: ${ONE_TP_AMB:-1} - ONE_VER_APLIC: ${ONE_VER_APLIC:-rastro-1.0} - ONE_HOST: ${ONE_HOST:-one.svrs.rs.gov.br} - ONE_TP_DIST: ${ONE_TP_DIST:-1,4} - ONE_CUF: ${ONE_CUF:-41} - ONE_CNPJ_OPER: ${ONE_CNPJ_OPER:-} - ONE_POLL_INTERVAL: ${ONE_POLL_INTERVAL:-120} - ONE_MAX_BATCHES: ${ONE_MAX_BATCHES:-15} - ONE_BATCH_DELAY_MS: ${ONE_BATCH_DELAY_MS:-1200} - ONE_IND_RESUMO: ${ONE_IND_RESUMO:-0} - DFE_CERT_PFX_PATH: ${DFE_CERT_PFX_CONTAINER_PATH:-/certs/11de260603452f3c.pfx} - DFE_CERT_PASSPHRASE: ${DFE_CERT_PASSPHRASE:-} - CERT_DIR: /certs - DFE_TLS_REJECT_UNAUTHORIZED: ${DFE_TLS_REJECT_UNAUTHORIZED:-false} - MINIO_ENDPOINT: minio - MINIO_PORT: '9000' - MINIO_ROOT_USER: ${MINIO_ROOT_USER} - MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD} - MINIO_BUCKET: ${MINIO_BUCKET:-rastro-photos} - command: sh -c "wait-for-db schema rabbitmq && pnpm --filter @rastro/ingestor start" - volumes: - - ${CERT_HOST_DIR:-/data/rastro/certificado}:/certs:ro - deploy: - resources: - limits: { cpus: '1.0', memory: 640M } processor: - image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/rastro-node:${TAG:-latest} + image: gitea.externo.utic.app.br/ericoalmeida/rastro-node:latest restart: unless-stopped - depends_on: { db: { condition: service_healthy } } + depends_on: + db: { condition: service_healthy } environment: <<: *app-env NODE_ENV: production - DB_CONNECTION_LIMIT: ${DB_CONNECTION_LIMIT_PROCESSOR:-8} - DB_POOL_TIMEOUT: ${DB_POOL_TIMEOUT:-15} - SEFAZ_PR_DFE_URL: ${SEFAZ_PR_DFE_URL:-} - SEFAZ_PR_DFE_USER: ${SEFAZ_PR_DFE_USER:-} - SEFAZ_PR_DFE_PASSWORD: ${SEFAZ_PR_DFE_PASSWORD:-} + DB_CONNECTION_LIMIT: '8' OSRM_URL: ${OSRM_URL:-http://osrm:5000} - REROUTE_STALE_INTERVAL_MIN: ${REROUTE_STALE_INTERVAL_MIN:-15} + REROUTE_STALE_INTERVAL_MIN: '15' command: sh -c "wait-for-db schema rabbitmq && pnpm --filter @rastro/processor start" - deploy: - resources: - limits: { cpus: '2.0', memory: 1G } - - dfe-worker: - image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/rastro-node:${TAG:-latest} - restart: unless-stopped - depends_on: { db: { condition: service_healthy } } - environment: - <<: *app-env - NODE_ENV: production - DB_CONNECTION_LIMIT: ${DB_CONNECTION_LIMIT_DFE_WORKER:-12} - DB_POOL_TIMEOUT: ${DB_POOL_TIMEOUT:-15} - SEFAZ_PR_DFE_URL: ${SEFAZ_PR_DFE_URL:-} - SEFAZ_PR_DFE_USER: ${SEFAZ_PR_DFE_USER:-} - SEFAZ_PR_DFE_PASSWORD: ${SEFAZ_PR_DFE_PASSWORD:-} - OSRM_URL: ${OSRM_URL:-http://osrm:5000} - DFE_GEN_INTERVAL: ${DFE_GEN_INTERVAL:-20} - DFE_GEN_BATCH: ${DFE_GEN_BATCH:-25} - DFE_GEN_CONCURRENCY: ${DFE_GEN_CONCURRENCY:-6} - DFE_REFRESH_TTL_HOURS: ${DFE_REFRESH_TTL_HOURS:-12} - DFE_GEN_ROUTE: ${DFE_GEN_ROUTE:-true} - SEFAZ_WS_TP_AMB: ${SEFAZ_WS_TP_AMB:-1} - SEFAZ_WS_ENDPOINTS: ${SEFAZ_WS_ENDPOINTS:-} - SEFAZ_WS_MAX_CTE: ${SEFAZ_WS_MAX_CTE:-20} - SEFAZ_ARQUIVOXML_ENDPOINTS: ${SEFAZ_ARQUIVOXML_ENDPOINTS:-} - SEFAZ_ARQUIVOXML_CUF: ${SEFAZ_ARQUIVOXML_CUF:-41} - SEFAZ_ARQUIVOXML_ORGAO: ${SEFAZ_ARQUIVOXML_ORGAO:-SEFA-PARANA} - SEFAZ_ARQUIVOXML_SETOR: ${SEFAZ_ARQUIVOXML_SETOR:-AGAA} - SEFAZ_ARQUIVOXML_VERAPLIC: ${SEFAZ_ARQUIVOXML_VERAPLIC:-PR_Rastro_v1} - SEFAZ_ARQUIVOXML_MATR: ${SEFAZ_ARQUIVOXML_MATR:-999999} - SEFAZ_ARQUIVOXML_MAX_NFE: ${SEFAZ_ARQUIVOXML_MAX_NFE:-40} - SEFAZ_CONSULTADFE_ENDPOINTS: ${SEFAZ_CONSULTADFE_ENDPOINTS:-} - DFE_CERT_PFX_PATH: ${DFE_CERT_PFX_CONTAINER_PATH:-/certs/11de260603452f3c.pfx} - DFE_CERT_PASSPHRASE: ${DFE_CERT_PASSPHRASE:-} - CERT_DIR: /certs - DFE_TLS_REJECT_UNAUTHORIZED: ${DFE_TLS_REJECT_UNAUTHORIZED:-false} - command: sh -c "wait-for-db schema && pnpm --filter @rastro/processor start:worker" - volumes: - - ${CERT_HOST_DIR:-/data/rastro/certificado}:/certs:ro - deploy: - resources: - limits: { cpus: '2.0', memory: 1G } analytics: - image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/rastro-analytics:${TAG:-latest} + image: gitea.externo.utic.app.br/ericoalmeida/rastro-analytics:latest restart: unless-stopped - depends_on: { db: { condition: service_healthy } } + depends_on: + db: { condition: service_healthy } environment: <<: *app-env - INTEL_TOP_COMPANIES: ${INTEL_TOP_COMPANIES:-200} - INTEL_TOP_COMMODITIES: ${INTEL_TOP_COMMODITIES:-50} - INTEL_HORIZON_WEEKS: ${INTEL_HORIZON_WEEKS:-8} - INTEL_CYCLE_HOURS: ${INTEL_CYCLE_HOURS:-24} - deploy: - resources: - limits: { cpus: '2.0', memory: 1536M } + INTEL_TOP_COMPANIES: '200' + INTEL_TOP_COMMODITIES: '50' + INTEL_HORIZON_WEEKS: '8' + INTEL_CYCLE_HOURS: '24' - # ---------------------------------------------------------------- Backend / Fronts - # No Coolify, atribua os DOMÍNIOS a estes 3 serviços pela UI (ver runbook). O - # backend precisa responder /api e /health NO MESMO domínio do web e do admin - # (o front chama same-origin). Configure isso pelo roteamento por path do Coolify. backend: - image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/rastro-node:${TAG:-latest} + image: gitea.externo.utic.app.br/ericoalmeida/rastro-node:latest restart: unless-stopped - depends_on: { db: { condition: service_healthy } } + depends_on: + db: { condition: service_healthy } environment: <<: *app-env NODE_ENV: production - DB_CONNECTION_LIMIT: ${DB_CONNECTION_LIMIT_BACKEND:-12} - DB_POOL_TIMEOUT: ${DB_POOL_TIMEOUT:-15} + DB_CONNECTION_LIMIT: '12' BACKEND_PORT: '39010' JWT_SECRET: ${JWT_SECRET} - SESSION_COOKIE_NAME: ${SESSION_COOKIE_NAME:-rastro_session} + SESSION_COOKIE_NAME: rastro_session CORS_ORIGINS: https://${WEB_DOMAIN},https://${ADMIN_DOMAIN} - RATE_LIMIT_MAX: ${RATE_LIMIT_MAX:-1000} + RATE_LIMIT_MAX: '1000' GOTENBERG_URL: http://gotenberg:3000 MINIO_ENDPOINT: minio MINIO_PORT: '9000' MINIO_ROOT_USER: ${MINIO_ROOT_USER} MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD} - MINIO_BUCKET: ${MINIO_BUCKET:-rastro-photos} + MINIO_BUCKET: rastro-photos command: sh -c "wait-for-db schema && pnpm --filter @rastro/backend start" - # Porta interna do backend (aponte o domínio do Coolify para 39010, path /api e /health) - expose: - - "39010" - deploy: - resources: - limits: { cpus: '2.0', memory: 1G } + expose: ["39010"] web: - image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/rastro-node:${TAG:-latest} + image: gitea.externo.utic.app.br/ericoalmeida/rastro-node:latest restart: unless-stopped environment: <<: *app-env VITE_DEV_HELPERS: 'false' PREVIEW_ALLOWED_HOSTS: ${WEB_DOMAIN} command: sh -c "pnpm --filter web preview --host 0.0.0.0 --port 39000" - expose: - - "39000" - deploy: - resources: - limits: { cpus: '1.0', memory: 640M } + expose: ["39000"] admin: - image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/rastro-node:${TAG:-latest} + image: gitea.externo.utic.app.br/ericoalmeida/rastro-node:latest restart: unless-stopped environment: <<: *app-env VITE_DEV_HELPERS: 'false' PREVIEW_ALLOWED_HOSTS: ${ADMIN_DOMAIN} command: sh -c "pnpm --filter admin preview --host 0.0.0.0 --port 39020" - expose: - - "39020" - deploy: - resources: - limits: { cpus: '1.0', memory: 640M } + expose: ["39020"] volumes: db_data: