todos-contra-el-fuego-web/RUNBOOK.md
vjrj 197a59f641 fase 3: stack docker-compose local del sistema modernizado
Compose con los 5 servicios: mongo:7 (replica set rs0 + mongo-init one-shot),
redis (AOF), web Meteor 3.1 (Dockerfile multi-stage: builder debian con
meteor-tool 3.1 -> server-deps alpine -> runtime node:22-alpine), notifications
(dry-run) y node-red 4. Healthchecks (127.0.0.1, no localhost: busybox wget
prefiere IPv6 y Meteor escucha IPv4), restart unless-stopped, logging rotado
3x10MB, secretos montados desde ./secrets (gitignored, solo .example versionado).
.npmrc legacy-peer-deps para el ERESOLVE de las libs react viejas.

Validado: los 5 servicios healthy y smoke REST byte-identico (12/12) contra la
web dockerizada en :3200. RUNBOOK.md documenta arranque, smoke, backups y
rollback. No toca infra de Comunes.
2026-07-15 01:01:07 +02:00

4.6 KiB
Raw Permalink Blame History

RUNBOOK — stack local dockerizado (fase 3, validación)

Stack Docker Compose del sistema modernizado de "Todos contra el fuego": web Meteor 3.1 (Node 22), MongoDB 7 (replica set de un nodo), Redis (AOF), tcef-notifications y node-red. Es el entorno de validación local previo a producción — el despliegue real irá al ansible de Comunes (fase 3 del plan); este compose no toca el proxy ni la infra compartida.

Requisitos

  • Docker + Docker Compose v2.
  • El repo hermano ../tcef-notifications (el compose construye su imagen desde ahí).

Primer arranque

# 1. Secretos (gitignorados; ver secrets/README.md)
cp settings-development.json secrets/meteor-settings.json
cp secrets/notifications.env.example secrets/notifications.env   # MODE=dry-run

# 2. Construir y levantar (el primer build de la web tarda: descarga meteor-tool
#    y compila el bundle; ~10-20 min en frío)
docker compose build
docker compose up -d

# 3. Comprobar salud
docker compose ps          # todo "healthy" / mongo-init "exited (0)"

Servicios y puertos en el host:

Servicio Contenedor URL / puerto
web Meteor tcef-stack-web http://localhost:3200
node-red tcef-stack-node-red http://localhost:1880
MongoDB 7 tcef-stack-mongo solo red interna (usar docker exec)
Redis tcef-stack-redis solo red interna
notificaciones tcef-stack-notifications sin puerto (worker)

mongo-init es un one-shot: inicia el replica set rs0 y fija db.migrations a la versión 18 (los up() históricos ya son async, pero se pinta v18 porque los datos reales de producción llegan pre-migrados).

Nota healthcheck: los checks usan 127.0.0.1, no localhost. El wget de busybox (alpine) resuelve localhost a ::1 (IPv6) primero, pero los servidores Meteor/node-red escuchan solo en IPv4 → un localhost daría unhealthy aunque la app responda perfectamente por el puerto mapeado.

Smoke test REST (red de seguridad del contrato Flutter)

Debe ser byte-idéntico a los snapshots committeados:

MONGO_CONTAINER=tcef-stack-mongo MONGO_SHELL=mongosh MONGO_PORT=27017 \
  BASE_URL=http://localhost:3200 ./smoke/smoke.sh

Operación diaria

docker compose logs -f web            # logs de un servicio (rotados: 3×10MB)
docker compose ps                     # estado + healthchecks
docker compose restart notifications  # reiniciar un servicio
docker compose down                   # parar todo (los volúmenes persisten)
docker compose down -v                # ⚠️ borra también mongo/redis/node-red

Desplegar una nueva versión

# web (tras cambios en el repo)
docker compose build web && docker compose up -d web

# notificaciones (tras cambios en ../tcef-notifications)
docker compose build notifications && docker compose up -d notifications

Verificar tras cada despliegue de la web: docker compose ps healthy + smoke REST byte-idéntico (arriba).

Backups y restauración (volúmenes locales)

# Mongo: dump / restore de la db fuegos
docker exec tcef-stack-mongo mongodump --db fuegos --archive > fuegos.dump
docker exec -i tcef-stack-mongo mongorestore --archive --drop < fuegos.dump

# node-red: tar del volumen de datos
docker run --rm -v tcef-stack_nodered-data:/data -v "$PWD:/backup" alpine \
  tar czf /backup/nodered-data.tgz -C /data .

Rollback

  • web: git checkout <commit-anterior> + docker compose build web && docker compose up -d web. (En producción se conservará la imagen anterior etiquetada; aquí basta git.)
  • notificaciones: igual, desde ../tcef-notifications. KILL_SWITCH=1 en secrets/notifications.env + docker compose up -d notifications detiene todo envío al instante sin parar el servicio.
  • datos: restaurar el último dump (arriba).

Salvaguardas de notificaciones

secrets/notifications.env arranca en MODE=dry-run (no envía nada). La progresión dry-run → shadow → canary → full está documentada en ../tcef-notifications/docs/rollout.md y nunca se salta pasos. En este stack local no hay credenciales reales salvo que las pongas tú.

Deuda conocida de este compose

  • tcef-notifications no expone endpoint HTTP de salud → healthcheck por proceso (pgrep). Añadir /healthz al servicio cuando toque.
  • node-red corre la imagen oficial vacía (los flows de los bots viven en shiva; su migración de datos es parte del cutover real de fase 3).
  • El driver mongodb 3.7 de tcef-notifications (elegido por el Mongo 3.2 de producción) conecta con Mongo 7 en pruebas locales, pero al hacer el cutover real a Mongo 7 debe subirse a driver 6.x (y habilitar change streams).