mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-11-01 18:32:13 +00:00
- The reviewed Spanish text is kept where the English source is unchanged - New and changed texts follow the glossary and the Spanish interface
171 lines
22 KiB
JSON
171 lines
22 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 un backup 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 el backup, 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 del backup."
|
|
},
|
|
"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 del backup — 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": "El kernel de un host Proxmox se identifica con una cadena de versión como <code>6.17.13-2-pve</code>. Los dos primeros números (<strong>6.17</strong> en este ejemplo) definen la versión mayor: cuando cambian, algunos ficheros de configuración escritos para el kernel anterior pueden no ser válidos en el nuevo. Cuando la restauración detecta que el backup y el destino tienen versiones mayores de kernel distintas, el flujo se ramifica según la dirección del salto —si el backup es más antiguo o más reciente que el destino— porque los dos casos tienen modos de fallo opuestos. Los backups más recientes que el destino se restauran limpiamente tal cual (verificado en banco de pruebas con varios saltos de kernel). Los backups más antiguos que el destino necesitan un filtro para no 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 del backup 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 el backup 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 del backup es más RECIENTE que el del destino (por ejemplo: el backup 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 del backup es más ANTIGUO que el del destino (por ejemplo: el backup 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é un backup 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 el backup, 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. El backup 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 del backup, 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 cinco 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 (configuración de VM/LXC, 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 omite archivos críticos del arranque; la hidratación reaplica ajustes seleccionados: cmdline IOMMU, IDs VFIO, <code>GRUB_TIMEOUT</code> personalizado y listas de bloqueo nvidia. Se ejecuta con un kernel destino más reciente. La fusión de cmdline conserva las claves del destino y añade módulos que faltan. Los valores GRUB y archivos permitidos pueden reemplazar contenido distinto del destino. Repetir la misma entrada es idempotente.",
|
|
"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> del backup 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> del backup 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 del backup",
|
|
"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> del backup, 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 el backup."
|
|
},
|
|
"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\\treason</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."
|
|
}
|
|
]
|
|
}
|
|
}
|