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
.debde wkhtmltopdf (cambiarWKHTMLTOPDF_DEB_URL), la versión demsodbcsql17en 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):
- 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=falseen.envmientras se prueba). - Probar cada job sin efectos externos:
Todos aceptan
docker compose exec panel /opt/dabra/bin/dabra-job job-envio-puma .venv/bin/python -m envio_puma --dry-run--dry-run(ver elRUNBOOKde cada repo). Revisar el log y el exit code (0 ok, 1 error, 2 configuración). - 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. - 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¶
- Commit en el repo del job (con sus tests en verde) y, en el repo real, avanzar el submódulo en
jobs-deploy. python tools/preparar_contexto.py --limpiar(piloto) yDABRA_VERSION=<nueva> docker compose build.- Transferir (sección 3) y
DABRA_VERSION=<nueva> docker compose up -d. 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¶
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.