Mi clúster de Proxmox de 3 nodos, tal como funciona hoy

Bitácora en vivo · última actualización 2026-10-17

Tres máquinas, un clúster, sin almacenamiento compartido, sin Ceph. Todo lo de abajo está copiado del clúster en marcha. Copia lo que necesites. Cuando algo cambia agrego una línea con fecha al log y actualizo la salida.

Log

Las máquinas

NodoHardwarePVEPools
reaperMinisforum MS-A2, Ryzen 9 9955HX, 32G, BIOS 1.029.2.21, kernel 7.0.14-24rpool 472G, data-zfs 952G
sevroMinisforum MS-A2, Ryzen 9 9955HX, 32G, BIOS 1.029.2.21, kernel 7.0.14-24rpool 472G, data-zfs 952G, nas-pool 952G
skynetGigabyte B650 AORUS ELITE AX V2, Ryzen 9 7950X3D, 96G, RTX 5070 Ti9.2.20, kernel 7.0.14-19rpool 1.81T, tank 476G

skynet es la rara. Es una placa de escritorio con la GPU pasada a mi VM de escritorio de cada día, así que se actualiza al final.

Quorum

$ pvecm status
Cluster information
-------------------
Name:             howlers
Config Version:   9
Transport:        knet
Secure auth:      on

Votequorum information
----------------------
Expected votes:   3
Highest expected: 3
Total votes:      3
Quorum:           2
Flags:            Quorate

Membership information
----------------------
    Nodeid      Votes Name
0x00000001          1 192.168.1.14
0x00000002          1 192.168.1.13 (local)
0x00000003          1 192.168.1.166

Tres votos, se necesitan dos. Cualquiera de las máquinas puede caerse y las otras dos siguen. Con dos nodos necesitas un QDevice; un tercer nodo real me resolvió eso.

corosync.conf

$ cat /etc/pve/corosync.conf
nodelist {
  node {
    name: reaper
    nodeid: 1
    quorum_votes: 1
    ring0_addr: 192.168.1.14
  }
  node {
    name: sevro
    nodeid: 2
    quorum_votes: 1
    ring0_addr: 192.168.1.13
  }
  node {
    name: skynet
    nodeid: 3
    quorum_votes: 1
    ring0_addr: 192.168.1.166
  }
}

quorum {
  provider: corosync_votequorum
}

totem {
  cluster_name: howlers
  config_version: 9
  interface {
    knet_link_priority: 10
    linknumber: 0
  }
  ip_version: ipv4-6
  link_mode: passive
  secauth: on
  token_coefficient: 125
  version: 2
}

Un enlace en la LAN de la casa. La documentación quiere un segundo enlace de corosync, separado [1]. Todavía no tengo uno. Eso es lo que sigue.

Red: 10G con respaldo de 2.5G

$ cat /etc/network/interfaces
auto bond0
iface bond0 inet manual
    bond-slaves nic2 nic0
    bond-mode active-backup
    bond-primary nic2
    bond-miimon 100

auto vmbr0
iface vmbr0 inet static
    address 192.168.1.13/24
    gateway 192.168.1.1
    bridge-ports bond0
    bridge-vlan-aware yes
    bridge-vids 2-4094
    bridge-stp off
    bridge-fd 0
$ grep -E "Mode|Active|Interface|Speed" /proc/net/bonding/bond0
Bonding Mode: fault-tolerance (active-backup)
Currently Active Slave: nic2
Slave Interface: nic2
Speed: 10000 Mbps
Slave Interface: nic0
Speed: 2500 Mbps

nic2 es el DAC de 10G, nic0 es el cobre de 2.5G. Desconecta el DAC y el tráfico pasa a nic0. Active-backup no necesita nada del switch [2]. El bridge es VLAN-aware, así que un guest solo recibe tag=101 en su NIC.

Aplícalo con red de seguridad. El rollback corre como un timer de systemd, así que se dispara igual si tu sesión ssh se cae:

cp /etc/network/interfaces /root/interfaces.bak
systemd-run --on-active=2min --unit=net-rollback sh -c 'cp /root/interfaces.bak /etc/network/interfaces && ifreload -a'
ifreload -a
# still in? cancel the rollback
systemctl stop net-rollback.timer

storage.cfg

$ cat /etc/pve/storage.cfg
dir: local
    path /var/lib/vz
    content vztmpl,import,iso,backup

zfspool: local-zfs
    pool rpool/data
    content rootdir,images
    sparse 1

zfspool: data-zfs
    pool data-zfs
    content images,rootdir
    mountpoint /data-zfs
    nodes sevro,reaper
    sparse 1

cifs: nas-iso
    path /mnt/pve/nas-iso
    server 192.168.1.20
    share share
    content iso
    subdir /lab/images/iso
    username neal

La replicación necesita almacenamiento ZFS con el mismo storage ID en ambos nodos [4]. Por eso ambas minis tienen data-zfs. Las ISOs viven en el NAS para que todos los nodos vean la misma lista.

Replicación en vez de almacenamiento compartido

$ pvesr status
JobID      Enabled    Target         LastSync             NextSync             Duration  FailCount State
100-0      Yes        local/reaper   2026-10-17_14:50:00  2026-10-17_14:55:00  1.647333          0 OK
103-0      Yes        local/reaper   2026-10-17_14:50:02  2026-10-17_14:55:00  1.470997          0 OK
106-0      Yes        local/reaper   2026-10-17_14:50:03  2026-10-17_14:55:00  1.581741          0 OK
108-0      Yes        local/reaper   2026-10-17_14:50:05  2026-10-17_14:55:00  1.914492          0 OK
109-0      Yes        local/reaper   2026-10-17_14:50:07  2026-10-17_14:55:00  1.929232          0 OK

Cada 5 minutos cada guest toma una snapshot y envía la diferencia a la otra mini. Tarda menos de 2 segundos. Crea una:

pvesr create-local-job 109-0 reaper --schedule "*/5"

Mover un guest replicado es rápido porque casi todo el disco ya está ahí:

qm migrate 105 reaper --online --with-local-disks
pct migrate 109 reaper --restart

HA está apagado. No hay dispositivo de fencing, así que cuando un nodo muere arranco la réplica en el otro a mano. En el peor caso pierdo 5 minutos.

Actualizar un nodo

# empty the node first
qm migrate <id> <other-node> --online --with-local-disks
pct migrate <id> <other-node> --restart

apt update && apt full-upgrade -y
reboot

pveversion

Un nodo a la vez. Los otros dos siguen arriba, el quorum se mantiene.

Qué cambiaría

Fuentes

  1. Proxmox VE: Cluster Manager, corosync redundancy
  2. Linux kernel: bonding driver, active-backup mode
  3. Proxmox forum: MS-A2 BIOS 1.03 and passthrough
  4. Proxmox VE: Storage Replication