Whitepaper técnico — PodHeitor Proxmox para Bacula

Arquitetura interna, modos de operação, replicação DR Veeam-style, instant recovery via NBD, conversão cross-hypervisor (vSphere/Hyper-V → PVE), e modelo de segurança com fingerprint pinning TLS.

Documento técnico complementar à página do plugin PodHeitor Proxmox.

1. Problema: Bacula stock não enxerga Proxmox VE

Bacula Community em sua forma stock não tem awareness algum de hipervisores. Backup de VMs Proxmox sem plugin é tipicamente uma das três opções, todas ruins:

  • Backup do filesystem do host — captura arquivos .qcow2/.raw em estado inconsistente, sem quiesce, sem CBT. Restauração frequentemente boota em corrupção.
  • vzdump + dump em diretório, depois Bacula — duplica o storage (1× dataset PVE + 1× dump vzdump), e cada incremental retransmite o dump inteiro porque vzdump não emite delta nativamente.
  • Bacula Enterprise PVE plugin — existe, mas custa preço enterprise e não suporta replicação DR cross-site nem conversão cross-hypervisor.

O PodHeitor Proxmox Plugin endereça as três lacunas em um único binário: backup VM-aware com CBT, replicação DR Veeam-style entre nós PVE, e restore cross-hypervisor (vSphere/Hyper-V → PVE).

2. Modelo arquitetural

O plugin segue o padrão PodHeitor de cdylib + backend standalone, comunicando-se via PTCOMM (length-tagged framing em stdin/stdout). A motivação é tripla:

  1. Crash isolation. Um panic no engine de NBD ou QMP mata o backend, não o bacula-fd. O cdylib observa EOF na pipe, reporta o job como falhado, e o FD continua atendendo outros jobs.
  2. Liberdade de paralelismo. O backend pode abrir conexões PVE REST + NBD + QMP em paralelo sem violar o contrato Bacula de “uma thread por bpContext“.
  3. License firewall. Desde v2.0.0, nenhum source AGPLv3 do Bacula é vinculado estaticamente.

2.1 Topologia de processos

bacula-fd  →  podheitor-proxmox-fd.so (cdylib ~600 LoC)  →  podheitor-proxmox-backend (Rust ~4500 LoC)
                                                                ├─ PVE REST API (HTTPS/TLS pinned)
                                                                ├─ NBD Client (disk I/O)
                                                                └─ QMP Client (snapshot + dirty bitmap)

O backend hospeda cinco engines: BackupEngine, RestoreEngine, ReplicationSender, ReplicationReceiver e InstantRecoveryEngine. Selecionado pelo parâmetro mode= do plugin string.

3. Modos de operação

Mode Função Engine
backup Backup VM-aware (Full/Inc/Diff) com CBT via QEMU dirty bitmaps BackupEngine
seed Sync inicial completa, auto-provisiona VM réplica no DR ReplicationSender
incremental (DR) Replicação CBT incremental — dirty-bitmap deltas only ReplicationSender
receiver Daemon receiver no DR target — escuta TCP dr_port (9190) ReplicationReceiver
failover-exec Boot da réplica no DR (planned failover) ReplicationSender
failback-pre Retorno da réplica para standby ReplicationSender

4. CBT via QEMU dirty bitmaps

Em vez de re-enviar 100 GB toda noite, o plugin instala um dirty bitmap persistente no QEMU do PVE node via QMP block-dirty-bitmap-add. Cada incremental:

  1. Tira snapshot consistente (com quiesce=yes via QEMU Guest Agent quando disponível).
  2. Lê apenas blocos marcados dirty desde o último backup, via NBD BLOCK_STATUS.
  3. Stream-a esses blocos pela PTCOMM com offset preservado.
  4. Reseta o bitmap após confirmar que o backup terminou OK.

VM de 100 GB com 2 GB modificados → apenas 2 GB transferidos. Sem CBT (Bacula stock + filesystem), seriam 100 GB cada noite.

5. Replicação DR Veeam-style (v1.1.0)

O plugin implementa um pipeline DR cross-node PVE-1 → PVE-2 com semântica próxima a Veeam Replication, mas dirigido inteiramente pelo Bacula Director (FileSet/Job).

5.1 Fases

  • Seed (mode=seed): sync inicial full. Auto-provisiona a VM réplica no DR target (cores, RAM, NICs, SCSI controllers, storage spec).
  • Incremental contínuo (mode=incremental): apenas deltas dirty-bitmap.
  • Restore-points: snapshots auto-rotacionados na réplica (default 7 pontos).
  • Verify (verify_sample_blocks=N): hash FNV-1a-64 de N blocos amostrais, comparado source ↔ DR. Mismatch = job fail (não silenciosamente OK).
  • Planned failover (mode=failover-exec): uma execução boot-a a réplica no DR.
  • Planned failback (mode=failback-pre): retorna réplica a standby.

5.2 Autenticação do canal DR

Método Parâmetro Quando usar
Token PSK (HMAC) dr_auth_token Default; setup rápido entre dois sites controlados
TLS Mutual Auth dr_auth_cert + dr_auth_key Compliance / multi-tenant; rustls + PEM
Ambos todos os 3 Defense-in-depth

5.3 Daemon receiver standalone

O DR target não precisa rodar bacula-fd. O package instala o template systemd [email protected]; o receiver fica escutando em dr_port (default 9190) e aceita streams autenticados, escrevendo discos via NBD para o storage dr_storage do PVE local. Isso reduz superfície de ataque no DR e simplifica air-gap parcial.

6. Instant Recovery via NBD overlay

Recuperação tradicional de uma VM de 500 GB pode levar horas para escrever bytes em disco antes que o serviço volte. O InstantRecoveryEngine contorna isso:

  1. Boot-a a VM no PVE apontando para um disco virtual servido por NBD pelo backend, lendo direto do stream Bacula restore.
  2. Overlay writes (ir_overlay_storage) capturam mudanças do guest em storage local rápido.
  3. Em background, com ir_auto_migrate=yes, o disco é migrado para storage final (ir_target_storage) sem downtime.

RTO típico cai de horas para minutos. Parâmetros chave: ir_nbd_bind, ir_nbd_port, ir_overlay_storage, ir_target_storage, ir_timeout (default 3600s).

7. Conversão cross-hypervisor

O plugin lê backups produzidos pelos plugins-irmãos PodHeitor vSphere e PodHeitor Hyper-V e restaura diretamente em PVE — sem reconversão manual:

Origem Formato disco origem Conversão
VMware vSphere VMDK VMDK → qcow2/raw via biblioteca interna (não shell-out)
Hyper-V VHDX VHDX → qcow2/raw via biblioteca interna

Validado em laboratório: Job 805 (Hyper-V → PVE) e Job 865 (VMware → PVE) restauraram VMs com boot bem-sucedido no PVE de destino.

8. Modelo de segurança

8.1 TLS Fingerprint Pinning (PVE API)

Bacula stock tipicamente confia na trust store do sistema; PVE certs são autossignados por padrão. O plugin enforça SHA-256 fingerprint pinning explícito via pve_fingerprint=AA:BB:CC:..., com pve_insecure=no como default. Para obter o fingerprint:

openssl s_client -connect pve-host:8006 </dev/null 2>/dev/null 
  | openssl x509 -noout -fingerprint -sha256 
  | sed 's/SHA256 Fingerprint=//'

Mismatch (cert rotacionado, MITM, host trocado) → job aborta com ERROR: TLS fingerprint mismatch. Expected AA:BB:... got CC:DD:....

8.2 Credenciais

  • Senhas e tokens passados via FileSet plugin string (não armazenados em disco pelo plugin).
  • bacula-dir.conf deve ter perms 600, owner bacula.
  • Para produção: integrar com vault externo (HashiCorp Vault, AWS Secrets Manager) e gerar plugin string via templating do Director.

9. Validação em laboratório

Métrica Resultado
Bacula Jobs executados (sequencial) 1.290+ JobIDs
Backup/Restore Full/Inc/Diff (same-host + cross-host) OK
Cross-hypervisor Hyper-V → PVE (Job 805) OK
Cross-hypervisor VMware → PVE (Job 865) OK
Replication seed 100 GB 107 GB em 93,7 min, 19 MB/s sustained
Replication incrementais 15 / 15 back-to-back, média 14,5 s
Integrity verify 150 sample blocks, 0 mismatches
mTLS DR channel Cert v3 com IP SAN — handshake + integrity OK
Planned failover + failback One-command, exit 0
Bacula-driven JobId 3448 Termination=OK

Ambiente: Director Oracle Linux 9.6 + Bacula 15.0.3; PVE Site A Debian 12 + PVE 8.4.18; PVE Site B Debian 13 + PVE 9.x.

10. Anti-patterns documentados

  • Não desabilite pve_fingerprint em produção. Setar pve_insecure=yes aceita qualquer cert apresentado pelo PVE host — incluindo certs MITM. Use somente em lab.
  • Não rode quiesce=yes sem QEMU Guest Agent instalado e ativo na VM. Sem agent, o plugin cai para crash-consistent automaticamente, mas o operador deve saber que isso aconteceu (verifique log do job).
  • Não rode receiver e sender no mesmo host PVE. Eles abrem o mesmo dr_port e o segundo binda em fail.
  • Não confunda backup_type=incremental (Bacula level) com mode=incremental (DR mode). O primeiro é nível de backup do FileSet; o segundo é o modo do engine de replicação. São ortogonais.

11. License posture

Desde v2.0.0, o plugin distribui sob LicenseRef-PodHeitor-Proprietary. Nenhum source AGPLv3 do Bacula é vinculado estaticamente ao .so. O cdylib é construído sobre o crate puro PodHeitor plugin-proxmox no workspace PodHeitor Rust cdylib, com bindings extern "C" independentes via crate bacula-fd-abi.

Pronto para avaliar?

Trial gratuito de 30 dias para frotas Proxmox VE em produção. Garantimos no mínimo 50% de desconto vs Bacula Enterprise, Veeam ou Commvault, com mais funcionalidades inclusas (replicação DR, instant recovery, conversão cross-hypervisor).

Heitor Faria — Fundador, PodHeitor International
[email protected]
☎ +1 (789) 726-1749 · +55 (61) 98268-4220 (WhatsApp)
🔗 Página do plugin PodHeitor Proxmox

Disponível em: pt-brPortuguêsenEnglish (Inglês)esEspañol (Espanhol)

Deixe um comentário