Saltar a contenido

RUNBOOK · jobs-deploy

Procedimientos para construir, desplegar y operar el contenedor dabra-panel (panel + 32 jobs). Descripción y decisiones: README.md.

Reglas que no se saltan: nunca versionar .env ni secrets/*.env; nunca pegar valores de secretos en tickets, logs ni chats; <destinatario de avisos> sigue siendo el destinatario de avisos y errores.

1. Requisitos

  • Docker Engine + plugin Compose v2, amd64, en la máquina de build y en la VM (docker --version, docker compose version).
  • Acceso a internet solo en el build (Debian, packages.microsoft.com, PyPI, GitHub para wkhtmltopdf). La VM no lo necesita si se transfiere la imagen.
  • Tras un proxy/antivirus que inspecciona HTTPS: poner la CA raíz en PEM en certs/<nombre>.crt.

2. Construir la imagen

# Piloto (carpetas sueltas en pilot/): copia el panel y los 18 repos a ./panel y ./jobs
python tools/preparar_contexto.py --limpiar
# Repo real: git submodule update --init --recursive

docker compose build

El build instala 18 venvs y verifica con import <paquete> que cada job queda importable; si falta una dependencia, el build falla y dice en qué repo.

Primera verificación, sin levantar nada:

docker run --rm --entrypoint python dabra-jobs:latest -m tools.sync_jobs --validar   # 32 jobs, 0 errores
docker run --rm --entrypoint /opt/dabra/bin/smoke dabra-jobs:latest

En esta segunda, todo debe salir OK salvo SIN secrets/... (esperado) y el panel no responde en :8000 (el panel no está corriendo).

Estado: ejecutados con éxito en Docker Desktop el 2026-10-14. Si el build falla en otra máquina, lo más probable es: el .deb de wkhtmltopdf (cambiar WKHTMLTOPDF_DEB_URL), la versión de msodbcsql17 en el repositorio de Microsoft para Debian 12, o un paquete de PyPI sin wheel (habría que agregar compilador).

3. Llevar la imagen a la VM

# Máquina de build
docker save dabra-jobs:latest | gzip > dabra-jobs-$(date +%F).tar.gz
scp dabra-jobs-*.tar.gz docker-compose.yml .env.example usuario@vm:/opt/dabra-deploy/

# VM
cd /opt/dabra-deploy
gunzip -c dabra-jobs-*.tar.gz | docker load

Para versiones: DABRA_VERSION=2026.10.14 docker compose build etiqueta dabra-jobs:2026.10.14. Conservar la anterior para el rollback.

4. Preparar la VM

sudo mkdir -p /var/log/dabra /var/lib/dabra
sudo chown 10001 /var/log/dabra /var/lib/dabra      # el contenedor corre con UID 10001

cp .env.example .env && chmod 600 .env              # completar SECRET_KEY, ADMIN_PASSWORD, API_TOKEN, SMTP...
#   LOGS_HOST_DIR=/var/log/dabra   DATA_HOST_DIR=/var/lib/dabra   DABRA_VERSION=<etiqueta>

mkdir -p secrets env_examples
# Plantillas con los nombres de variables de cada job (solo nombres), generadas desde la propia imagen:
docker run --rm --user "$(id -u)" -v "$PWD/env_examples:/out" --entrypoint python dabra-jobs:${DABRA_VERSION:-latest} \
  tools/generar_env_example.py --jobs /opt/dabra/jobs --salida /out
for f in env_examples/*.env.example; do n=$(basename "$f" .example); [ -e secrets/$n ] || cp "$f" secrets/$n; done
chmod 600 secrets/*.env                             # completar cada uno con los valores reales
# Verificar (imprime solo nombres que faltan, nunca valores):
docker run --rm -v "$PWD/secrets:/run/secrets/dabra:ro" --entrypoint python dabra-jobs:${DABRA_VERSION:-latest} \
  tools/verificar_env.py --jobs /opt/dabra/jobs --secrets /run/secrets/dabra

Los valores salen del inventario de secretos del proyecto (fuera de este repo). Si una variable es opcional en el job, dejarla vacía y aceptar el aviso de verificar_env.py.

Montar los shares de backup (si se usan) y descomentar su línea en docker-compose.yml.

5. Arrancar y verificar

docker compose up -d
docker compose ps                                   # STATUS healthy en ~40 s
docker compose logs panel | grep -E "creado|actualizado|ERROR|WARNING"   # 32 'creado' la primera vez
docker compose exec panel /opt/dabra/bin/smoke      # debe terminar en SMOKE OK

Entrar a http://<vm>:8080 con ADMIN_USER / ADMIN_PASSWORD. Publicar detrás de nginx con TLS y COOKIE_SECURE=true; no exponer el panel sin HTTPS.

6. Puesta en marcha controlada de los jobs

El panel ejecuta los 32 jobs según su cron en cuanto están activos (todos tienen ejecutar_interno: true; no hace falta ningún cron en la VM). Si la base del panel se creó con una versión anterior de los job.yaml, en la que 17 jobs figuraban como ejecutados por un cron externo, aplica el cambio una vez con docker compose exec panel python -m tools.sync_jobs --forzar (sobrescribe también cron, tolerancia, timeout y activo con los del yaml; hazlo antes de editar nada en el panel). Para evitar doble envío (el mismo archivo enviado desde Windows y desde Linux):

  1. Con el contenedor arriba, desactivar en el panel los jobs que todavía corren en el servidor Windows o en el cron anterior (o arrancar con SCHEDULER_ENABLED=false en .env mientras se prueba).
  2. Probar cada job sin efectos externos:
    docker compose exec panel /opt/dabra/bin/dabra-job job-envio-puma .venv/bin/python -m envio_puma --dry-run
    
    Todos aceptan --dry-run (ver el RUNBOOK de cada repo). Revisar el log y el exit code (0 ok, 1 error, 2 configuración).
  3. Orden sugerido: monitores y lecturas (monitor-*, ingesta-dolarapi) → reportes internos → envíos a terceros, de uno en uno, usando "Ejecutar ahora" del panel con rango de fechas cuando el job lo acepta.
  4. Cuando un job queda validado: apagarlo en su origen el mismo día y dejarlo activo en el panel. Anotar la fecha en ESTADO_MIGRACION.md.

7. Operación diaria

Tarea Cómo
Ver estado y alertas Panel → Estado / Alertas
Logs de una corrida Panel → job → corrida, o /var/log/dabra/<job>/<fecha>.log en el host
Correr un job ya Panel → job → Ejecutar ahora (con desde/hasta si acepta_rango)
Cambiar cron, tolerancia, timeout, activo Panel → job. sync_jobs no lo pisa
Volver a leer los job.yaml docker compose exec panel python -m tools.sync_jobs (agregar --dry-run para ver sin escribir)
Pisar lo editado en el panel con lo del yaml ... sync_jobs --forzar
Jobs que ya no están en ningún yaml Aparecen como huerfano; ... sync_jobs --desactivar-huerfanos los desactiva (nunca borra)
Cambiar un secreto de un job Editar secrets/<repo>.env; el job lo lee en su próxima corrida, sin reiniciar
Cambiar .env del panel docker compose up -d (recrea el contenedor)

8. Actualizar un job

  1. Commit en el repo del job (con sus tests en verde) y, en el repo real, avanzar el submódulo en jobs-deploy.
  2. python tools/preparar_contexto.py --limpiar (piloto) y DABRA_VERSION=<nueva> docker compose build.
  3. Transferir (sección 3) y DABRA_VERSION=<nueva> docker compose up -d.
  4. docker compose exec panel /opt/dabra/bin/smoke.

La base del panel y los datos de los jobs están en volúmenes: sobreviven al cambio de imagen. MANIFEST.json dentro de la imagen (/opt/dabra/MANIFEST.json) dice qué commit de cada repo contiene.

9. Rollback

DABRA_VERSION=<anterior> docker compose up -d

Si el job nuevo ya escribió algo, el rollback no lo deshace; ver el RUNBOOK del repo del job.

10. Backup de la base del panel

docker run --rm -v dabra-jobs_panel_data:/data -v "$PWD":/backup alpine \
  tar czf /backup/panel_data_$(date +%F).tgz -C /data .

(Confirmar el nombre real del volumen con docker volume ls.) Los datos de los jobs viven en DATA_HOST_DIR y los logs en LOGS_HOST_DIR: incluirlos en el respaldo del servidor.

11. Problemas frecuentes

Síntoma Causa y solución
Un job sale con ERROR: no existe /opt/dabra/jobs/... o exit 127 El comando quedó mal en el panel; sync_jobs lo corrige (se refresca siempre)
El job falla con Falta la variable de entorno X Falta en secrets/<repo>.env; docker compose exec panel python tools/verificar_env.py --jobs /opt/dabra/jobs --secrets /run/secrets/dabra
Permission denied en /data/logs o /var/lib/dabra chown 10001 en la carpeta del host
Can't open lib 'ODBC Driver 17 for SQL Server' Revisar odbcinst -q -d dentro del contenedor; reconstruir la imagen
El job usa credenciales del panel (SMTP del panel en vez del propio) Debe pasar por dabra-job; revisar que el comando en el panel empiece por /opt/dabra/bin/dabra-job
sync_jobs informa diferente Hay un campo editado en el panel que difiere del yaml; es informativo. Usar --forzar solo si se quiere volver al yaml
Alerta LOCK_HELD Se lanzó un job mientras seguía corriendo la corrida anterior (el panel no solapa un job consigo mismo)
Alerta RUN_INTERRUPTED El panel se reinició durante una corrida; revisar si el job dejó datos a medias
Jobs que arrancan tarde en las franjas cargadas El panel ejecuta 4 a la vez; ajustar horarios en el panel o ampliar el pool (cambio en el panel, a decidir)
CERTIFICATE_VERIFY_FAILED en el build Proxy/antivirus: agregar la CA en certs/
exec /opt/dabra/bin/entrypoint.sh: no such file or directory Fin de línea CRLF en los .sh; el Dockerfile lo corrige, pero conviene clonar con .gitattributes

Fuente: repositorio jobs-deploy, versión 5bbe011. Página generada con tools/publicar_docs.py.