Files
ProxMenux/web/messages/es/docs/backup-restore/cross-kernel.json
MacRimi 720f3fdbd2 docs: promote /web from develop for backup-restore, Log2RAM and Network Flow guides
Brings 69 files from develop under /web/:
- Full Backup & Restore section (11 pages EN + ES: overview, how-it-works, destinations,
  creating backups, scheduled jobs, restoring, cross-kernel hydration)
- Log2RAM dedicated block in post-install/optional with commands + upstream link
- Network Flow diagram documented on monitor/dashboard/network
- Rewritten category descriptions in post-install/customizable
- Fixed automated.json thresholds + link to Log2RAM section
- Updated screenshots (network-flow-overview, storage-top-row, vms modals)

No code, config or AppImage binaries touched — /web/ scope only. Merging deploys
the documentation site to the current beta release notes.
2026-07-04 22:10:49 +02:00

95 lines
21 KiB
JSON

{
"meta": {
"title": "Restauración cross-kernel — detección de dirección, filtro de subconjunto seguro, hidratación | ProxMenux",
"description": "Cómo restaura ProxMenux una copia de host sobre un destino con un kernel de versión mayor distinta. Documenta cómo se detecta la dirección del salto, el filtro de subconjunto seguro que salta rutas críticas del arranque cuando el destino corre un kernel más reciente que la copia, y la hidratación independiente del kernel de cuatro fases que reaplica la configuración del usuario como IOMMU, IDs VFIO y tokens custom del cmdline sin copiar verbatim los ficheros ligados al kernel.",
"ogTitle": "ProxMenux Backup — restauración cross-kernel e hidratación",
"ogDescription": "Restauración cross-kernel direccional con filtro de subconjunto seguro e hidratación independiente del kernel.",
"twitterTitle": "Restauración cross-kernel | ProxMenux",
"twitterDescription": "Cómo maneja ProxMenux una restauración cuando el kernel del destino difiere del de la copia."
},
"header": {
"title": "Restauración cross-kernel",
"description": "Cómo maneja ProxMenux una restauración cuando el kernel del host de destino es distinto al kernel que había en el momento de la copia — especialmente cuando el destino ejecuta un kernel más reciente. Documenta cómo se detecta la diferencia, cómo se filtran las rutas críticas del arranque que podrían romper el destino, y cómo se reaplica la configuración propia del usuario sin copiar verbatim los ficheros ligados al kernel.",
"section": "Backup & Restore"
},
"intro": {
"title": "Cada salto de kernel se maneja de forma distinta",
"body": "Cuando la restauración detecta que la copia y el destino tienen versiones mayores distintas de kernel, el flujo se ramifica en función de la dirección del salto — si la copia es más antigua o más reciente que el destino — porque los dos casos tienen modos de fallo opuestos. Las copias más recientes que el destino se restauran limpiamente tal cual (verificado empíricamente en múltiples pruebas de banco). Las copias más antiguas que el destino necesitan un filtro para evitar romper el arranque del destino con configuración escrita para un kernel que desde entonces ha cambiado."
},
"directionCheck": {
"heading": "La comprobación de dirección",
"intro": "Durante la comprobación de compatibilidad, <code>hb_compat_check</code> compara el kernel registrado en el manifiesto de la copia contra el kernel actual del destino (<code>uname -r</code>) y clasifica la restauración en uno de tres casos, guardado en la variable interna <code>HB_COMPAT_KERNEL_DIRECTION</code>:",
"rows": [
{ "direction": "same", "condition": "La versión mayor del kernel coincide entre la copia y el destino.", "behavior": "El flujo de restauración completo corre sin cambios. Sin filtro adicional, sin hidratación, sin aviso especial en la interfaz." },
{ "direction": "bk_newer", "condition": "El kernel de la copia es más RECIENTE que el del destino (por ejemplo: la copia se hizo con kernel 7.0 y el destino corre kernel 6.17).", "behavior": "El flujo de restauración completo corre sin cambios, exactamente igual que en <code>same</code>. No se aplica ningún filtro. Verificado empíricamente: los controladores se reinstalan contra el kernel del destino, la configuración IOMMU se aplica limpia, las VMs con passthrough GPU arrancan sin problemas." },
{ "direction": "bk_older", "condition": "El kernel de la copia es más ANTIGUO que el del destino (por ejemplo: la copia se hizo con kernel 6.17 y el destino corre kernel 7.0).", "behavior": "Se activan el filtro de subconjunto seguro y la hidratación de cuatro fases descritos más abajo. La restauración procede — el destino reproduce el origen, pero los ficheros críticos del arranque no se copian verbatim." }
]
},
"whyBkNewerIsSafe": {
"heading": "Por qué una copia con kernel más reciente que el destino se restaura sin cambios",
"body": "Cuando la restauración corre contra un destino con un kernel <em>más antiguo</em> que el registrado en la copia, todos los mecanismos de los que depende la restauración son independientes de la versión del kernel. Los instaladores de controladores de GPU y otros dispositivos PCI detectan el kernel en ejecución con <code>uname -r</code> y compilan DKMS contra lo que tenga el destino. La instalación de paquetes por APT trae binarios construidos para la distribución del destino. Los tokens IOMMU del cmdline como <code>intel_iommu=on</code> son estables entre versiones mayores de kernel. La copia lleva rutas escritas bajo un kernel más reciente, pero esas rutas (blacklists de módulos, defaults de GRUB, configuración de initramfs) siguen siendo sintaxis válida en el más antiguo — los kernels ignoran los tokens que no reconocen en lugar de fallar. Este caso es equivalente en la práctica a una restauración con el mismo kernel, y ProxMenux lo trata como tal."
},
"safeSubsetFilter": {
"heading": "El filtro de subconjunto seguro (sólo cuando el kernel del destino es más reciente)",
"intro": "Cuando el kernel del destino es más reciente que el de la copia, la comprobación de compatibilidad añade 16 rutas críticas del arranque de <code>hb_unsafe_paths_cross_version</code> a <code>RS_SKIP_PATHS</code>. Estas rutas se excluyen de la restauración porque escribir una versión suya de un kernel más antiguo sobre un destino que corre uno más reciente ha causado kernel panics en pruebas de banco. Las rutas cubren cuatro categorías:",
"categoryRows": [
{ "category": "Bootloader", "paths": "<code>/etc/default/grub</code>, <code>/etc/kernel</code>", "reason": "Defaults de GRUB atados al orden previo de kernels, y estado de proxmox-boot-tool (cmdline, UUIDs de ESP, hooks) que referencia rutas e identificadores de la instalación más antigua." },
{ "category": "Módulos del kernel y artefactos de arranque", "paths": "<code>/etc/modules-load.d</code>, <code>/etc/modprobe.d</code>, <code>/etc/initramfs-tools</code>", "reason": "Listas de autocarga que pueden referenciar módulos renombrados entre majors del kernel, opciones de módulo que pueden no aplicar, hooks de initramfs escritos para el kernel más antiguo." },
{ "category": "Stack de almacenamiento e identidad de filesystem", "paths": "<code>/etc/fstab</code>, <code>/etc/multipath</code>, <code>/etc/iscsi</code>, <code>/etc/udev/rules.d</code>, <code>/etc/zfs</code>", "reason": "UUIDs que pueden no existir en esta instalación, drivers de multipath que cambian entre kernels, parámetros iSCSI que evolucionan, reglas udev que pueden atarse a subsistemas inexistentes, estado ZFS (<code>zpool.cache</code> + <code>hostid</code>) que puede bloquear el pool como si no perteneciera al host." },
{ "category": "Fuentes APT", "paths": "<code>/etc/apt</code>", "reason": "Las suites de fuentes APT pueden disparar un downgrade de paquetes críticos en la próxima actualización." },
{ "category": "systemd", "paths": "<code>/etc/systemd/system</code>, <code>/etc/systemd/journald.conf</code>, <code>/etc/systemd/logind.conf</code>, <code>/etc/systemd/system.conf</code>, <code>/etc/systemd/user.conf</code>", "reason": "Overrides de unit y .wants ligados al major de systemd más antiguo; claves de configuración que pueden no parsearse en un systemd más reciente." }
],
"outroBody": "El filtro corre ANTES del diálogo de confirmación para que el usuario vea la lista exacta de rutas que se saltarán, categorizadas por motivo. La restauración procede igualmente — todo lo demás (VMs, LXCs, red, /etc/pve, usuarios, cron, estado de ProxMenux, paquetes, drivers, /root) se restaura con normalidad."
},
"hydration": {
"heading": "Hidratación independiente del kernel",
"intro": "El filtro de subconjunto seguro por sí solo dejaría al destino sin la configuración que el usuario había puesto dentro de esos ficheros críticos del arranque: cmdline IOMMU para passthrough GPU, IDs de dispositivo VFIO, <code>GRUB_TIMEOUT</code> custom, blacklists de nvidia. La pasada de hidratación reaplica esas piezas de forma independiente de la versión del kernel. Corren cuatro fases cuando el kernel del destino es más reciente que el de la copia, cada una aditiva (nunca sobrescribe un valor que el destino ya lleva) e idempotente (correr dos veces es un no-op).",
"phaseRows": [
{ "phase": "1a — Ruta GRUB", "detail": "Para hosts que usan GRUB (instalaciones ext4/lvm). <code>_rs_hyd_grub</code> mergea cada token de <code>manifest.kernel_params.cmdline_extra</code> de la copia en el <code>GRUB_CMDLINE_LINUX_DEFAULT</code> vivo del destino, saltando los tokens cuya clave el destino ya lleva. Después mergea claves whitelisted <code>GRUB_*</code> (<code>GRUB_TIMEOUT</code>, <code>GRUB_TIMEOUT_STYLE</code>, <code>GRUB_DEFAULT</code>, <code>GRUB_TERMINAL</code>, <code>GRUB_DISABLE_OS_PROBER</code>, <code>GRUB_SERIAL_COMMAND</code>, <code>GRUB_GFXMODE</code>, <code>GRUB_GFXPAYLOAD_LINUX</code>) del <code>/etc/default/grub</code> de la copia si difieren de las del destino." },
{ "phase": "1b — Ruta systemd-boot / ZFS", "detail": "Para hosts que usan systemd-boot (típicamente ZFS-on-root). <code>_rs_hyd_kernel_cmdline</code> mergea los tokens del usuario de <code>cmdline_extra</code> en el <code>/etc/kernel/cmdline</code> del destino, manteniendo intacto el boilerplate propio del destino: <code>root=</code>, <code>boot=</code> y <code>rootflags=</code>." },
{ "phase": "2 — Merge en /etc/modules", "detail": "<code>_rs_hyd_modules</code> añade los módulos de <code>manifest.kernel_params.modules_loaded_at_boot</code> que estén en la whitelist (<code>vfio</code>, <code>vfio_pci</code>, <code>vfio_iommu_type1</code>, <code>vfio_virqfd</code>, <code>kvm</code>, <code>kvm_intel</code>, <code>kvm_amd</code>, <code>nvidia</code>, <code>nvidia_drm</code>, <code>nvidia_modeset</code>, <code>nvidia_uvm</code>, <code>i915</code>, <code>xe</code>) Y que aún no estén presentes en <code>/etc/modules</code> del destino." },
{ "phase": "3 — Copia de ficheros whitelisted", "detail": "<code>_rs_hyd_files</code> copia ficheros escritos por el usuario del staging rootfs al destino en vivo cuando el contenido difiere. La whitelist cubre ficheros VFIO/nvidia/blacklist bajo <code>/etc/modprobe.d</code>, <code>/etc/modules-load.d</code>, y la regla VFIO bind + reglas udev de nvidia de ProxMenux bajo <code>/etc/udev/rules.d</code>. Los ficheros propiedad de la distro (<code>pve-blacklist.conf</code>, <code>mdadm.conf</code>, <code>nvme.conf</code>) se excluyen intencionadamente — sus contenidos evolucionan entre releases." },
{ "phase": "4 — Forzar reflows post-arranque", "detail": "Las cuatro fases escriben directamente en el destino vivo FUERA del pipeline normal de restauración. Para que los tokens/módulos/ficheros mergeados tengan efecto en el siguiente arranque, <code>HB_HYDRATION_APPLIED=1</code> se propaga a través de <code>plan.env</code> a <code>apply_pending_restore.sh</code>, que fuerza <code>NEEDS_INITRAMFS=1</code> y <code>NEEDS_GRUB=1</code> con independencia de lo que hubiera en la lista de apply. El dispatcher post-arranque después regenera el initramfs y refresca el bootloader." }
]
},
"planCommit": {
"heading": "Plan vs commit — el usuario ve un preview antes",
"body": "La hidratación corre en dos modos. Antes del diálogo de confirmación, ProxMenux ejecuta <code>_rs_apply_bk_older_hydration</code> en modo <code>plan</code>: calcula exactamente lo que se mergearía, rellena <code>RS_HYDRATION_SUMMARY</code> con un bloque verde que lista cada acción, y retorna sin escribir nada. El diálogo de confirmación muestra ese bloque verde junto a la lista ámbar de rutas saltadas por el subconjunto seguro, para que el usuario vea POR ADELANTADO qué se reaplicará automáticamente. Tras la confirmación del usuario, ProxMenux vuelve a ejecutar el mismo helper en modo <code>commit</code> — mismas fases, misma lógica, pero esta vez cada fase escribe en el destino vivo. Cancelar el diálogo de confirmación deja el destino intacto."
},
"flowDiagram": {
"heading": "El flujo cuando el kernel del destino es más reciente que el de la copia",
"intro": "Los pasos específicos que se añaden cuando el kernel del destino es más reciente se insertan dentro del flujo normal de restauración. Todo lo demás — hot apply, prepare pending, instalación de paquetes, dispatcher post-arranque — corre idéntico a una restauración con el mismo kernel.",
"diagram": " ┌────────────────────────────────────────────────────────────┐\n │ hb_compat_check │\n │ HB_COMPAT_KERNEL_DIRECTION = bk_older │\n └───────────────────────────┬────────────────────────────────┘\n │\n ▼\n ┌────────────────────────────────────────────────────────────┐\n │ Añade 16 rutas críticas del arranque a RS_SKIP_PATHS │\n │ /etc/default/grub, /etc/kernel, /etc/modules-load.d, ... │\n └───────────────────────────┬────────────────────────────────┘\n │\n ▼\n ┌────────────────────────────────────────────────────────────┐\n │ _rs_apply_bk_older_hydration \"plan\" │\n │ Calcula qué se mergearía │\n │ Rellena RS_HYDRATION_SUMMARY (bloque verde) │\n │ Sin escrituras │\n └───────────────────────────┬────────────────────────────────┘\n │\n ▼\n ┌────────────────────────────────────────────────────────────┐\n │ Diálogo de confirmación │\n │ Ámbar: rutas saltadas por el filtro de subconjunto seguro │\n │ Verde: tokens/ficheros reaplicados por la hidratación │\n │ El usuario acepta o cancela │\n └───────────────────────────┬────────────────────────────────┘\n │ (aceptado)\n ▼\n ┌────────────────────────────────────────────────────────────┐\n │ _rs_apply_bk_older_hydration \"commit\" │\n │ Fase 1a/1b: mergea tokens del cmdline + claves GRUB │\n │ Fase 2: añade módulos a /etc/modules │\n │ Fase 3: copia ficheros whitelisted vfio/nvidia │\n │ Fija HB_HYDRATION_APPLIED=1 │\n └───────────────────────────┬────────────────────────────────┘\n │\n ▼\n ┌────────────────────────────────────────────────────────────┐\n │ El resto de la restauración corre normalmente │\n │ _rs_apply hot (salta RS_SKIP_PATHS) │\n │ _rs_prepare_pending_restore (escribe plan.env con │\n │ HB_HYDRATION_APPLIED=1) │\n │ packages.manual.list install │\n │ Reinicio │\n │ apply_pending_restore.sh (fuerza NEEDS_INITRAMFS=1, │\n │ NEEDS_GRUB=1 por el flag de hidratación) │\n │ apply_cluster_postboot.sh │\n │ update-initramfs -u -k all │\n │ update-grub / proxmox-boot-tool refresh │\n │ component --auto-reinstall │\n └────────────────────────────────────────────────────────────┘"
},
"concreteExamples": {
"heading": "Ejemplos concretos",
"intro": "La pasada de hidratación no es abstracta — produce resultados observables y correctos en escenarios habituales. Dos ejemplos que la hidratación resuelve automáticamente:",
"rows": [
{ "scenario": "GPU passthrough (VFIO)", "detail": "El origen tenía <code>intel_iommu=on iommu=pt</code> en el cmdline, <code>vfio</code>/<code>vfio_pci</code>/<code>vfio_iommu_type1</code> en <code>/etc/modules</code>, un <code>/etc/modprobe.d/vfio.conf</code> con <code>options vfio-pci ids=10de:2216</code>, y un <code>/etc/modprobe.d/blacklist-nvidia.conf</code>. La hidratación mergea los tokens del cmdline en el GRUB o kernel cmdline del destino, añade los módulos vfio a <code>/etc/modules</code>, y copia los dos ficheros modprobe escritos por el usuario. En el siguiente arranque, IOMMU está activo, los módulos VFIO cargan, la GPU queda ligada a vfio-pci y la VM arranca con el passthrough funcionando." },
{ "scenario": "Defaults custom de GRUB", "detail": "El origen tenía <code>GRUB_TIMEOUT=1</code> y <code>GRUB_DISABLE_OS_PROBER=true</code>. La hidratación lee ambas claves del <code>/etc/default/grub</code> de la copia, ve que difieren de los defaults de la instalación fresca, y reescribe esas dos líneas en el fichero del destino (dejando todo lo demás, incluido <code>GRUB_DISTRIBUTOR</code>, intacto)." }
]
},
"callout": {
"warningTitle": "Qué no reaplica la hidratación cuando el kernel del destino es más reciente",
"warningBody": "La hidratación reaplica sólo la configuración que ProxMenux sabe que es segura entre versiones del kernel: tokens IOMMU, IDs VFIO, claves whitelisted de GRUB y módulos de una lista fija (<code>vfio*</code>, <code>nvidia*</code>, <code>i915</code>, <code>xe</code>, <code>kvm*</code>). Todo lo que quede fuera de ese conjunto — hooks custom de initramfs bajo <code>/etc/initramfs-tools/hooks/</code>, ficheros no whitelisted bajo <code>/etc/modprobe.d/</code>, overrides de unit de systemd escritos por el usuario — permanece excluido. El motivo es concreto: esos ficheros pueden invocar interfaces internas del kernel (APIs de módulos, layout de <code>/sys</code>, hooks de <code>udev</code>) que cambian entre versiones mayores, y aplicarlos verbatim sobre el kernel más reciente puede impedir que el destino arranque. Cuando se necesita reproducción exacta de la cadena de arranque, la restauración debe correr sobre un host con la misma versión mayor de kernel que la copia."
},
"codeReference": {
"heading": "Dónde viven los mecanismos",
"intro": "Para desarrolladores que quieran trazar o extender el comportamiento cross-kernel:",
"rows": [
{ "component": "Detección de dirección", "location": "<code>hb_compat_check</code> en <code>lib_host_backup_common.sh</code>. Fija <code>HB_COMPAT_KERNEL_DIRECTION</code>." },
{ "component": "Lista de rutas del subconjunto seguro", "location": "<code>hb_unsafe_paths_cross_version</code> en <code>lib_host_backup_common.sh</code>. Emite líneas <code>path\\tmotivo</code> usadas tanto por el filtro CLI como por el endpoint Web <code>/api/host-backups/restore/prepare</code>." },
{ "component": "Fases de hidratación", "location": "<code>_rs_hyd_grub</code>, <code>_rs_hyd_kernel_cmdline</code>, <code>_rs_hyd_modules</code>, <code>_rs_hyd_files</code> en <code>backup_host.sh</code>. Orquestados por <code>_rs_apply_bk_older_hydration</code>." },
{ "component": "Forzado de reflow post-arranque", "location": "<code>apply_pending_restore.sh</code> lee <code>HB_HYDRATION_APPLIED</code> de <code>plan.env</code> y fuerza <code>NEEDS_INITRAMFS=1</code>/<code>NEEDS_GRUB=1</code>." },
{ "component": "Preview Web", "location": "<code>/api/host-backups/restore/prepare</code> en <code>flask_server.py</code>. Fuentea la librería helper, ejecuta <code>_rs_apply_bk_older_hydration</code> en modo plan, devuelve las acciones al modal Web." }
]
},
"whereNext": {
"heading": "A dónde seguir",
"items": [
{ "label": "Restaurar", "href": "/docs/backup-restore/restoring", "tail": " — el pipeline completo de restauración en el que se enchufan los mecanismos de esta página." },
{ "label": "Cómo funciona", "href": "/docs/backup-restore/how-it-works", "tail": " — el manifiesto y los colectores que producen el bloque <code>kernel_params</code> del que lee la hidratación." }
]
}
}