Arquitectura cdylib + backend, modos dump e incremental por oplog, replay point-in-time, manifest firmado con Ed25519, exporter Prometheus y aislamiento de licencia para Bacula Community 15.0.3+ y Bacularis.
Documento técnico complementario a la página del plugin PodHeitor MongoDB.
1. El problema: Bacula stock no respalda MongoDB de forma segura
El File Daemon de Bacula, por sí solo, respalda archivos. MongoDB en producción no es un conjunto coherente de archivos en un punto único del tiempo: copiar /var/lib/mongo con mongod activo produce un snapshot inconsistente que falla en --repair o — peor — abre silenciosamente en estado corrupto. Las alternativas tradicionales tienen cada una su costo:
- Bacula Enterprise MongoDB plugin — solo hace
mongodumpfull; no tiene incrementales por oplog, ni PITR, ni manifest firmado, ni exporter de métricas. - Veeam / Commvault — el precio por TB protegido escala mal en clusters MongoDB grandes; PITR sigue dependiendo de oplog manual.
- Scripts caseros de
mongodump— ignoran read preference, martillan al PRIMARY, no detectan rotation gap del oplog, y el operador se entera solo en el momento del desastre.
PodHeitor MongoDB cubre esos huecos con paralelismo cross-DB y cross-collection, oplog tip persistente, replay PIT por timestamp o contador de incremental, y empaquetado RPM/DEB con unit systemd hardened.
2. Modelo arquitectónico
El plugin sigue el patrón PodHeitor de cdylib + backend standalone, con PTCOMM (framing length-tagged sobre stdin/stdout):
bacula-fd (root, daemon)
│
│ dlopen
▼
/opt/bacula/plugins/podheitor-mongodb-fd.so (Rust cdylib)
│
│ fork+exec, PTCOMM stdin/stdout
▼
/opt/bacula/bin/podheitor-mongodb-backend (subproceso por job)
├── mongodump / mongorestore
├── stats sidecar → /opt/bacula/working/podheitor-mongodb-<r>-stats.json
├── oplog tip file → ...-tip.json
└── manifest + topology + RestoreObject → catálogo Bacula (FT_RESTORE_FIRST=25)
│
▼
/opt/bacula/bin/podheitor-mongodb-exporter
(HTTP :9105/metrics, bacula:bacula, systemd hardened)
El motivo del split es el mismo que en HPC: crash isolation (un panic en código que toca MongoDB no bloquea bacula-fd), libertad de paralelismo (el backend hospeda tokio + threadpools cross-DB sin violar el contrato Bacula de «un thread por bpContext«), y firewall de licencia (el subproceso nunca toca el ABI de Bacula; solo el cdylib lo hace, exclusivamente vía el crate bacula-fd-abi con extern "C" independiente).
3. Modos de backup soportados (v1.0)
| Modo | Mecanismo | Estado v1.0 |
|---|---|---|
dump |
mongodump lógico streaming, BSON sobre PTCOMM |
GA — JobId 7984/7985 validados |
dump multi-DB pipelined |
N DBs en paralelo, cap configurable (parallel_dbs=4) |
GA — JobId 7906 |
dump chunking por collection |
Particiona collection grande por _id vía $bucketAuto |
GA — JobId 7925/7927 |
Incremental por oplog (level=I) |
applyOps over the wire — incrementales reales, no diff de dump |
GA — JobId 8037-8041 |
| Replay PIT | second / RFC 3339 / :inc / @inc |
GA — JobId 8065-8099 |
snapshot (LVM/ZFS) |
Stub de código | Phase 3 — pendiente lab LVM/ZFS-backed |
hot_backup (Percona createBackup) |
Stub de código | Phase 4 — pendiente Percona Server lab |
| Orquestación de cluster sharded | Stub de código | Phase 6 — pendiente |
replicate (DR clone) |
Stub de código | Phase 7 — pendiente |
4. Selector de fuente SECONDARY-aware
Un backup que martilla al PRIMARY es un backup que cuesta SLA. El plugin parsea el connection string replicaSet, ejecuta rs.status() en el driver, y elige un SECONDARY saludable (readPreference=secondaryPreferred respetado). Si ningún SECONDARY está accesible, cae a PRIMARY con warning explícito en el job log — comportamiento documentado, no silencioso.
Validado en campo: JobId 7728/7996.
5. Incremental por oplog — la pieza que le falta a Bacula Enterprise
Incrementales «de verdad» en MongoDB exigen el oplog. El plugin mantiene un oplog tip persistente en /opt/bacula/working/podheitor-mongodb-<resource>-tip.json: en cada job level=I, lee el tip del job anterior, abre cursor tailable en local.oplog.rs desde ese timestamp, y streama todos los applyOps hasta el tip actual.
La detección de rotation gap es obligatoria: si el oplog dio wrap entre dos jobs, el tip antiguo ya no existe. El plugin lo detecta comparando el ts del primer entry vs el tip esperado y aborta con mensaje claro — el operador debe correr Full nuevo. Validado en JobId 8047-8050.
6. Replay point-in-time
Restore granular a un instante arbitrario, sin tener que restaurar la chain entera en la máquina destino:
# Por timestamp absoluto (RFC 3339)
pluginoptions "podheitor-mongodb: mode=restore pit=2026-04-15T14:30:00Z dry_run=true"
# Por contador de incremental dentro del día
pluginoptions "podheitor-mongodb: mode=restore pit=:inc=12"
# Por segundo Unix
pluginoptions "podheitor-mongodb: mode=restore pit=1713187800"
dry_run=true hace que el plugin compute la chain (Full + N incrementales) y emita preview en el job log sin aplicar — útil para que el operador verifique antes de ejecutar restore destructivo. Validado en JobId 8097/8099.
El sidecar JSON per-restore elimina la necesidad de reiniciar el FD para cambiar parámetros de restore — el sidecar se lee en cada job y se descarta después (Phase 5ε, JobId 8090/8092).
7. Manifest firmado y verificación BLAKE3
Cada backup emite un manifest JSON que cataloga lo respaldado: lista de DBs, collections, conteos de documentos, oplog tip, topología del replica set al momento del backup. El manifest se hashea con BLAKE3 y se firma con Ed25519 usando una llave configurada por env var (PODHEITOR_MONGODB_SIGNING_KEY).
En el restore, el plugin verifica la firma antes de aplicar — protege contra tampering post-backup (ransomware que intenta reescribir backups antes de detonar). La llave vive fuera del FD; los artefactos se pueden auditar independientemente vía verify-artifacts.sh.
8. Empaquetado y exporter Prometheus
v1.0 entrega RPM (EL9) + DEB (Debian 12 / Ubuntu 22.04), firmados (RPM in-archive + DEB detached GPG), validados en smoke matrix de 5 distros vía podman (5/5 PASS). El exporter Prometheus expone en :9105/metrics:
podheitor_mongodb_exporter_scrapes_totalpodheitor_mongodb_backup_duration_seconds{resource}podheitor_mongodb_oplog_lag_seconds{resource}podheitor_mongodb_last_success_timestamp{resource}
El exporter corre como bacula:bacula bajo unit systemd hardened (ProtectSystem=strict, NoNewPrivileges=yes, PrivateTmp=yes), leyendo solo los stats sidecars en el working dir.
9. FileSet de ejemplo (replica set)
FileSet {
Name = "MongoDB-RS-Dump"
Include {
Options { Signature = SHA256 }
Plugin = "podheitor-mongodb: mode=dump uri=mongodb://backup_user@rs0-1,rs0-2,rs0-3/?replicaSet=rs0&readPreference=secondaryPreferred&authSource=admin database=* parallel_dbs=4 verify=true"
}
}
Job {
Name = "MongoDB-Backup"
Type = Backup
Client = mongo-fd
FileSet = "MongoDB-RS-Dump"
Storage = File1
Pool = Default
Schedule = "WeeklyCycle"
}
10. Versiones soportadas (v1.0)
- MongoDB Community 4.4, 5.0, 6.0, 7.0, 8.0
- Percona Server for MongoDB 6.0, 7.0, 8.0 (modo
hot_backupen Phase 4 — code-stub) - MongoDB Enterprise 7.0+ (
$backupCursor) — Phase 9 / v1.5 - Bacula Community 15.0.3+ y Bacularis
11. Postura de licencia
El plugin se distribuye bajo licencia PROPRIETARY single-license. El backend nunca toca el ABI de Bacula.
¿Listo para evaluar?
Trial gratuito de 30 días para clusters MongoDB calificados (Community, Percona, Enterprise). Garantizamos al menos 50% de descuento vs Bacula Enterprise, Veeam o Commvault, con más funcionalidades incluidas — incluyendo replay PIT y manifest firmado que ningún competidor entrega out-of-the-box.
Heitor Faria — Fundador, PodHeitor International
✉ [email protected]
☎ +1 (789) 726-1749 · +55 (61) 98268-4220 (WhatsApp)
🔗 Página del plugin PodHeitor MongoDB
Disponível em:
Português (Portugués, Brasil)
English (Inglés)
Español