Cluster, quorum, alta disponibilidad y migración
Cluster, quorum, alta disponibilidad y migración
Hasta aquí has operado nodos sueltos. En el capítulo 7 montaste storage, en el capítulo 9 armaste la red del host y en el capítulo 10 cerraste el acceso. Todo eso vive en una máquina: si esa máquina se apaga, se apaga tu infraestructura completa.
Un cluster de Proxmox VE resuelve dos problemas que suelen confundirse. El primero es operativo: una sola interfaz, una base de datos de configuración replicada, migración de guests entre nodos, backups y permisos centralizados. El segundo es de disponibilidad: que cuando un nodo muera de verdad, sus VMs arranquen solas en otro sitio. Lo primero lo da pvecm casi gratis. Lo segundo exige entender quorum, fencing y watchdog, y aceptar que el mecanismo que te salva es el mismo que reinicia un servidor sano si te equivocas con la red.
Al terminar tendrás un cluster de tres nodos con corosync en red dedicada y un enlace de respaldo, sabrás leer pvecm status línea a línea, tendrás recursos HA con reglas de afinidad, entenderás por qué el failover tarda unos dos minutos y no menos, y podrás migrar VMs en caliente con o sin storage compartido. La referencia es Proxmox VE 9.2 sobre Debian 13 Trixie, con corosync 3.1.10-pve2.
Requisitos previos que no se negocian
La documentación oficial es explícita en cinco puntos, y todos cuestan un cluster roto si los saltas: todos los nodos deben poder conectarse entre sí por UDP 5405-5412 para que corosync funcione; la fecha y la hora deben estar sincronizadas (en Debian 13 el daemon por defecto es chrony); hace falta un túnel SSH en TCP 22 entre nodos; si te interesa la alta disponibilidad necesitas al menos tres nodos para un quorum fiable; y la red debe ser fiable, con latencias por debajo de 5 ms entre todos los nodos.
A eso se suma la recomendación de dedicar una NIC física al tráfico de cluster, con un matiz que casi todo el mundo entiende al revés: corosync no necesita ancho de banda, necesita latencia baja y consistente. Una NIC de 1 Gbit dedicada es mejor que compartir una de 25 Gbit con el storage. Cuando un backup satura el enlace, corosync empieza a perder tokens y el cluster parpadea.
| Servicio | Puerto | Protocolo |
|---|---|---|
| corosync (knet) | 5405-5412 | UDP |
| SSH: túnel de migración, shell, replicación | 22 | TCP |
Web UI y API pveproxy | 8006 | TCP |
pvedaemon (local) | 85 | TCP |
| SPICE proxy | 3128 | TCP |
QDevice corosync-qnetd | 5403 | TCP |
| Migración en vivo (rango) | 60000-60050 | TCP |
Si el firewall de Proxmox está habilitado, las reglas ACCEPT para corosync se generan automáticamente; no dependas de eso para el firewall del switch o del proveedor de nube, que sí tienes que abrir a mano (capítulo 10). Dos reglas duras antes de tocar nada. Uno. El hostname y la IP de cada nodo deben ser definitivos antes de crear o unirse: cambiarlos después rompe el cluster y no hay procedimiento limpio de vuelta. Dos. Cada nodo debe resolver a los demás; /etc/hosts es lo que se usa en la práctica y lo que recolecta pvereport, y es la forma robusta de no depender de un DNS externo que también puede caerse.
# En LOS TRES nodos, antes de crear nada
timedatectl set-ntp true
chronyc tracking
cat >> /etc/hosts <<'EOF'
10.10.10.1 pve1.lab.local pve1
10.10.10.2 pve2.lab.local pve2
10.10.10.3 pve3.lab.local pve3
EOF
ping -c3 10.10.10.2 && ping -c3 10.10.10.3
pvecm create y pvecm add
El cluster se crea en un solo nodo con pvecm create <clustername> [OPTIONS]:
| Opción | Tipo | Default | Para qué sirve |
|---|---|---|---|
--link[0..7] | [address=]<IP>[,priority=<int>] | IP local como link0 | Dirección y prioridad del enlace de corosync |
--nodeid | entero 1-N | — | Node ID de este nodo |
--votes | entero 1-N | 1 | Votos de quorum de este nodo |
--token-coefficient | entero 0-N | 125 | Coeficiente del token timeout de corosync |
pvecm create PRODUCCION # usa la IP de gestión como link0
pvecm create PRODUCCION --link0 10.10.10.1 # red dedicada de corosync
pvecm create PRODUCCION --link0 10.10.10.1,priority=15 --link1 10.20.20.1,priority=20
Ese token-coefficient de 125 ms es novedad de PVE 9.2: los clusters nuevos se crean con ese valor para reducir el tiempo de recuperación tras la caída de un nodo. El default de corosync upstream es token = 1000 ms con token_coefficient = 650 ms, y el timeout real se calcula como token + (nodos - 2) * token_coefficient. Con 8 nodos eso son 1000 + 6 * 125 = 1750 ms en PVE 9.2 frente a 1000 + 6 * 650 = 4900 ms con los valores upstream: casi tres veces menos espera antes de que el cluster reaccione.
Los demás nodos se unen con pvecm add <hostname> [OPTIONS]:
| Opción | Tipo | Para qué sirve |
|---|---|---|
--fingerprint | SHA-256 en formato XX:XX:... | Fingerprint del certificado del nodo destino |
--force | boolean | No fallar si el nodo ya existe |
--link[0..7] | [address=]<IP>[,priority=<int>] | Dirección local de este nodo en el enlace N |
--nodeid | entero 1-N | Node ID a asignar |
--use_ssh | boolean | Forzar el join legacy por SSH aunque el peer soporte join por API |
--votes | entero 0-N | Votos del nodo; 0 = nodo sin voto |
pvecm add 10.10.10.1 --link0 10.10.10.2 --link1 192.168.1.12 # en pve2
pvecm add 10.10.10.1 --link0 10.10.10.3 --link1 192.168.1.13 # en pve3
pvecm status && pvecm nodes && corosync-cfgtool -s
pvecm addnode es la contraparte que se ejecuta en el cluster y que usa internamente el join por API, con --apiversion y --new_node_ip; en operación manual no la necesitas.
Lo que pierdes al unirte
Este es el aviso más caro del capítulo, y es literal: «All existing configuration in /etc/pve is overwritten when joining a cluster. In particular, a joining node cannot hold any guests, since guest IDs could otherwise conflict.»
Se pierde todo lo que vive en pmxcfs: las definiciones de storage de /etc/pve/storage.cfg, los usuarios y ACL de /etc/pve/user.cfg, el firewall, los jobs de backup, las réplicas y las opciones de datacenter. No se pierde /etc/network/interfaces, ni /etc/hosts, ni los paquetes instalados, ni los datos de los storages locales: los volúmenes siguen en disco, lo que desaparece es la definición del storage y los .conf de los guests. Si el nodo ya tiene VMs, el procedimiento correcto es respaldar, unir y restaurar con VMIDs libres; los modos de vzdump están en el capítulo 13.
vzdump 100 101 102 --storage backup-nfs --mode stop --compress zstd # ANTES de unir
# ...pvecm add...
qmrestore /mnt/backup/dump/vzdump-qemu-100-*.vma.zst 250 # VMID que no colisione
El papel de SSH y pvecm updatecerts
Proxmox usa túneles SSH para tres cosas: proxear sesiones de consola y shell de nodos y guests, migrar memoria y storage local en modo secure, y ejecutar la replicación de storage. Para eso modifica el sistema de tres formas. Uno. El cliente SSH de root prefiere AES sobre ChaCha20, porque con AES-NI el cifrado sale casi gratis y la migración va más rápida. Dos. /root/.ssh/authorized_keys es un symlink a /etc/pve/priv/authorized_keys, que vive en pmxcfs y está replicado en todos los nodos; cuando borras un nodo su clave sigue ahí hasta que la quitas a mano. Tres. sshd permite login de root con contraseña.
Hay una recomendación oficial que ahorra horas: protege ~/.bashrc para que no imprima nada en sesiones no interactivas, porque cualquier mensaje de bienvenida rompe las migraciones (el túnel espera un protocolo limpio y recibe texto).
case $- in
*i*) ;;
*) return;;
esac
Cuando los certificados o las claves se desincronizan el síntoma es un nodo gris en la GUI aunque responda a ping, o un pvecm add que falla con Host key verification failed:
pvecm updatecerts # regenera ficheros y directorios necesarios
pvecm updatecerts --force # fuerza un certificado SSL nuevo
pvecm updatecerts --silent # ignora errores, útil sin quorum
pvecm updatecerts --unmerge-known-hosts # deshace la fusión de known_hosts
corosync.conf: dos copias y config_version
La configuración de corosync existe en dos ficheros distintos, y confundirlos es la causa clásica de “he cambiado la config y no pasa nada”:
| Ruta | Qué es |
|---|---|
/etc/pve/corosync.conf | El fichero maestro, dentro de pmxcfs, replicado a todos los nodos. Es el que se edita |
/etc/corosync/corosync.conf | La copia local que corosync lee al arrancar. La genera PVE a partir de la anterior |
/etc/corosync/authkey | Clave compartida de cifrado del cluster. Se genera con pvecm keygen <fichero> |
/var/lib/corosync/ | Estado en runtime: ringid y demás. Se borra al separar un nodo |
Editar directamente /etc/corosync/corosync.conf no sirve: se sobreescribe y no se propaga. Y hay una consecuencia circular incómoda: sin quorum, /etc/pve es de solo lectura, así que no puedes arreglar corosync.conf desde ahí. Más abajo están las dos salidas de ese callejón. Así es el fichero completo tal como lo publica la documentación para tres nodos con dos anillos:
logging {
debug: off
to_syslog: yes
}
nodelist {
node {
name: due
nodeid: 2
quorum_votes: 1
ring0_addr: 10.10.10.2
ring1_addr: 10.20.20.2
}
node {
name: tre
nodeid: 3
quorum_votes: 1
ring0_addr: 10.10.10.3
ring1_addr: 10.20.20.3
}
node {
name: uno
nodeid: 1
quorum_votes: 1
ring0_addr: 10.10.10.1
ring1_addr: 10.20.20.1
}
}
quorum {
provider: corosync_votequorum
}
totem {
cluster_name: testcluster
config_version: 4
ip_version: ipv4-6
secauth: on
version: 2
interface {
linknumber: 0
}
interface {
linknumber: 1
}
}
Cuatro claves para leerlo. ringN_addr dentro de nodelist es la dirección de ese nodo en el enlace N. El bloque interface { linknumber: N } dentro de totem declara el enlace a nivel de cluster, y es donde van propiedades como knet_link_priority. secauth: on activa cifrado y autenticación con /etc/corosync/authkey. Y provider: corosync_votequorum es el módulo que implementa el quorum. El procedimiento oficial de edición no es opcional:
cp /etc/pve/corosync.conf /etc/pve/corosync.conf.new # 1. copia de trabajo
nano /etc/pve/corosync.conf.new # 2. editar y SUBIR config_version
cp /etc/pve/corosync.conf /etc/pve/corosync.conf.bak # 3. respaldo del actual
mv /etc/pve/corosync.conf.new /etc/pve/corosync.conf # 4. activar
systemctl status corosync # 5. verificar
journalctl -b -u corosync
systemctl restart corosync # 6. solo si hace falta
Advertencia: el aviso literal es «Always increment the config_version number after configuration changes; omitting this can lead to problems». Si te olvidas, los nodos ignoran el cambio o quedan desincronizados, y el diagnóstico es infernal porque el fichero parece correcto en todas partes. El otro error que parte clusters es cambiar el ring0_addr de todos los nodos a una red nueva sin haber verificado antes la conectividad en esa red: haz ping desde cada nodo a cada nodo con las IP nuevas antes de tocar el fichero.
Enlaces redundantes, prioridades y corosync sobre bonds
Desde PVE 6.0 el transporte es Kronosnet (knet) sobre UDP unicast; el multicast quedó atrás y los transportes legacy udp y udpu desactivan cifrado y redundancia, así que no se recomiendan. El máximo son 8 enlaces, de link0 a link7, y cada enlace redundante debería estar en una red físicamente separada: dos VLAN sobre el mismo cable no son redundancia. La prioridad más alta gana; en modo pasivo se usa el enlace activo de mayor prioridad y, si varios comparten prioridad, el de menor link ID. Aviso oficial: «Link priorities cannot be mixed, meaning that links with different priorities will not be able to communicate», o sea que todos los nodos deben declarar la misma prioridad para el mismo enlace.
Añadir un enlace a un cluster existente es manual: añades ring1_addr a cada nodo del nodelist, añades el bloque interface correspondiente dentro de totem y subes config_version. Con prioridades explícitas los dos bloques quedan así:
interface {
linknumber: 0
knet_link_priority: 15
}
interface {
linknumber: 1
knet_link_priority: 20
}
Sobre bonds la postura oficial es clara y contraintuitiva: prefiere varios enlaces de corosync antes que un bond, porque knet gestiona el failover a nivel de aplicación y sabe cuándo un camino dejó de entregar paquetes.
| Modo de bond | Recomendación para corosync |
|---|---|
balance-rr, balance-xor, balance-tlb, balance-alb | Evitar. Riesgo de conectividad asimétrica si una interfaz falla en silencio: link up pero sin paquetes |
LACP 802.3ad | Aceptable con bond-lacp-rate fast en el nodo y en el switch: baja el failover de 90 s a 3 s |
active-backup | Evita la asimetría, pero puede no hacer failover de forma fiable |
Los modos de bonding y su sintaxis en /etc/network/interfaces están en el capítulo 9. Para diagnóstico, en orden de utilidad:
corosync-cfgtool -s # estado de los links: LINK ID, status, addr
corosync-cfgtool -n # vista de nodos
corosync-quorumtool -s # estado detallado de quorum
corosync-quorumtool -l # lista de miembros
corosync-cmapctl | grep members
journalctl -b -u corosync -u pve-cluster -f
| Síntoma en el log | Causa habitual |
|---|---|
Retransmit List: ... constante | Latencia o pérdida en la red de corosync, o corosync compartiendo NIC con storage y migración |
link: host: X link: 0 is down | NIC, switch o VLAN del anillo caídos |
Sync members[N] cambiando sin parar | Red inestable o token timeout demasiado bajo |
[TOTEM ] A processor failed, forming new configuration | Pérdida de un nodo o de conectividad |
pmxcfs[...] [status] notice: node lost quorum | Pérdida de quorum, /etc/pve pasa a solo lectura |
Quorum: la tabla de votos
Un quorum es el número mínimo de votos que hace falta para permitir una operación. Por defecto cada nodo aporta un voto y se necesita mayoría estricta: expected_votes / 2 + 1.
| Nodos | Votos esperados | Quorum necesario | Fallos tolerados |
|---|---|---|---|
| 2 | 2 | 2 | 0 |
| 2 + QDevice | 3 | 2 | 1 |
| 3 | 3 | 2 | 1 |
| 4 | 4 | 3 | 1 |
| 4 + QDevice | 5 | 3 | 2 |
| 5 | 5 | 3 | 2 |
Lee la tabla dos veces. Un cluster de cuatro nodos tolera exactamente lo mismo que uno de tres: un fallo. Has pagado un servidor entero y no has comprado disponibilidad, solo capacidad. De ahí la regla operativa: los clusters de número par son los que se benefician de un QDevice; los impares no. Y un cluster de dos nodos tolera cero fallos: si cae uno, el otro pierde quorum y /etc/pve pasa a solo lectura. Los guests que ya corrían siguen corriendo, pero no puedes arrancar, crear ni migrar nada. Dos nodos sin QDevice sirven para gestión unificada, no para disponibilidad.
QDevice: instalación exacta, ffsplit y cuándo no usarlo
El QDevice es un árbitro externo que no ejecuta corosync ni forma parte del cluster: solo aporta un voto de desempate. Puede ser un Debian cualquiera, una Raspberry Pi o una VM en otro sitio.
flowchart LR
subgraph Cluster["Cluster PVE de dos nodos"]
N1["pve1 con corosync-qdevice y 1 voto"]
N2["pve2 con corosync-qdevice y 1 voto"]
end
QN["Servidor externo con corosync-qnetd y 1 voto"]
N1 <-->|"corosync UDP 5405-5412"| N2
N1 -->|"TCP 5403"| QN
N2 -->|"TCP 5403"| QN
apt install corosync-qnetd # 1) en el servidor EXTERNO
systemctl status corosync-qnetd && ss -lntp | grep 5403
apt install corosync-qdevice # 2) en TODOS los nodos del cluster
pvecm qdevice setup 192.168.1.200 # 3) desde cualquier nodo, con todos online
pvecm status
Gotcha: pvecm qdevice setup copia la clave SSH del cluster al servidor externo, así que necesitas acceso SSH como root ahí durante el setup, por contraseña o por clave. Si tienes root deshabilitado, el comando falla a mitad y deja el estado sucio. La sinopsis es pvecm qdevice setup <address> [--force <boolean>] [--network <string>]: --network fija la red desde la que conectar al QDevice y --force evita abortar en operaciones potencialmente peligrosas. Para quitarlo, pvecm qdevice remove. Así se lee pvecm status con el QDevice activo:
Expected votes: 3
Total votes: 3
Quorum: 2
Flags: Quorate Qdevice
Nodeid Votes Qdevice Name
0x00000001 1 A,V,NMW 192.168.22.180 (local)
0x00000002 1 A,V,NMW 192.168.22.181
0x00000000 1 Qdevice
| Bandera | Significado |
|---|---|
A / NA | Alive / Not Alive: hay o no comunicación con el daemon corosync-qnetd |
V / NV | El QDevice votará o no votará por ese nodo |
MW / NMW | Master Wins / Not Master Wins. El default es NMW |
NR | QDevice no registrado |
Si ves NA, casi siempre es que el puerto TCP 5403 del servidor externo no es alcanzable; compruébalo con nc -zv <ip-qnetd> 5403 desde cada nodo. El algoritmo que usa PVE es ffsplit (fifty-fifty split): el QDevice concede su voto a la partición que contenga al menos la mitad de los nodos y, en caso de empate exacto, desempata eligiendo la partición con el node ID más bajo. Ese criterio se cambia con la opción tie_breaker en /etc/corosync/corosync.conf y requiere systemctl restart corosync-qdevice.service. Existe además el algoritmo lms (last man standing) en corosync upstream, pero PVE no lo configura por defecto y su documentación no describe cómo activarlo.
Por qué no usarlo en clusters impares, con el razonamiento de la propia documentación: el árbitro aportaría N-1 votos, permitiendo que fallaran todos los nodos menos uno. Suena bien hasta que miras las consecuencias. Si el QDevice cae, ya no toleras ningún fallo adicional de nodo. Recuperar en masa todos los servicios HA sobre un único superviviente lo sobrecargaría. Y Ceph, que verás en el capítulo 12, exige como mínimo (N-1)/2 nodos, con lo que la ganancia teórica no es utilizable. Regla operativa: quita el QDevice antes de añadir o eliminar nodos y vuelve a instalarlo cuando el cluster recupere un número par.
pvecm qdevice remove
pvecm add ... # o pvecm delnode ...
pvecm qdevice setup 192.168.1.200
Perder el quorum: qué pasa y cómo se sale
Sin quorum, pmxcfs monta /etc/pve en solo lectura: no puedes crear, arrancar ni migrar guests, no puedes editar configuración y HA no recupera nada. Lo que sí sigue funcionando son los guests que ya estaban en ejecución, salvo que HA decida hacer fencing del nodo.
flowchart TD
A["Se pierde el quorum"] --> B["pmxcfs monta /etc/pve en solo lectura"]
B --> C["No se puede crear arrancar ni migrar guests"]
B --> D["No se puede editar configuracion"]
B --> E["Los guests ya en ejecucion siguen corriendo"]
A --> F{"Hay HA activo en el nodo"}
F -->|"Si"| G["El LRM pierde el agent lock y deja de refrescar el watchdog"]
G --> H["Reset del nodo por watchdog en unos 70 segundos"]
F -->|"No"| I["Nada se reinicia solo"]
Hay dos salidas de emergencia y las dos son peligrosas. La primera es bajar los votos esperados con pvecm expected 1, que hace que el cluster vuelva a tener quorum con un solo nodo. No es persistente: vuelve al valor normal al reiniciar corosync. La advertencia oficial es literal: «Avoid cluster configuration changes (adding/removing nodes, storage, guests) when expected votes are set. Only use forced quorum for emergencies.» El riesgo concreto es split-brain: si los otros nodos vuelven mientras expected está forzado, puedes acabar con dos particiones escribiendo /etc/pve a la vez.
La segunda salida es para cuando corosync ni siquiera arranca y necesitas editar su configuración: montar pmxcfs en modo local.
systemctl stop pve-cluster
pmxcfs -l # monta /etc/pve local y escribible, sin cluster
# ...arreglar corosync.conf...
killall pmxcfs && systemctl start pve-cluster
Cold start y recuperación de un nodo muerto
Un cluster pierde quorum cuando todos los nodos están apagados, que es lo que pasa tras un corte de luz; por eso se recomienda UPS, especialmente con HA. Lo importante del arranque en frío es que no hay que hacer nada: «On node startup, the pve-guests service is started and waits for quorum. Once quorate, it starts all guests which have the onboot flag set.» El arranque de guests se retrasa hasta que hay quorum y los nodos rápidos esperan a los lentos. No fuerces pvecm expected 1 durante un cold start normal: solo tienes que esperar al último nodo.
Distinto es un nodo que no va a volver y cuyos guests necesitas ya, sin HA configurado. El procedimiento oficial es mover los ficheros de configuración a mano:
pvecm status # 1. comprobar quorum
pvecm expected 1 # 2. forzar solo si es imprescindible
mv /etc/pve/nodes/A/qemu-server/100.conf /etc/pve/nodes/B/qemu-server/100.conf
mv /etc/pve/nodes/A/lxc/200.conf /etc/pve/nodes/B/lxc/200.conf
qm start 100 && pct start 200 # 4. arrancar en el nodo vivo
Advertencia: si el nodo A vuelve a arrancar con el guest todavía “suyo” y el storage es compartido, tendrás el mismo disco montado dos veces y corrupción garantizada. Antes de mover un .conf, asegúrate físicamente de que A no vuelve. Con replicación ZFS aceptas además perder los cambios desde la última réplica; ese mecanismo está en el capítulo 8.
Sacar un nodo y por qué hay que reinstalarlo para reincorporarlo
El aviso literal va primero, porque es la parte que la gente se salta: «It is critical to power off the node before removal, and make sure that it will not power on again (in the existing cluster network) with its current configuration.»
# 1. Migrar o respaldar TODOS los guests: /etc/pve/nodes/node4/qemu-server y /lxc vacíos
ha-manager rules config && pvesr list # 2. sacarlo de reglas HA y jobs de replicación
pvecm qdevice remove # 3. si hay QDevice, quitarlo primero
node4# systemctl poweroff # 4. APAGAR y garantizar que no vuelve a esa red
node1# pvecm nodes && pvecm delnode node4 && pvecm status # 5. desde OTRO nodo
pvecm delnode no lo limpia todo. Quedan restos que hay que borrar a mano:
rm -rf /etc/pve/nodes/node4 # restos de configuración
ssh-keygen -f /etc/ssh/ssh_known_hosts -R node4 # fingerprints SSH obsoletos
nano /etc/pve/priv/authorized_keys # eliminar la línea de node4
pvecm qdevice setup 192.168.1.200 # reponer si el cluster vuelve a ser par
Los fingerprints obsoletos viven en dos sitios: /etc/pve/priv/known_hosts, que es cluster-wide, y el ~/.ssh/known_hosts de cada nodo. Y llegamos al punto que sorprende a todo el mundo: si quieres que ese mismo servidor vuelva al cluster, la documentación no admite matices: «Reinstall Proxmox VE on the server, then rejoin the node to the cluster.»
Las razones son concretas. Los certificados SSL del nodo, sus claves SSH y su identidad en pmxcfs quedaron invalidados en el cluster, pero el nodo antiguo conserva su copia local de la base de datos de pmxcfs del cluster viejo; si lo enciendes otra vez en la misma red con su configuración anterior, intentará participar con un nodeid ya borrado y puede corromper el cluster. Además, reutilizar el mismo nombre sin reinstalar produce colisiones en /etc/pve/nodes/<nombre> y en los fingerprints SSH: el join falla o deja el nodo en estado inconsistente. El reingreso limpio es: reinstalar PVE desde cero, fijar hostname e IP definitivos (pueden ser los mismos, ahora sí es seguro), verificar que /etc/pve/nodes/<nombre> ya no existe en el cluster, borrar el known_hosts obsoleto en todos los nodos, y pvecm add <IP-de-un-nodo> --link0 <IP-local>.
Existe un procedimiento para separar un nodo sin reinstalar, documentado pero no recomendado, y que exige antes mover las VMs, respaldar los datos locales y parar los jobs de replicación:
# En el nodo que se separa
systemctl stop pve-cluster && systemctl stop corosync
pmxcfs -l
rm /etc/pve/corosync.conf && rm -r /etc/corosync/*
killall pmxcfs && systemctl start pve-cluster
pvecm delnode oldnode # esto, en cualquier nodo del cluster que se queda
rm /var/lib/corosync/* # de nuevo en el nodo separado
El aviso que acompaña al procedimiento: «Ensure that all shared resources are cleanly separated! Otherwise you will run into conflicts and problems.»
Arquitectura HA: CRM, LRM y los locks de pmxcfs
El stack de alta disponibilidad son dos daemons y un multiplexor de watchdog, coordinados por los locks distribuidos que provee pmxcfs.
flowchart TB
subgraph PMXCFS["pmxcfs en /etc/pve con locks distribuidos"]
ML["manager lock: uno por cluster"]
AL1["agent lock del nodo1"]
AL2["agent lock del nodo2"]
AL3["agent lock del nodo3"]
end
CRM["pve-ha-crm master: decisiones cluster-wide y fencing"]
LRM1["pve-ha-lrm en nodo1"]
LRM2["pve-ha-lrm en nodo2"]
LRM3["pve-ha-lrm en nodo3"]
CRM -->|"escribe"| MS["/etc/pve/ha/manager_status"]
MS -->|"lee comandos"| LRM1
MS -->|"lee comandos"| LRM2
MS -->|"lee comandos"| LRM3
LRM1 -->|"escribe resultado"| LS1["/etc/pve/nodes/nodo1/lrm_status"]
LS1 --> CRM
CRM --- ML
LRM1 --- AL1
LRM2 --- AL2
LRM3 --- AL3
LRM1 -->|"refresca"| WD["watchdog-mux hacia /dev/watchdog"]
pve-ha-lrm, el Local Resource Manager, corre en cada nodo: lee el estado deseado de /etc/pve/ha/manager_status, ejecuta los comandos con hasta 4 workers concurrentes (ajustable con max_worker en datacenter.cfg) y escribe el resultado en /etc/pve/nodes/<nodo>/lrm_status. pve-ha-crm, el Cluster Resource Manager, corre en todos los nodos pero solo actúa en el que tiene el manager lock: toma las decisiones globales y ordena el fencing. La pieza que hace esto seguro son los locks de pmxcfs: un nodo se considera fenceable cuando otro puede adquirir su agent lock, y eso solo ocurre si el nodo dejó de renovarlo. No hay heurísticas: o el lock se puede tomar o no.
El lock tiene tres estados: active cuando el LRM lo tiene en exclusiva, wait for agent lock cuando está esperando a adquirirlo, y lost agent lock cuando se perdió el quorum y el lock quedó liberado.
Los requisitos de HA son cuatro y no son negociables: al menos tres nodos de cluster para tener quorum fiable, storage compartido para VMs y contenedores, redundancia de hardware en todas partes, y componentes de servidor fiables. El watchdog por hardware es opcional pero recomendado. Storage válido: Ceph RBD, NFS, iSCSI/LVM compartido, Fibre Channel/LVM, CIFS, GlusterFS y ZFS-over-iSCSI. La alternativa sin storage compartido es replicación ZFS más HA, asumiendo pérdida de datos hasta la última réplica. Antes de tocar un cluster real hay un simulador que ahorra sustos: apt install pve-ha-simulator, luego mkdir working y pve-ha-simulator working/.
Recursos HA: estados solicitados, estados internos y salir de error
Los recursos viven en /etc/pve/ha/resources.cfg:
vm: 501
state started
max_relocate 2
max_restart 1
failback 1
auto-rebalance 1
comment "Servidor web de produccion"
ha-manager add vm:100 # dar de alta en HA
ha-manager add ct:200 --state started --max_restart 2 --max_relocate 3
ha-manager set vm:100 --state stopped
ha-manager config [--type vm] # listar recursos
ha-manager status [--verbose] # estado global
ha-manager migrate vm:100 nodo2 # migración online vía CRM
ha-manager relocate vm:100 nodo2 # parar y arrancar en destino
ha-manager remove vm:100 # purge 1 por defecto
Defaults que conviene memorizar: max_restart 1, max_relocate 1, failback 1, auto-rebalance 1, y purge 1 al eliminar, lo que significa que el recurso también se borra de las reglas que lo referencian. Los estados solicitados son cuatro y cada uno tiene un uso distinto:
| Estado solicitado | Comportamiento |
|---|---|
started (default) | El CRM intenta arrancarlo y mantenerlo corriendo. Ante fallo del nodo, lo recupera en otro |
stopped | Se mantiene parado, pero HA lo sigue gestionando: se relocaliza si el nodo falla |
disabled | Parado y sin intentos de relocalización. Es además la forma de salir del estado error |
ignored | Queda fuera de la gestión de HA: ni CRM ni LRM lo tocan, útil para maniobras manuales sin desregistrarlo |
Los estados internos que verás en ha-manager status son otra cosa: son lo que el CRM cree que está pasando.
| Estado interno | Significado |
|---|---|
stopped | Parado confirmado; el LRM lo vuelve a parar si aparece corriendo |
request_stop | El CRM espera confirmación del LRM |
stopping | Parada pendiente, sin confirmación aún |
started / starting | Activo, o arranque pendiente |
fence | Esperando a que se complete el fencing del nodo |
recovery | Buscando nodo nuevo tras el fallo |
freeze | Congelado, sin cambios de estado: reinicio o actualización |
ignored | Fuera de HA |
migrate | Migración en vivo en curso |
error | Deshabilitado por errores del LRM, requiere intervención manual |
queued | Recién añadido, el CRM aún no lo procesó |
disabled | Parado y marcado como deshabilitado |
La política de fallo de arranque encadena los dos contadores: reintentar en el mismo nodo hasta max_restart y, si se agota, reubicar a otros nodos hasta max_relocate. Si todo falla, el servicio entra en error, y el contador solo se resetea tras un arranque exitoso. Salir de error es el procedimiento de tres pasos que hay que tener a mano de madrugada:
ha-manager set vm:100 --state disabled # limpia el flag de error
# ...arreglar la causa raíz...
ha-manager set vm:100 --state started
De HA groups a HA rules
Los HA Groups están deprecados desde Proxmox VE 9.0. El fichero histórico era /etc/pve/ha/groups.cfg, con nodes, restricted y nofailback. Si vienes de PVE 8 la migración es automática, pero con una condición importante: los grupos se convierten en reglas solo cuando todos los nodos del cluster han llegado a PVE 9. Durante una ventana de upgrade mixta no pasa nada, y eso es correcto, no un fallo. El modelo nuevo vive en /etc/pve/ha/rules.cfg y tiene dos tipos de regla. Node affinity, que sustituye a los groups:
ha-manager rules add node-affinity ha-rule-vm100 --resources vm:100 --nodes node1
ha-manager rules set node-affinity ha-rule-vm100 --strict 1
# Afinidad negativa: nunca en node3
ha-manager rules add node-affinity ha-rule-negative \
--affinity negative --resources ct:200,vm:300 --nodes node3
# Cascada de prioridades
ha-manager rules add node-affinity priority-cascade \
--resources vm:400,ct:500 --nodes "node1:2,node2:1,node3:1,node4"
| Opción | Valores | Default |
|---|---|---|
--resources | <tipo>:<nombre> separados por coma | requerido |
--nodes | <nodo>[:<prioridad>] separados por coma | — |
--affinity | positive o negative | positive |
--strict | boolean | 0: restricción blanda que permite failover fuera. Con 1 el recurso se para si no hay nodos válidos |
--comment / --disable | string / boolean | — |
Resource affinity no existía con groups y es la funcionalidad realmente nueva:
ha-manager rules add resource-affinity keep-together \
--affinity positive --resources vm:100,vm:200 # juntos en la misma máquina
ha-manager rules add resource-affinity keep-separate \
--affinity negative --resources vm:200,ct:300 # nunca en el mismo nodo
Tres detalles. Uno. Requiere al menos dos recursos. Dos. Las reglas positivas son estrictas por defecto. Tres. Varias reglas positivas que compartan recursos se fusionan en una sola, lo que a veces produce agrupaciones mayores de las esperadas. El sistema valida conflictos por ti: un recurso solo puede estar en una node-affinity rule; una node-affinity negativa no puede listar todos los nodos ni usar prioridades; una resource-affinity negativa exige que el número de recursos no supere el de nodos; y reglas positivas y negativas no pueden solaparse sobre el mismo par de recursos.
ha-manager rules list
ha-manager rules config --type node-affinity # o --resource vm:100
ha-manager rules set node-affinity <regla> --strict 0
ha-manager rules remove <regla>
Fencing por watchdog: los tiempos reales
Aquí está el mecanismo que hace HA seguro y, a la vez, el que reinicia servidores. La idea: ha-manager resetea periódicamente un temporizador watchdog; si por un fallo de hardware o de programa el nodo deja de resetearlo, el temporizador expira y provoca un reset completo del servidor. Eso es self-fencing: el nodo se suicida para garantizar que no sigue tocando el storage compartido mientras otro arranca sus VMs. Los números no son estimaciones, están en el código de pve-ha-manager:
| Constante | Valor | Dónde |
|---|---|---|
WATCHDOG_DEV | /dev/watchdog | watchdog-mux.c |
WD_SOCK_PATH | /run/watchdog-mux.sock | watchdog-mux.c |
CLIENT_WATCHDOG_TIMEOUT | 60 s, con aviso a los 50 s | watchdog-mux.c |
watchdog_timeout | 10 s en el dispositivo del kernel | watchdog-mux.c |
max_time del ciclo del LRM | 10 s | LRM.pm |
Abandono en lost_agent_lock | 90 s | LRM.pm |
fence_delay | 60 s | NodeStatus.pm |
Eliminación de un nodo en estado gone | 3600 s | NodeStatus.pm |
Cómo encajan: el dispositivo watchdog del kernel se programa con 10 segundos y watchdog-mux lo refresca continuamente; el LRM, que es su cliente, debe reportarse dentro de 60 segundos y a los 50 se emite un aviso; si no se reporta, watchdog-mux deja de refrescar /dev/watchdog y el servidor se resetea unos 10 s después. En paralelo el CRM espera fence_delay = 60 s antes de considerar offline al nodo. De ahí sale la cifra oficial: «error detection and failover times of about 2 minutes», lo que acota la disponibilidad alcanzable en un 99,999 %. watchdog-mux mantiene /dev/watchdog abierto de forma permanente para que ningún otro proceso interfiera y para no depender del magic close del hardware; un cliente que envía el carácter V se considera desconectado limpiamente.
sequenceDiagram
participant N as nodo caido
participant WD as watchdog-mux
participant CRM as CRM master
participant N2 as nodo destino
Note over N: t igual a 0 pierde red y quorum
N->>WD: el LRM entra en lost_agent_lock y deja de refrescar
Note over CRM: t cercano a 60 s marca el nodo offline por fence_delay
Note over WD: t cercano a 60 s deja de tocar /dev/watchdog
Note over N: t cercano a 70 s reset por watchdog o self-fencing
CRM->>CRM: adquiere el agent lock del nodo caido
Note over CRM: los servicios pasan a fence y luego a recovery
CRM->>N2: recovery elige nodo con CRS y reglas de afinidad
N2->>N2: arranca los guests
Note over CRM,N2: total tipico cercano a 2 minutos
Tras un fencing exitoso el CRM construye el conjunto de nodos elegibles, filtra por node affinity rules, aplica las resource affinity rules, elige el de menor carga según el CRS, y coloca el servicio en stopped para arrancarlo si su estado solicitado es started.
Configura el watchdog por hardware. Por defecto «all hardware watchdog modules are blocked for security reasons»; si no hay watchdog configurado se usa el softdog del kernel Linux. Para usar el del chipset o el BMC se declara el módulo en /etc/default/pve-ha-manager, fichero que lee el servicio watchdog-mux y que carga el módulo al arrancar:
# select watchdog module (default is softdog)
WATCHDOG_MODULE=iTCO_wdt
Módulos habituales: iTCO_wdt en chipsets Intel, ipmi_watchdog en BMC/IPMI, hpwdt en HPE iLO y softdog como fallback por software.
systemctl restart watchdog-mux
lsmod | grep -E 'wdt|softdog|watchdog'
wdctl # información del dispositivo watchdog
journalctl -u watchdog-mux -b
El modo de fencing global se define en datacenter.cfg con fencing: watchdog|hardware|both, y el default es watchdog. Los estados que aparecen en ha-manager status --verbose:
| Estado | Significado |
|---|---|
armed | Hay CRM gestionando servicios, watchdog abierto y activo |
standby | HA listo pero sin CRM master activo, watchdog no abierto |
disarming | El CRM congela servicios y espera a que los LRM suelten el watchdog |
disarmed | Todos los watchdogs liberados: no hay fencing ni failover automático |
Modo mantenimiento, shutdown policy y disarm-ha
Reiniciar un nodo con HA activo sin avisar a HA es la forma más rápida de provocar un failover que no querías. El camino correcto es ha-manager crm-command node-maintenance enable|disable <nodo>. El comando se encola en el CRM y se ejecuta cuando este lo procesa; el LRM se marca no disponible pero sigue procesando migraciones, y el watchdog permanece activo hasta que todos los servicios se han migrado, que es exactamente lo que quieres: si el nodo muere a mitad del vaciado, sigue habiendo fencing. La confirmación de que ya puedes trabajar es la línea watchdog closed (disabled) en el log. Gotcha: el modo mantenimiento manual no se borra solo; hay que desactivarlo explícitamente, y al hacerlo los servicios vuelven al nodo original.
flowchart TD
A["ha-manager crm-command node-maintenance enable pve1"] --> B["El CRM encola el comando"]
B --> C["El LRM se marca no disponible pero sigue migrando"]
C --> D["Esperar a que todos los servicios salgan del nodo"]
D --> E["Buscar watchdog closed disabled en el log del LRM"]
E --> F["Trabajar: actualizar cambiar disco reiniciar"]
F --> G["ha-manager crm-command node-maintenance disable pve1"]
G --> H["Los servicios vuelven al nodo original"]
ha-manager crm-command node-maintenance enable pve1
watch -n2 ha-manager status
journalctl -u pve-ha-lrm -f | grep -i watchdog # esperar "watchdog closed (disabled)"
apt update && apt dist-upgrade && reboot
ha-manager crm-command node-maintenance disable pve1
Para apagados y reinicios lanzados desde fuera de HA, el comportamiento lo decide shutdown_policy en datacenter.cfg, con default conditional:
| Valor | Comportamiento |
|---|---|
migrate | El LRM se marca no disponible y retrasa el apagado hasta que todos los servicios se hayan movido. Cuando el nodo vuelve, los servicios desplazados regresan |
failover | Todos los servicios se paran, pero se recuperan en otro nodo si el actual no vuelve pronto |
freeze | Todos los servicios se paran y se congelan: no se recuperan hasta que el nodo vuelva |
conditional (default) | Detecta si se pidió shutdown o reboot. En shutdown el LRM para los servicios gestionados y otros nodos los toman después; en reboot el LRM avisa al CRM y espera a que ponga los recursos en freeze |
Para mantenimiento programado usa migrate o node-maintenance enable; conditional implica corte de servicio. Novedad de PVE 9.2: para mantener varios nodos a la vez existe el desarmado explícito de HA a nivel de cluster. Con freeze no se emiten comandos nuevos y los recursos quedan congelados; con ignore los recursos salen del seguimiento de HA. Mientras HA está desarmado no hay failover automático: es una ventana de riesgo consciente, no un modo de operación.
ha-manager crm-command disarm-ha freeze
# ... mantenimiento en varios nodos, sin riesgo de fencing ...
ha-manager crm-command arm-ha
Cluster Resource Scheduler y el balanceador dinámico
El CRS es lo que decide a qué nodo va un recurso. Se configura en datacenter.cfg con una línea del tipo crs: ha=static,ha-rebalance-on-start=1,ha-auto-rebalance=1:
| Sub-opción | Valores | Default |
|---|---|---|
ha | basic, static, dynamic | basic |
ha-rebalance-on-start | 0 o 1 | 0 |
ha-auto-rebalance | 0 o 1 | 0 |
ha-auto-rebalance-threshold | porcentaje | 30 |
ha-auto-rebalance-margin | porcentaje | 10 |
ha-auto-rebalance-hold-duration | rondas | 3 |
ha-auto-rebalance-method | bruteforce, topsis | bruteforce |
Los tres modos difieren en qué información miran: basic cuenta el número de guests activos en cada nodo; static usa la información estática de los guests activos, es decir las cuotas configuradas de CPU y memoria; dynamic usa el uso medio real de CPU y memoria además de las cuotas, y es novedad de PVE 9.2. El CRS actúa en tres momentos: al recuperar recursos HA tras la caída de un nodo, al cambiar la configuración de reglas HA si una regla impone restricciones nuevas, y al arrancar un recurso si ha-rebalance-on-start está activo.
La otra novedad de 9.2 es el balanceador automático: el HA Manager puede reducir el desequilibrio global del cluster emitiendo migraciones de rebalanceo por su cuenta. Se configura en Datacenter → Options → Cluster Resource Scheduling y requiere modo static o dynamic. Un recurso con auto-rebalance 0 queda excluido de esas migraciones automáticas, que es la forma de sacar de la ecuación a una VM que no tolera un corte. En la GUI verás los modos etiquetados con nombres largos tipo static-load y dynamic-load; en el fichero los valores son basic, static y dynamic. Si dudas de qué está activo en tu sistema, pvesh get /cluster/options te lo dice.
Migración en vivo: requisitos, opciones y redes dedicadas
La migración en vivo funciona así: se arranca un proceso QEMU nuevo en el destino con el flag incoming y las vCPU en pausa; el origen envía la memoria de forma asíncrona; las páginas que se modifican se marcan como dirty y se hace otra pasada; el bucle se repite hasta que la diferencia es lo bastante pequeña para enviarse en milisegundos; entonces se pausa el origen, se envía el resto y se despausa el destino. El tiempo total de pausa es, según la documentación, «well under a second».
El parámetro que gobierna la convergencia es migrate_downtime, con default 0.1 segundos. Si la migración no logra converger porque se ensucia demasiada RAM, el límite se incrementa automáticamente paso a paso hasta que converge, y «will be capped to 2000 seconds (maximum in QEMU)». Existe también migrate_speed en MB/s, con default 0 que significa sin límite. Los requisitos, literales:
- La VM no tiene recursos locales que no puedan migrarse: dispositivos PCI o USB en passthrough bloquean la migración en vivo; los discos locales sí pueden migrarse enviándolos al destino.
- Los hosts están en el mismo cluster de Proxmox VE y el destino tiene la misma o superior versión de los paquetes de PVE.
- Los hosts tienen CPU del mismo fabricante con capacidades similares; entre fabricantes distintos puede funcionar según los modelos y el tipo de CPU configurado, pero no está garantizado.
- Solo entre hosts de la misma arquitectura: el estado de CPU de un huésped no se puede transferir entre x86 y arm64.
Regla de versiones durante un upgrade: la migración de versiones antiguas a nuevas siempre funciona; la inversa puede fallar. Por eso, al actualizar un cluster nodo a nodo, migras hacia los ya actualizados y no de vuelta. El comando es qm migrate <vmid> <target> [OPTIONS]:
| Opción | Default | Qué hace |
|---|---|---|
--online | — | Usa migración en vivo si la VM está corriendo. Se ignora si está parada |
--with_local_disks | — | Habilita la migración en vivo del storage para discos locales |
--targetstorage | — | Mapeo de storage origen a destino. Un solo ID mapea todos los storages a ese; el valor especial 1 mapea cada storage a sí mismo |
--migration_network | — | CIDR de la subred que se usa para migrar |
--migration_type | secure | secure cifra por túnel SSH; insecure solo en redes completamente privadas |
--bwlimit | límite de datacenter o storage | Límite de ancho de banda en KiB/s |
--force | — | Permite migrar VMs con dispositivos locales. Solo root |
--with_conntrack_state | 0 | Migra las entradas de conntrack de la VM |
El manpage de qm usa guion bajo en --with_local_disks y --with_conntrack_state; parte de la documentación narrativa y la API los escriben con guion medio, así que para no depender del parser usa la forma del manpage. La migración de conntrack es best-effort: copia las entradas al destino y las purga del origen para que el firewall del nuevo host reconozca las conexiones activas, pero depende mucho del montaje de red y con SNAT en el host lo más probable es que no funcione.
La red de migración se fija en datacenter.cfg y el tipo debe acompañar siempre al ajuste de red, igual que los límites globales de ancho de banda en KiB/s:
migration: secure,network=10.1.2.0/24
bwlimit: clone=100000,default=50000,migration=200000,move=100000,restore=100000
qm migrate 106 tre --online --migration_network 10.1.2.0/24
Advertencia sobre insecure: el canal secure está fuertemente recomendado salvo que controles la red por completo, porque insecure transmite el contenido de la RAM sin cifrar, con riesgo de exponer contraseñas o claves. Con AES acelerado por hardware el sobrecoste es pequeño; el impacto se nota sobre todo en redes de 10 Gbps o más.
Migración con discos locales, masiva y remota
Sin storage compartido, QEMU copia los bloques del disco en caliente con un block mirror mientras la VM sigue corriendo, y al final hace el switchover de RAM. Funciona, pero es mucho más lento: se mueve el disco entero por la red.
qm migrate 100 nodo2 --online --with_local_disks
qm migrate 100 nodo2 --online --with_local_disks --targetstorage local-zfs
qm migrate 100 nodo2 --online --with_local_disks --targetstorage 1
qm migrate 100 nodo2 --online --with_local_disks --targetstorage local-lvm:local-zfs
qm migrate 100 nodo2 --online --with_local_disks --bwlimit 100000 # 100 MiB/s
Un detalle que cambia decisiones de diseño: «Storage migration always uses secure channels regardless of this setting». Es decir, --migration_type insecure afecta al tráfico de RAM, no al de disco; no esperes ganar velocidad de copia desactivando el cifrado. Si el destino ya es receptor de una réplica ZFS del capítulo 8, la migración es rapidísima: solo se transfieren los deltas desde la última replicación, y la dirección de la réplica se invierte automáticamente al terminar.
Migración masiva. En la GUI es Bulk Actions → Bulk Migrate sobre el nodo, con destino, online u offline y paralelismo. Por API existe el endpoint /nodes/{node}/migrateall, que es lo que usa ese botón; los nombres exactos de sus parámetros conviene confirmarlos en tu sistema con pvesh usage /nodes/<nodo>/migrateall -v antes de meterlos en un script. Un bucle explícito es más aburrido y más predecible:
for vmid in $(qm list | awk 'NR>1 {print $1}'); do
qm migrate "$vmid" nodo2 --online || echo "FALLO: $vmid"
done
Contenedores. LXC no tiene migración en vivo: «Running containers cannot live-migrated due to technical limitations.» Lo que hay es la restart migration, que apaga el contenedor, lo mueve y lo arranca en el destino; como los contenedores son ligeros, el corte típico es de cientos de milisegundos. Una restart migration apaga el contenedor y lo mata si excede el timeout especificado, que por defecto son 180 segundos; después hace una migración offline normal y lo arranca en destino. Los detalles de contenedores están en el capítulo 6.
pct migrate 110 pve2 # CT parado: migración offline
pct migrate 110 pve2 --restart # CT corriendo: timeout por defecto 180 s
pct migrate 110 pve2 --restart --timeout 300
pct migrate 110 pve2 --target-storage local-zfs # cambiar de storage en destino
pct migrate 110 pve2 --target-storage 1 # cada storage a sí mismo
pct migrate 110 pve2 --bwlimit 51200
Migración remota entre clusters distintos. Es funcionalidad experimental, con la forma qm remote-migrate <vmid> [<target-vmid>] <target-endpoint> --target-bridge <string> --target-storage <string> [OPTIONS]. El <target-endpoint> tiene la forma apitoken=...,host=...,fingerprint=...,port=.... La opción --delete (default 0) borra la VM original tras la migración; por defecto la VM original se conserva en el cluster origen en estado parado, que es el comportamiento seguro. Acepta también --online y --bwlimit. Cambio de PVE 9.2: la migración remota de recursos HA está prohibida, en cualquier estado; si necesitas mover una VM gestionada por HA a otro cluster, primero la sacas de HA con ha-manager remove y luego migras.
Errores comunes y diagnóstico
| Síntoma | Causa probable | Cómo lo confirmas | Qué haces |
|---|---|---|---|
/etc/pve en solo lectura, mkdir: Read-only file system | Sin quorum | pvecm status muestra Quorate: No | Recuperar nodos; en emergencia pvecm expected 1 |
pvecm add falla con authentication key ... invalid | Reloj desincronizado | timedatectl, chronyc tracking | Sincronizar NTP en todos los nodos |
pvecm add falla con Host key verification failed | Fingerprint SSH obsoleto | ssh-keygen -F <host> | pvecm updatecerts y limpiar known_hosts |
| Nodo gris en la GUI pero responde a ping | Certificados desincronizados o pvestatd caído | systemctl status pvestatd pveproxy | pvecm updatecerts --force && systemctl restart pvedaemon pveproxy pvestatd |
| El cluster parpadea: nodos que entran y salen | corosync compartiendo NIC con storage o migración | journalctl -u corosync | grep -i retransmit | Red dedicada de corosync o segundo enlace |
| Nodos que se reinician solos con HA activo | El watchdog dispara por pérdida de quorum | journalctl -k | grep -i watchdog, last -x reboot | Arreglar la red de corosync y añadir enlace redundante |
QDevice en NA (Not Alive) | TCP 5403 bloqueado | nc -zv <ip-qnetd> 5403, systemctl status corosync-qdevice | Abrir el puerto y revisar el firewall del host externo |
pvecm add falla tras reinstalar el mismo nodo | Restos del nodo anterior en el cluster | ls /etc/pve/nodes/ | rm -rf /etc/pve/nodes/<nombre> y limpiar known_hosts |
Recurso HA en estado error | Falló el arranque max_restart + max_relocate veces | ha-manager status --verbose, journalctl -u pve-ha-lrm | Arreglar la causa, luego --state disabled y --state started |
ha-manager status muestra watchdog: standby | No hay CRM master por falta de quorum, o HA desarmado | pvecm status, ha-manager status --verbose | Recuperar quorum o ha-manager crm-command arm-ha |
Migración falla: can't migrate VM which uses local devices | PCI o USB en passthrough | qm config <vmid> | grep -E 'hostpci|usb' | Quitar el dispositivo o --force (solo root, con corte) |
Migración falla: target storage does not exist | Storage local sin el mismo ID en el destino | pvesm status en ambos nodos | --targetstorage <id> o crear el storage con el mismo ID |
| Migración en vivo falla por CPU | Modelo host entre CPU distintas | qm config <vmid> | grep cpu, lscpu en ambos | Cambiar a x86-64-v2-AES o modelo custom, requiere reiniciar el guest |
Job de replicación en error | Espacio, red o storage ID inexistente en destino | pvesr status, journalctl -u pvesr | Corregir y pvesr run --id <job>; reintenta solo cada 30 minutos |
Cambié corosync.conf y no pasa nada | Editaste la copia local o no subiste config_version | grep config_version /etc/pve/corosync.conf | Editar el fichero de /etc/pve con el procedimiento del .new y subir la versión |
Las unidades de systemd que hay que mirar, por orden de qué te cuentan: corosync para membresía, enlaces, token timeouts y retransmits; pve-cluster para pmxcfs, quorum y montaje de /etc/pve; pve-ha-crm para decisiones HA, fencing y recovery (solo el master decide); pve-ha-lrm para la ejecución local de comandos HA, el lock y el watchdog; watchdog-mux para apertura y cierre del watchdog; y corosync-qdevice para la conexión al qnetd.
journalctl -b -u corosync -u pve-cluster -u pve-ha-crm -u pve-ha-lrm
journalctl -eu pve-ha-crm
wdctl
pvereport > /root/reporte-$(hostname)-$(date +%F).txt
pvereport recolecta, entre otras muchas cosas, pvecm nodes, pvecm status, cat /etc/pve/corosync.conf, ha-manager status y cat /etc/pve/datacenter.cfg. Ejecútalo y guárdalo antes de cualquier cambio grande: es la línea base contra la que comparar. Contiene información sensible, así que revísalo antes de pegarlo en un foro.
Lo que queda operativo
Tienes un cluster con corosync sobre red dedicada y un anillo de respaldo con prioridades coherentes, sabes por qué config_version es obligatorio y cómo se edita el fichero maestro sin romper nada, entiendes la tabla de quorum lo bastante bien como para no comprar un cuarto nodo esperando disponibilidad, y tienes un QDevice si tu número de nodos es par. Del lado de HA tienes recursos registrados con reglas de afinidad de nodo y de recurso, el watchdog configurado y verificado con wdctl, y un procedimiento de mantenimiento que no provoca fencings accidentales. Y sabes mover guests en caliente, con o sin storage compartido. Falta el ingrediente que convierte tres servidores en una plataforma: storage compartido y replicado que viva en el propio cluster. En el capítulo 12 montarás Ceph hiperconvergido sobre estos mismos nodos, con monitores, managers y OSD, y verás cómo se relaciona su propio quorum con el de corosync que acabas de configurar.