Entornos de arranque ZFS: la red de seguridad para actualizaciones que los usuarios de Linux ignoran

¿Te fue útil?

Todo administrador de Linux tiene una cicatriz por un “simple mantenimiento rutinario”. Kernel actualizado, initramfs reconstruido, reboot programado.
Luego la máquina vuelve… solo en la imaginación. En la realidad se queda en una shell de initramfs, o hace un bucle de arranque, o arranca pero le faltan nombres de NIC,
módulos de GPU o controladores de almacenamiento. Mientras tanto estás explicando a alguien no técnico por qué “estamos investigando” significa “estoy mirando una pantalla negra a las 2 a. m.”

Los entornos de arranque ZFS son la respuesta madura a ese dolor. No son llamativos. No son “cloud-native”.
Son brutalmente prácticos: crea una copia arrancable nueva de tu sistema raíz, actualiza esa, y si sale mal,
elige el entorno anterior en el arranque y sigue adelante. Los usuarios de Linux lo ignoran porque las distribuciones principales no lo promueven mucho,
y porque la expresión “entorno de arranque” suena a algo de Solaris que se habla en conferencias a las que no asistes.

Qué es un entorno de arranque (y qué no es)

Un entorno de arranque ZFS (BE) es una versión del sistema de archivos raíz arrancable por separado, normalmente implementada como un clon ZFS
(o un conjunto de datasets clonados juntos) más una entrada del cargador de arranque que apunte a él. Puedes mantener múltiples entornos: “actual”,
“antes-de-actualizar”, “post-actualización”, “pruebas”, “oh-no”, etc. Cada entorno es barato porque comparte bloques con su origen
mediante copy-on-write. Solo pagas por los cambios.

Lo que no es: una imagen de disco completa que copias con dd; una instantánea de VM; una copia de seguridad; un reemplazo de la gestión de configuración.
Los entornos de arranque son una red de seguridad para el cambio del sistema: actualizaciones, cambios de kernel, instalación de controladores, movimientos de libc,
refactorizaciones grandes de configuración. Te permiten fallar rápido y revertir más rápido.

La propiedad clave es esta: el rollback es una elección de arranque. No es un procedimiento de recuperación. No es arrancar desde ISO, chroot y rezar.
Si todavía puedes llegar al menú de arranque, usualmente puedes volver a un sistema funcional.

Por qué los usuarios de Linux aún se la juegan con las actualizaciones

La cultura Linux históricamente ha tratado reinstalar como un rito de paso y la recuperación ante desastres como una cuestión de habilidad.
En servidores mitigamos con canarios, blue/green, fijado de paquetes y snapshots en hipervisores. En estaciones de trabajo cruzamos los dedos y guardamos “un USB arrancable por ahí”. Ninguno de esos es tan directo como: “arranca el sistema raíz de ayer y punto”.

Hay razones prácticas para saltarse los BE en Linux:

  • El soporte de la distro es desigual. Algunas configuraciones lo hacen fluido (p. ej., ZFS-on-root de Ubuntu con ZSys en el pasado; varias herramientas comunitarias ahora),
    otras son DIY con scripts.
  • Los bootloaders son quisquillosos. GRUB + ZFS funciona, pero necesitas entender cómo encuentra datasets. systemd-boot es más limpio pero espera una partición EFI
    con kernels que pueda ver; eso cambia la historia de BE.
  • La gente confunde snapshots con entornos de arranque. Una snapshot es estupenda; una snapshot de la que puedas arrancar es mejor.
  • Root en ZFS sigue siendo “avanzado” en el ecosistema Linux. Muchas organizaciones se sienten cómodas con ZFS para datos, no para /.

Ninguna de estas es un motivo para rendirse. Son razones para diseñar tu entorno intencionalmente en lugar de esperar que los valores por defecto te salven el día del reboot.

Hechos e historia que explican el diseño

Algo de contexto hace que las decisiones de diseño parezcan menos magia y más ingeniería aburrida—mi tipo favorito.

  1. Los entornos de arranque se popularizaron en Solaris/Illumos. El flujo operativo—clonar root, actualizar el clon, reiniciar—era normal allí mucho antes de que Linux lo adoptara.
  2. ZFS se diseñó pensando en flujos administrativos. Snapshots, clones, send/receive y propiedades son de primera clase, no añadidos.
  3. GRUB adquirió conocimiento de ZFS más tarde y de forma desigual. Muchas empresas evitaron root-on-ZFS simplemente porque las herramientas de arranque inicial se retrasaron.
  4. Copy-on-write significa “copias baratas”, no “copias gratuitas”. Los BE comparten bloques hasta que los cambias; las grandes actualizaciones aún pueden consumir espacio real.
  5. Las propiedades de datasets son el plano de control. mountpoints, canmount, bootfs y propiedades de cifrado deciden si un BE es arrancable.
  6. OpenZFS se volvió un esfuerzo multiplataforma. El mismo modelo conceptual abarca illumos, FreeBSD, Linux—la herramienta de arranque varía, pero la semántica de ZFS es consistente.
  7. El initramfs de Linux se convirtió en el guardián. En muchos sistemas Linux, es initramfs (no solo el kernel) el que debe importar el pool y montar el dataset correcto.
  8. UEFI cambió la historia de dónde colocas el kernel. Algunos flujos mantienen kernels dentro del dataset raíz; otros los ponen en una partición EFI separada que todos los BE comparten.

Modelo mental práctico: datasets, snapshots, clones y bootloaders

Root-on-ZFS suele verse como un árbol de datasets

Un diseño sensato separa lo que cambia con frecuencia de lo que quieres compartir entre entornos de arranque. Quieres que la raíz del SO
sea clonable, mientras que algunos datasets deben ser persistentes entre BEs (directorios home, contenedores, imágenes de VM, datos de bases de datos).

Patrón común:

  • rpool/ROOT/<BE-name> montado en /
  • rpool/USERDATA montado en /home (compartido entre BEs)
  • rpool/var a veces dividido en datasets, pensando con cuidado en logs, caches y estado

Snapshots vs clones

Una snapshot es de solo lectura en un punto en el tiempo. Un clone es un dataset escribible creado a partir de una snapshot. La mayoría de implementaciones de BE usan clones
porque necesitas una raíz escribible para arrancar y ejecutar.

El ciclo de vida del BE es básicamente:

  1. Crear snapshot del dataset raíz actual.
  2. Clonar la snapshot con un nuevo nombre de dataset.
  3. Hacer que ese dataset sea montable como / (ajustar propiedades).
  4. Asegurar que el bootloader/initramfs pueda encontrarlo.
  5. Actualizar dentro del nuevo entorno.
  6. Reiniciar y seleccionarlo.
  7. Mantener el anterior hasta estar seguro. Luego destruirlo para recuperar espacio.

Realidad del bootloader: necesitas un puntero a “qué root”

Hay tres enfoques comunes:

  • GRUB lee ZFS y carga kernel/initrd desde ZFS. Luego la línea de comandos del kernel apunta a un dataset (o la lógica del initramfs lo selecciona).
  • GRUB carga kernel/initrd desde un /boot separado (ext4). La raíz sigue siendo ZFS; la selección del BE depende de cómo las entradas de /boot se correspondan con los datasets.
  • systemd-boot carga kernels EFI stub desde la Partición del Sistema EFI. Esto a menudo significa que tus imágenes de kernel no están dentro del BE, por lo que los BE deben gestionarse con cuidado para mantener kernel+initramfs consistentes.

No tienes que amar ninguno de estos. Solo tienes que elegir uno y probar el rollback bajo estrés, no solo bajo optimismo.

Una idea parafraseada de Werner Vogels que la gente de operaciones vive así: todo falla, y lo planificas—luego automatizas la recuperación para que no sea un evento heroico (idea parafraseada).

Tareas prácticas: comandos, salidas y las decisiones que tomas

Estos son los movimientos del día a día que hacen los BE reales. Cada tarea incluye: comando, qué significa la salida y la decisión que tomas.
Nombres de host/pool son ejemplos. Ajústalos, pero no improvises los conceptos.

Tarea 1: Confirma que tu sistema raíz es ZFS (y qué dataset es)

cr0x@server:~$ findmnt -no SOURCE /
rpool/ROOT/ubuntu_1a2b3c

Significado: Tu raíz del sistema es un dataset ZFS llamado rpool/ROOT/ubuntu_1a2b3c.
Decisión: Ese dataset (y cualquier dataset hijo montado bajo él) es la unidad que necesitas snapshotear/clonar para un BE.

Tarea 2: Inventario de pools y salud básica antes de tocar nada

cr0x@server:~$ sudo zpool status
  pool: rpool
 state: ONLINE
  scan: scrub repaired 0B in 00:06:21 with 0 errors on Tue Dec 24 03:12:14 2025
config:

        NAME        STATE     READ WRITE CKSUM
        rpool       ONLINE       0     0     0
          nvme0n1p3 ONLINE       0     0     0

errors: No known data errors

Significado: El pool está sano y fue scrubeado recientemente.
Decisión: Procede. Si ves errores o un vdev degradado, arregla eso primero; desplegar BEs en un pool enfermo es como repintar un barco que se hunde.

Tarea 3: Comprueba espacio libre para que la “copia barata” no se vuelva un fallo por disco lleno

cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint rpool
NAME                 USED  AVAIL  REFER  MOUNTPOINT
rpool                64.1G  112G    96K   /

Significado: Tienes 112G disponibles, suficiente para múltiples BEs.
Decisión: Si avail está justo, destruye BEs antiguos primero o añade capacidad. Las actualizaciones pueden inflar /usr, initramfs y caches rápidamente.

Tarea 4: Lista las propiedades del dataset raíz que afectan el arranque

cr0x@server:~$ sudo zfs get -o name,property,value -s local,received mountpoint,canmount,atime,compression rpool/ROOT/ubuntu_1a2b3c
NAME                    PROPERTY     VALUE
rpool/ROOT/ubuntu_1a2b3c mountpoint   /
rpool/ROOT/ubuntu_1a2b3c canmount     noauto
rpool/ROOT/ubuntu_1a2b3c atime        off
rpool/ROOT/ubuntu_1a2b3c compression  zstd

Significado: El dataset raíz se monta en /, pero canmount=noauto sugiere que se monta mediante lógica especial de arranque (común en configuraciones BE).
Decisión: Preserva estas propiedades al clonar; mountpoint/canmount desajustados son una trampa clásica de “arranca a initramfs”.

Tarea 5: Crea una snapshot del dataset raíz actual

cr0x@server:~$ sudo zfs snapshot rpool/ROOT/ubuntu_1a2b3c@pre-upgrade-2025w52

Significado: La snapshot existe instantáneamente; es una vista consistente en el tiempo (tan consistente como tu sistema en ejecución permita).
Decisión: Ahora tienes una línea base segura. Siguiente: clónala en un nuevo BE para los cambios.

Tarea 6: Verifica que la snapshot exista y cuánto “cuesta”

cr0x@server:~$ sudo zfs list -t snapshot -o name,used,refer | grep pre-upgrade
rpool/ROOT/ubuntu_1a2b3c@pre-upgrade-2025w52  0B  32.4G

Significado: La snapshot usa 0B inicialmente porque referencia bloques existentes; crecerá a medida que el dataset en vivo cambie.
Decisión: Es seguro mantener la snapshot mientras actualizas el clon. Si ves USED grande inmediatamente, probablemente has snapshotado un dataset con mucha actividad o bloques ya eliminados que se están reteniendo.

Tarea 7: Clona la snapshot en un nuevo dataset de entorno de arranque

cr0x@server:~$ sudo zfs clone rpool/ROOT/ubuntu_1a2b3c@pre-upgrade-2025w52 rpool/ROOT/ubuntu_1a2b3c-upg

Significado: Ahora tienes un dataset escribible rpool/ROOT/ubuntu_1a2b3c-upg que comparte bloques con el original.
Decisión: Ajusta mountpoint/canmount correctamente y asegúrate de que el sistema de arranque pueda apuntar a este dataset.

Tarea 8: Ajusta propiedades en el nuevo BE para que pueda montarse como / cuando se seleccione

cr0x@server:~$ sudo zfs set mountpoint=/ canmount=noauto rpool/ROOT/ubuntu_1a2b3c-upg

Significado: El clon tiene el mismo comportamiento de montaje que tu dataset raíz existente.
Decisión: Mantén solo un BE realmente montado en / en tiempo de ejecución. Si accidentalmente pones varios datasets con canmount=on y mountpoint /, crearás una pelea en tiempo de arranque.

Tarea 9: Monta el nuevo BE en algún lugar y haz chroot para la actualización

cr0x@server:~$ sudo mkdir -p /mnt/be-upg
cr0x@server:~$ sudo mount -t zfs rpool/ROOT/ubuntu_1a2b3c-upg /mnt/be-upg
cr0x@server:~$ sudo mount --bind /dev /mnt/be-upg/dev
cr0x@server:~$ sudo mount --bind /proc /mnt/be-upg/proc
cr0x@server:~$ sudo mount --bind /sys /mnt/be-upg/sys
cr0x@server:~$ sudo chroot /mnt/be-upg /bin/bash
root@server:/# cat /etc/os-release | head -2
PRETTY_NAME="Ubuntu 24.04.1 LTS"
NAME="Ubuntu"

Significado: Ahora estás operando dentro del sistema raíz del nuevo BE.
Decisión: Realiza las actualizaciones aquí, no en la raíz que está en ejecución, para que el rollback permanezca limpio.

Tarea 10: Ejecuta una actualización controlada dentro del nuevo BE y confirma que se construyeron kernels/initramfs

cr0x@server:~$ sudo chroot /mnt/be-upg /bin/bash -lc "apt update && apt -y full-upgrade"
...output...
Setting up linux-image-6.8.0-45-generic ...
update-initramfs: Generating /boot/initrd.img-6.8.0-45-generic
Processing triggers for grub-pc ...
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-6.8.0-45-generic
Found initrd image: /boot/initrd.img-6.8.0-45-generic
done

Significado: El entorno contiene un kernel e initramfs y se actualizó la configuración de arranque.
Decisión: Si no ves generación de initramfs o triggers de actualización del bootloader, detente. Arregla eso antes de reiniciar; un BE sin artefactos de arranque es una pieza de museo, no una ruta de recuperación.

Tarea 11: Confirma qué dataset intentará arrancar por defecto el pool (bootfs)

cr0x@server:~$ sudo zpool get bootfs rpool
NAME   PROPERTY  VALUE                    SOURCE
rpool  bootfs    rpool/ROOT/ubuntu_1a2b3c  local

Significado: El bootfs del pool apunta al BE actual.
Decisión: Si tu flujo de arranque respeta bootfs, ponlo en el nuevo BE antes de reiniciar. Si tu flujo ignora bootfs y usa entradas del GRUB, gestionarás la selección vía el bootloader en su lugar.

Tarea 12: Cambia el entorno de arranque por defecto modificando bootfs (cuando aplique)

cr0x@server:~$ sudo zpool set bootfs=rpool/ROOT/ubuntu_1a2b3c-upg rpool
cr0x@server:~$ sudo zpool get bootfs rpool
NAME   PROPERTY  VALUE                        SOURCE
rpool  bootfs    rpool/ROOT/ubuntu_1a2b3c-upg  local

Significado: El pool ahora prefiere arrancar en el BE actualizado.
Decisión: Reinicia en el nuevo BE. Mantén el BE previo intacto hasta tener múltiples arranques exitosos y los servicios luzcan normales.

Tarea 13: Después del reinicio, verifica que estás en el BE previsto

cr0x@server:~$ findmnt -no SOURCE /
rpool/ROOT/ubuntu_1a2b3c-upg

Significado: Estás ejecutando desde el BE actualizado.
Decisión: Ahora puedes validar: red, almacenamiento, agentes, GPU, cualquier cosa que históricamente falle en tu flota.

Tarea 14: Compara uso de espacio entre BEs y decide qué podar

cr0x@server:~$ sudo zfs list -o name,used,refer,origin rpool/ROOT
NAME                         USED  REFER  ORIGIN
rpool/ROOT                   128K   96K   -
rpool/ROOT/ubuntu_1a2b3c      6.4G  32.4G  -
rpool/ROOT/ubuntu_1a2b3c-upg  2.1G  33.0G  rpool/ROOT/ubuntu_1a2b3c@pre-upgrade-2025w52

Significado: El BE actualizado actualmente diverge en ~2.1G del original; el resto está compartido.
Decisión: Mantén al menos un fallback conocido bueno. Borra BEs antiguos una vez que estés confiado y necesites espacio.

Tarea 15: Revertir seleccionando el BE anterior (método bootfs del pool)

cr0x@server:~$ sudo zpool set bootfs=rpool/ROOT/ubuntu_1a2b3c rpool
cr0x@server:~$ sudo reboot

Significado: El próximo arranque preferirá el dataset raíz anterior.
Decisión: Usa esto cuando el nuevo BE está roto pero el antiguo aún arranca. Después de revertir, puedes diagnosticar el BE fallido desde un entorno seguro.

Tarea 16: Si necesitas destruir un BE fallido limpiamente, hazlo en el orden correcto

cr0x@server:~$ sudo zfs destroy rpool/ROOT/ubuntu_1a2b3c-upg
cr0x@server:~$ sudo zfs destroy rpool/ROOT/ubuntu_1a2b3c@pre-upgrade-2025w52

Significado: El clon debe destruirse antes que su snapshot origen (o obtendrás un error de dependencia).
Decisión: No “limpies” la snapshot mientras un clon BE dependa de ella. ZFS te detendrá, pero el error suele aparecer cuando ya estás molesto.

Chiste #1: Las snapshots de ZFS son como el café de la oficina: a todo el mundo le encantan hasta que alguien pregunta quién va a limpiar las antiguas.

Guía de diagnóstico rápido

Los problemas con entornos de arranque rara vez son misteriosos. Suelen ser un pequeño desajuste entre: lo que el bootloader piensa que es la raíz,
lo que initramfs puede importar, y qué datasets ZFS están configurados para montar. El truco es comprobar las cosas correctas en el orden correcto.

Primero: ¿se puede importar el pool y está sano?

Si el pool está degradado, faltan dispositivos o falla la importación en initramfs, nada más importa aún.

cr0x@server:~$ sudo zpool import
   pool: rpool
     id: 16084073626775123456
  state: ONLINE
 action: The pool can be imported using its name or numeric identifier.
 config:

        rpool        ONLINE
          nvme0n1p3  ONLINE

Interpretación: El pool es importable en el entorno actual.
Decisión: Si esto falla en initramfs pero funciona en el sistema en ejecución, probablemente te faltan módulos ZFS en initramfs, IDs de dispositivos o manejo de claves de cifrado.

Segundo: ¿qué considera el sistema que es “/”?

Comprueba el dataset raíz activo y el puntero bootfs del pool.

cr0x@server:~$ findmnt -no SOURCE /
rpool/ROOT/ubuntu_1a2b3c-upg
cr0x@server:~$ sudo zpool get bootfs rpool
NAME   PROPERTY  VALUE                        SOURCE
rpool  bootfs    rpool/ROOT/ubuntu_1a2b3c-upg  local

Interpretación: Bootfs y la raíz montada coinciden. Bien.
Decisión: Si difieren, puede que hayas arrancado un BE distinto del que crees (común cuando las entradas del GRUB apuntan a otro sitio).

Tercero: ¿son consistentes las propiedades de montaje de los datasets?

cr0x@server:~$ sudo zfs get -r -o name,property,value mountpoint,canmount rpool/ROOT
NAME                         PROPERTY   VALUE
rpool/ROOT                   mountpoint none
rpool/ROOT                   canmount   off
rpool/ROOT/ubuntu_1a2b3c      mountpoint /
rpool/ROOT/ubuntu_1a2b3c      canmount   noauto
rpool/ROOT/ubuntu_1a2b3c-upg  mountpoint /
rpool/ROOT/ubuntu_1a2b3c-upg  canmount   noauto

Interpretación: Múltiples BEs comparten mountpoint /, pero usan canmount=noauto, lo cual es normal para montado estilo BE.
Decisión: Si ves canmount=on en más de un dataset con mountpoint /, arréglalo antes de reiniciar.

Cuarto: si el arranque falla, confirma que initramfs puede ver ZFS y el pool

Desde una shell de initramfs (o un entorno de rescate), comprueba presencia de módulos e intenta la importación.

cr0x@server:~$ lsmod | grep zfs
zfs                  4980736  5
zunicode              335872  1 zfs
znvpair               126976  2 zfs
zcommon                98304  1 zfs
icp                   315392  1 zfs
spl                   135168  5 zfs,icp
cr0x@server:~$ zpool import -N rpool
cr0x@server:~$ zfs list rpool/ROOT
NAME        USED  AVAIL  REFER  MOUNTPOINT
rpool/ROOT  128K  112G    96K   none

Interpretación: Módulos ZFS cargados, pool importado sin montar datasets.
Decisión: Si faltan módulos, reconstruye initramfs desde un BE funcional. Si falla la importación del pool, sigue pistas de nombres de dispositivo, drivers faltantes o cifrado.

Quinto: identifica rápidamente el verdadero cuello de botella—¿bootloader, initramfs o userspace?

Si puedes llegar al kernel e initramfs pero fallas antes de userspace: suele ser “no puede montar root” (selección de dataset, importación, claves).
Si llegas a userspace pero los servicios fallan: es una regresión normal de actualización; el rollback sigue siendo tu amigo, pero depuras como cualquier otro problema de servicio.

Errores comunes: síntoma → causa raíz → solución

1) Síntoma: arranca a initramfs con “cannot import rpool”

Causa raíz: initramfs sin módulos ZFS o sin el hostid/cache correcto para la importación; a veces una actualización de kernel no reconstruyó initramfs correctamente en el nuevo BE.

Solución: Arranca un BE conocido bueno y reconstruye initramfs y actualiza el bootloader desde el BE objetivo.

cr0x@server:~$ sudo chroot /mnt/be-upg /bin/bash -lc "update-initramfs -u -k all && update-grub"
...output...
update-initramfs: Generating /boot/initrd.img-6.8.0-45-generic
Generating grub configuration file ...
done

2) Síntoma: el sistema arranca, pero /home está vacío o equivocado

Causa raíz: Clonaste /home dentro del BE cuando querías que fuera compartido, o cambiaste mountpoints y ahora el dataset persistente esperado no está montado.

Solución: Separa datasets persistentes de datasets BE. Asegura que /etc/fstab o las propiedades de montaje ZFS monten el dataset compartido consistentemente.

cr0x@server:~$ sudo zfs list -o name,mountpoint | egrep 'USERDATA|home'
rpool/USERDATA          /home

3) Síntoma: GRUB muestra solo una entrada; no puedo elegir el BE antiguo

Causa raíz: La generación de la configuración de GRUB no enumera los BEs, o los kernels/initrds no están presentes/consistentes para cada BE.

Solución: Adopta una estrategia consistente de ubicación de kernels y una herramienta/flujo de BE que se integre con tu bootloader. Como mínimo, regenera GRUB desde un BE que tenga los scripts correctos habilitados.

cr0x@server:~$ sudo grub-mkconfig -o /boot/grub/grub.cfg
Generating grub configuration file ...
done

4) Síntoma: “dataset is busy” al destruir un BE antiguo

Causa raíz: Estás intentando destruir la raíz actualmente montada, o algún proceso tiene un montaje dentro del BE montado en otro sitio.

Solución: Verifica montajes y desmonta el punto que usaste para operaciones chroot; destruye clones antes que snapshots origen.

cr0x@server:~$ mount | grep be-upg
rpool/ROOT/ubuntu_1a2b3c-upg on /mnt/be-upg type zfs (rw,xattr,noacl)
cr0x@server:~$ sudo umount /mnt/be-upg

5) Síntoma: el rollback “funciona” pero los servicios se comportan de forma inconsistente

Causa raíz: Compartes estado mutable (como /var/lib, imágenes de contenedores o bases de datos) entre BEs sin darte cuenta. El userspace antiguo ahora ve estado nuevo.

Solución: Decide deliberadamente qué se comparte entre BEs. O bien mantén el estado en datasets dedicados con compatibilidad en mente, o snapshotea/clona el estado junto con el BE para actualizaciones riesgosas.

6) Síntoma: el BE actualizado consume mucho más espacio del esperado

Causa raíz: Mantienes una snapshot de larga vida que ahora retiene muchos bloques liberados; o actualizaste paquetes grandes y caches, divergiendo mucho.

Solución: Podar snapshots/BEs antiguos; mover caches a datasets separados con poda agresiva; evita mantener snapshots “pre-upgrade” durante meses.

cr0x@server:~$ sudo zfs list -t snapshot -o name,used | sort -h | tail -5
rpool/ROOT/ubuntu_1a2b3c@pre-upgrade-2025w52  9.8G

Chiste #2: La forma más rápida de aprender sobre bootloaders es romper uno un viernes—de repente tendrás todo el fin de semana para estudiarlo.

Tres microhistorias corporativas desde la trinchera

Microhistoria 1: El incidente causado por una suposición equivocada

Una empresa mediana usaba ZFS para “datos”, pero no para el SO. Luego un equipo creó una nueva puerta de enlace analítica que sí ejecutaba root-on-ZFS,
porque al ingeniero le gustaban las snapshots y lo habían quemado antes con malas actualizaciones. Se lanzó a producción con una suposición clave:
“Si GRUB puede leer ZFS, los rollbacks son triviales.”

La primera gran actualización de kernel salió mal. No catastróficamente—solo lo suficiente. El nuevo kernel cambió el orden de drivers en el arranque,
lo que alteró el timing de descubrimiento de dispositivos. El pool a veces se importaba, a veces no, según la rapidez con la que el dispositivo NVMe apareciera.
Intentaron “revertir” seleccionando la entrada del BE antiguo. La máquina aun así terminó en initramfs. Mismo síntoma. Mismo pánico.

La suposición equivocada fue creer que el BE era la única pieza móvil. No lo era. El initramfs se construyó dentro del BE actualizado y se almacenó
de forma compartida en una partición /boot que todos los BE usaban. Cuando arrancaron el BE antiguo, seguían cargando el initramfs nuevo.
Así que el rollback no era rollback; era un disfraz.

La solución no fue complicada, pero requirió admitir la arquitectura real. Cambiaron el flujo para que cada BE tuviera los artefactos kernel+initramfs
que le correspondían, y pusieron una verificación post-actualización simple: “¿tiene este BE el kernel/initramfs que creemos que tiene,
y la entrada de arranque apunta a ellos?” Después de eso, el rollback hizo lo que decía la etiqueta.

Microhistoria 2: La optimización que salió mal

Otra organización tenía una flota de estaciones de trabajo de desarrolladores con root-on-ZFS y BEs. El equipo de flota se puso ambicioso: quería que las actualizaciones fueran rápidas,
así que ajustaron ZFS agresivamente. Cambiaron compresión, recordsize, y deshabilitaron atime (bien) mientras experimentaban con caching
y trimming. El objetivo era hacer operaciones de upgrade y compilaciones más rápidas.

El problema no fue inmediato. Apareció como un fuego lento: las máquinas empezaron a quedarse sin espacio “aleatoriamente”, mayormente justo después de grandes actualizaciones.
La gente culpaba logs, navegadores y sistemas de construcción. El almacenamiento parecía encantado. Algunas máquinas tenían mucho espacio libre un día y se quedaban sin él al siguiente,
sin archivos nuevos evidentes.

El culpable fue una política, no un bug. Mantuvieron muchos BEs y snapshots por “seguridad”, pero no presupuestaron espacio para la divergencia. Tras las actualizaciones,
las snapshots antiguas retenían bloques pre-actualización. Las optimizaciones empeoraron la rotura porque más contenido se reescribía durante las actualizaciones, y
también colocaron caches en datasets que sin querer formaban parte del árbol BE.

La lección: “guardar todo para siempre” no es estrategia de resiliencia; es una falla en cámara lenta. Implementaron retención:
conservar los últimos N BEs exitosos, mantener un “golden” mensual y borrar el resto. Además movieron caches de alta rotación fuera del árbol BE.
Mejoró el rendimiento y la previsibilidad.

Microhistoria 3: La práctica aburrida pero correcta que salvó el día

Una empresa financiera ejecutaba unas pocas máquinas Linux críticas con root-on-ZFS. Nada glamuroso: un par de servicios internos,
algunas bases de datos y los agentes habituales de monitorización. Su SRE líder insistía en una práctica aburrida:
antes de cualquier actualización, crear un nuevo BE; después de la actualización, requerir dos reinicios limpios y una lista de verificación de servicios antes de eliminar el BE antiguo.

Un día una actualización introdujo una regresión sutil en un driver de red. No impidió el arranque. No mató la máquina.
Provocó pérdida de paquetes intermitente bajo carga, que es el tipo de bug que hace desconfiar a todos de la realidad. La monitorización mostró picos.
Los servicios afectados estaban “mayormente bien”, excepto cuando no lo estaban.

El equipo no depuró en producción. Revirtieron al BE anterior, se estabilizaron y luego reprodujeron el comportamiento en el BE actualizado
durante horas de trabajo. Como el BE actualizado aún existía, pudieron arrancar en él intencionalmente y probar, en lugar de intentar resucitar
un estado que había sido sobrescrito.

El impacto de la incidencia se mantuvo pequeño, principalmente porque el rollback era una acción de rutina, no un último recurso. La regla aburrida—dos reinicios limpios y una checklist—
significó que tenían un BE conocido bueno listo cuando apareció la regresión. Sin heroísmos. Sin arqueología nocturna en /var/log.

Listas de verificación / plan paso a paso

Plan A: Adoptar entornos de arranque para una única máquina (estación o servidor)

  1. Verifica root-on-ZFS y el layout de datasets. Confirma que findmnt / muestra un dataset bajo rpool/ROOT.
  2. Decide qué debe compartirse. Usualmente: /home, posiblemente /var/lib para servicios seleccionados, pero con cuidado.
  3. Decide el mecanismo de selección de arranque. bootfs del pool, entradas del GRUB, o una herramienta BE que se integre con tu distro.
  4. Haz una prueba en seco sin cambiar paquetes. Crea snapshot, clona, móntala, haz chroot, luego sal y destruye.
  5. Realiza una actualización real en el clon. Las actualizaciones de kernel son el objetivo; inclúyelas.
  6. Reinicia y valida. Confirma dataset activo. Ejecuta chequeos de servicios.
  7. Practica el rollback. No esperes a un incidente para descubrir que tu rollback es teórico.
  8. Configura retención. Mantén un número pequeño de BEs; borra el resto según horario.

Plan B: Operacionalizar para una pequeña flota

  1. Estandariza nombres. Los humanos lo leerán a las 3 a. m. Usa nombres como prod-2025w52-kernel, no “clone1”.
  2. Define la política de “datasets compartidos”. Documenta qué puntos de montaje están dentro del árbol BE y cuáles son persistentes.
  3. Automatiza creación y limpieza. Los BE sin retención se convierten en una fuga de espacio con placa.
  4. Haz del rollback parte de la respuesta a incidentes. Revierte primero cuando esté en juego la disponibilidad; depura después en entorno controlado.
  5. Prueba actualizaciones del bootloader. La deriva de la flota suele aparecer aquí: diferentes versiones de GRUB, distintos layouts EFI, distinto comportamiento.
  6. Monitoriza espacio de pool y bloat de snapshots. Alerta sobre crecimiento de used en zfs list -t snapshot y sobre poco espacio libre.

Plan C: Simulacro de recuperación (cuando ya lo rompiste)

  1. En el menú de arranque, intenta seleccionar el BE anterior (si está disponible). Si funciona, estabiliza y diagnostica desde ahí.
  2. Si aterrizas en initramfs, intenta importar el pool con zpool import -N y listar datasets con zfs list.
  3. Monta manualmente el dataset raíz previsto en modo solo lectura para inspeccionar logs y configuración.
  4. Arranca un entorno de rescate que soporte ZFS si es necesario, luego apunta bootfs al dataset conocido bueno y reconstruye initramfs/GRUB.

Preguntas frecuentes

1) ¿Los entornos de arranque ZFS son lo mismo que las snapshots ZFS?

No. Una snapshot es una vista en un punto en el tiempo. Un entorno de arranque es un sistema raíz arrancable, normalmente un clon de una snapshot más integración con el arranque.
Las snapshots son ingredientes; los BE son la comida.

2) ¿Los entornos de arranque reemplazan a las copias de seguridad?

Absolutamente no. Los BE son locales, están en el mismo pool y sujetos al mismo fallo de hardware. Son para rollback de actualizaciones, no para recuperación ante desastres.

3) ¿Cuántos entornos de arranque debería mantener?

Mantén un pequeño número de conocidos buenos: típicamente 2–5. Más que eso sin una política de retención es una fuga de almacenamiento que descubrirás en la próxima actualización.

4) ¿Qué debería compartirse entre entornos de arranque?

Típicamente /home. Para servidores, los datos de servicios con estado deberían vivir en datasets dedicados fuera del árbol BE.
Compartir /var íntegramente es tentador y a menudo incorrecto; divídelo con intención.

5) ¿Puedo usar entornos de arranque si mi kernel e initramfs viven en una partición EFI?

Sí, pero ten cuidado: si todos los BE comparten los mismos archivos de kernel/initramfs, tu rollback puede no revertir la pila de arranque temprana.
Alinea tus artefactos de arranque con el BE o acepta que el rollback sea “solo userspace”, lo cual es más débil.

6) ¿Cuál es el flujo mínimo viable de BE en Linux?

Snapshotear la raíz actual, clonarla, chroot en el clon para actualizar, asegurar que bootloader/initramfs coincidan, reiniciar en el clon.
Mantén el dataset raíz antiguo intacto hasta confiar en el nuevo.

7) ¿Qué rompe más a menudo los entornos de arranque?

Propiedades de montaje desajustadas (mountpoint/canmount), entradas del bootloader apuntando al dataset equivocado, e initramfs que no puede importar el pool
(módulos, hostid, claves de cifrado, descubrimiento de dispositivos).

8) ¿Cómo sé si las snapshots están reteniendo demasiado espacio?

Comprueba los valores USED de las snapshots. Si las snapshots antiguas han crecido mucho, están fijando bloques antiguos que de otro modo se liberarían.

cr0x@server:~$ sudo zfs list -t snapshot -o name,creation,used | sort -k3 -h | tail -10
rpool/ROOT/ubuntu_1a2b3c@pre-upgrade-2025w52  Tue Dec 24 10:01  9.8G

9) ¿Es root-on-ZFS demasiado arriesgado para producción?

No es “demasiado arriesgado”. Es “debes tratar el arranque temprano como parte de tu sistema”. Si no puedes probar actualizaciones de bootloader/initramfs y practicar rollback,
entonces sí, es arriesgado—porque tú lo hiciste así.

10) ¿Cuál es el método de rollback más rápido cuando “estoy caído”?

Si tu menú de arranque lista BEs, elige la última entrada conocida buena. Si tu configuración usa bootfs, arranca un entorno de rescate y apunta bootfs de nuevo
al dataset previo, luego reinicia.

Próximos pasos que realmente puedes hacer esta semana

Si usas Linux y actualizas sistemas, necesitas una historia de rollback que no implique un USB en vivo y arrepentimiento. Los entornos de arranque ZFS son esa historia,
siempre que respetes la cadena de arranque: propiedades de dataset, initramfs y entradas del bootloader deben coincidir sobre qué significa “root”.

Haz esto a continuación:

  1. En una máquina, identifica tu dataset raíz y crea un clon BE antes de la próxima actualización.
  2. Practica el rollback a propósito mientras nada está en llamas. Confirma que puedes arrancar en ambos sentidos.
  3. Escribe una regla de retención y aplícala. El espacio no es infinito, y tampoco tu paciencia.
  4. Estandariza un layout donde el estado persistente viva fuera de rpool/ROOT.

Cuando la próxima actualización te muerda—y lo hará—tendrás una opción tranquila: reiniciar a ayer. Luego depura como un profesional, a la luz del día, con el café todavía caliente.

← Anterior
Diseño de documentación sin frameworks: barra lateral fija, contenido y TOC derecho con CSS Grid
Siguiente →
Proxmox «sistema de archivos del clúster no listo»: por qué ocurre y cómo solucionarlo

Deja un comentario