177 lines
5.0 KiB
YAML
177 lines
5.0 KiB
YAML
# Bot de Pontos v2 — Docker Compose (ARQUITETURA.md, seção 11).
|
|
# Antes de subir: criar o .env (a partir do .env.example) e os arquivos em ./secrets (ver README).
|
|
|
|
name: botpontos
|
|
|
|
x-backend: &backend
|
|
build:
|
|
context: ./backend
|
|
image: botpontos-backend:dev
|
|
restart: unless-stopped
|
|
read_only: true
|
|
cap_drop: [ALL]
|
|
security_opt: ["no-new-privileges:true"]
|
|
|
|
x-backend-env: &backend-env
|
|
BP_LOG_LEVEL: ${BP_LOG_LEVEL:-info}
|
|
BP_DEFAULT_TIMEZONE: ${BP_DEFAULT_TIMEZONE:-America/Sao_Paulo}
|
|
BP_DB_HOST: postgres
|
|
BP_DB_NAME: botpontos
|
|
BP_DB_USER: botpontos_app
|
|
BP_DB_PASSWORD_FILE: /run/secrets/pg_app_password
|
|
BP_ENCRYPTION_KEY_FILE: /run/secrets/encryption_key
|
|
BP_ENCRYPTION_KEY_VERSION: ${BP_ENCRYPTION_KEY_VERSION:-1}
|
|
BP_TELEGRAM_TOKEN_FILE: /run/secrets/telegram_token
|
|
BP_HOLIDAY_API_KEY_FILE: /run/secrets/holiday_api_key
|
|
BP_HOLIDAY_LOCATION: ${BP_HOLIDAY_LOCATION:-3106200}
|
|
BP_PUBLIC_URL: ${BP_PUBLIC_URL:-}
|
|
BP_COOKIE_SECURE: ${BP_COOKIE_SECURE:-true}
|
|
BP_TRUSTED_PROXIES: 127.0.0.0/8,172.16.0.0/12,${BP_NPM_IP:-}
|
|
|
|
x-backend-secrets: &backend-secrets
|
|
- pg_app_password
|
|
- encryption_key
|
|
- telegram_token
|
|
- holiday_api_key
|
|
|
|
services:
|
|
postgres:
|
|
image: postgres:17-alpine
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_DB: botpontos
|
|
POSTGRES_USER: botpontos
|
|
POSTGRES_PASSWORD_FILE: /run/secrets/pg_password
|
|
volumes:
|
|
- pgdata:/var/lib/postgresql/data
|
|
- ./postgres/init:/docker-entrypoint-initdb.d:ro
|
|
secrets: [pg_password, pg_app_password]
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U botpontos -d botpontos"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 10
|
|
networks: [internal]
|
|
|
|
# Aplica as migrations com o usuário dono do banco e termina.
|
|
migrate:
|
|
<<: *backend
|
|
restart: "no"
|
|
command: ["migrate", "up"]
|
|
environment:
|
|
BP_LOG_LEVEL: ${BP_LOG_LEVEL:-info}
|
|
BP_DB_HOST: postgres
|
|
BP_DB_NAME: botpontos
|
|
BP_DB_USER: botpontos
|
|
BP_DB_PASSWORD_FILE: /run/secrets/pg_password
|
|
secrets: [pg_password]
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
networks: [internal]
|
|
|
|
api:
|
|
<<: *backend
|
|
command: ["api"]
|
|
environment:
|
|
<<: *backend-env
|
|
BP_DB_MAX_CONNS: "10"
|
|
secrets: *backend-secrets
|
|
depends_on:
|
|
migrate:
|
|
condition: service_completed_successfully
|
|
healthcheck:
|
|
test: ["CMD", "/botpontos", "healthcheck", "http://127.0.0.1:8080/api/v1/health/live"]
|
|
interval: 15s
|
|
timeout: 5s
|
|
retries: 3
|
|
# egress: a API valida credenciais na PontoMais, reenvia lembretes e sincroniza feriados
|
|
networks: [internal, egress]
|
|
|
|
worker:
|
|
<<: *backend
|
|
command: ["worker"]
|
|
environment:
|
|
<<: *backend-env
|
|
BP_DB_MAX_CONNS: "5"
|
|
secrets: *backend-secrets
|
|
depends_on:
|
|
migrate:
|
|
condition: service_completed_successfully
|
|
healthcheck:
|
|
test: ["CMD", "/botpontos", "healthcheck", "http://127.0.0.1:8081/health/live"]
|
|
interval: 15s
|
|
timeout: 5s
|
|
retries: 3
|
|
networks: [internal, egress]
|
|
|
|
web:
|
|
build:
|
|
context: ./web
|
|
args:
|
|
API_INTERNAL_URL: http://api:8080
|
|
image: botpontos-web:dev
|
|
restart: unless-stopped
|
|
environment:
|
|
API_INTERNAL_URL: http://api:8080
|
|
depends_on:
|
|
api:
|
|
condition: service_healthy
|
|
# Publicado só no IP de rede local do servidor. O Nginx Proxy Manager (outra
|
|
# máquina) aponta para cá, e o firewall libera a 3000 só para o IP do NPM
|
|
# (deploy/botpontos-firewall.service). Em desenvolvimento, use 127.0.0.1.
|
|
ports:
|
|
- "${BP_HOST_LAN_IP:?defina BP_HOST_LAN_IP no arquivo .env}:3000:3000"
|
|
read_only: true
|
|
tmpfs:
|
|
- /tmp
|
|
- /app/.next/cache
|
|
cap_drop: [ALL]
|
|
security_opt: ["no-new-privileges:true"]
|
|
healthcheck:
|
|
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/healthz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
|
|
interval: 15s
|
|
timeout: 5s
|
|
retries: 3
|
|
networks: [internal, ingress]
|
|
|
|
backup:
|
|
image: postgres:17-alpine
|
|
restart: unless-stopped
|
|
entrypoint: ["sh", "/scripts/backup-loop.sh"]
|
|
environment:
|
|
PGHOST: postgres
|
|
PGUSER: botpontos
|
|
PGDATABASE: botpontos
|
|
BACKUP_INTERVAL_SECONDS: "86400"
|
|
BACKUP_RETENTION_DAYS: "14"
|
|
volumes:
|
|
- ./backups:/backups
|
|
- ./scripts:/scripts:ro
|
|
secrets: [pg_password]
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
networks: [internal]
|
|
|
|
volumes:
|
|
pgdata:
|
|
|
|
networks:
|
|
internal:
|
|
internal: true # sem acesso à internet; só comunicação entre containers
|
|
egress: {} # saída para PontoMais, Telegram e feriadosapi.com
|
|
ingress: {} # rede da porta publicada do web
|
|
|
|
secrets:
|
|
pg_password:
|
|
file: ./secrets/pg_password
|
|
pg_app_password:
|
|
file: ./secrets/pg_app_password
|
|
encryption_key:
|
|
file: ./secrets/encryption_key
|
|
telegram_token:
|
|
file: ./secrets/telegram_token
|
|
holiday_api_key:
|
|
file: ./secrets/holiday_api_key # pode ficar vazio: vale o fallback de segunda a sexta
|