Fuente:
El autor de este sencillo e ingenioso guión es iceflatline. Contiene algunas modificaciones para adaptarlo a este laboratorio
https://gnulinuxcodigo.blogspot.com/2025/03/crear-particiones-en-disco-duro-usb-con.html
Crear el pool de respaldo zbackup
zpool create -o ashift=12 \ -O compression=lz4 \ -O atime=off \ -O mountpoint=none \ backup /dev/gpt/zbackup
Conjuntos de datos zbackup
sudo zfs create -o mountpoint=none zbackup/solaris sudo zfs create -o mountpoint=none zbackup/solaris/home sudo zfs create -o mountpoint=none zbackup/solaris/home/carlos sudo zfs create -o mountpoint=none zbackup/tormenta-confiles sudo zfs create -o mountpoint=none zbackup/usr/ sudo zfs create -o mountpoint=none zbackup/usr/backup sudo zfs create -o mountpoint=none zbackup/usr/backup/docs sudo zfs create -o mountpoint=none zbackup/usr/home
Flujo de trabajo recomendado para un disco de respaldo mountpoint=none
Seguridad contra modificaciones accidentales
Evita conflictos de rutas
Comportamiento en el arranque — Con mountpoint=none ZFS no intenta montar nada del pool zbackup al arrancar, lo que acelera el boot y evita errores si el disco USB no está conectado en ese momento.
Acceso bajo demanda — Cuando se necesita recuperar algo, se monta puntualmente el dataset de interés, se hace lo que se necesita, y luego se desmonta.
Los scripts no se ven afectados — zfs receive escribe directamente al dataset sin necesidad de que esté montado. mountpoint=none no interfiere en absoluto con zfs send/receive.
carlos@tormenta:~ % zfs list -r zbackup zbackup 48.9G 1.71T 4.86M none zbackup/solaris 40.8G 1.71T 96K none zbackup/solaris/home 40.8G 1.71T 96K none zbackup/solaris/home/carlos 40.8G 1.71T 39.9G none zbackup/tormenta-confiles 800K 1.71T 800K none zbackup/usr 8.16G 1.71T 104K none zbackup/usr/backup 7.80G 1.71T 104K none zbackup/usr/backup/docs 7.80G 1.71T 7.80G none zbackup/usr/home 368M 1.71T 132M none
#!/bin/sh
### BEGIN INFO
# PROVIDE:
# REQUIRE:
# KEYWORD:
### INICIO DEL GUION
# Estas variables se nombran primero porque están anidadas en otras variables.
snap_prefix=snap
retention=15
# Se necesitan rutas completas a estas utilidades al ejecutar el script desde \
cron.
date=/bin/date
grep=/usr/bin/grep
sed=/usr/bin/sed
sort=/usr/bin/sort
xargs=/usr/bin/xargs
zfs=/sbin/zfs
src_0="zroot/home/carlos"
dst_0="zbackup/solaris/home/carlos"
host="root@192.168.88.160"
# Usar $date en lugar de date para consistencia con rutas absolutas.
today="$snap_prefix-`$date +%Y%m%d`"
yesterday="$snap_prefix-`$date -v -1d +%Y%m%d`"
snap_today="$src_0@$today"
snap_yesterday="$src_0@$yesterday"
# Patrón grep con sufijo numérico para evitar falsos positivos.
snap_old=`$zfs list -t snapshot -o name \
| $grep "${src_0}@${snap_prefix}-[0-9]" \
| $sort -r \
| $sed 1,${retention}d \
| $sort \
| $xargs -n 1`
log=/home/carlos/cronlog
# Todo el pipeline de listado remoto corre en tormenta vía SSH.
snap_old_dst_0=`ssh $host "$zfs list -t snapshot -o name \
| grep '${dst_0}@${snap_prefix}-[0-9]' \
| sort -r \
| sed 1,${retention}d \
| sort"`
# Crea una línea en blanco entre la entrada de registro anterior y esta.
echo >> $log
# Imprimir el nombre del script.
echo "zfsrep.sh" >> $log
# Imprime la fecha de hoy.
$date >> $log
# Crea una línea en blanco.
echo >> $log
# Buscar instantánea de hoy y, si no la encuentra, créala.
if $zfs list -H -o name -t snapshot \
| $sort \
| $grep "${snap_today}$" > /dev/null
then
echo "La instantánea de hoy '$snap_today' ya existe." >> $log
else
echo "Tomando la instantánea de hoy: $snap_today" >> $log
$zfs snapshot -r $snap_today >> $log 2>&1
fi
echo >> $log
# Replicar el snapshot diario (ayer) o mostrar error si falta.
if $zfs list -H -o name -t snapshot \
| $sort \
| $grep "${snap_yesterday}$" > /dev/null
then
echo "La instantánea de ayer '$snap_yesterday' existe. Continuando \
con la replicacion..." >> $log
$zfs send -R -i $snap_yesterday $snap_today \
| ssh $host $zfs receive -vuF -x mountpoint $dst_0 >> $log 2>&1
echo >> $log
echo "Replicacion completada." >> $log
else
echo "Error: Replicacion no completada. Falta la instantánea de \
ayer." >> $log
fi
echo >> $log
# Eliminar instantáneas locales más antiguas que el valor asignado a retention.
echo "Intentando destruir instantáneas antiguas $src_0..." >> $log
if [ -n "$snap_old" ]
then
echo "Destruyendo las siguientes instantáneas antiguas:" >> $log
echo "$snap_old" >> $log
$zfs list -t snapshot -o name \
| $grep "${src_0}@${snap_prefix}-[0-9]" \
| $sort -r \
| $sed 1,${retention}d \
| $sort \
| $xargs -n 1 $zfs destroy -r >> $log 2>&1
else
echo "No se pudo encontrar ninguna instantánea local para \
destruir." >> $log
fi
echo >> $log
# Purgar snaps remotos > retention
# Todo el pipeline, incluido zfs destroy, corre en tormenta vía SSH.
echo "Intentando destruir instantáneas antiguas $dst_0..." >> $log
if [ -n "$snap_old_dst_0" ]
then
echo "Destruyendo las siguientes instantáneas antiguas en $host:" >> $log
echo "$snap_old_dst_0" >> $log
ssh $host "$zfs list -t snapshot -o name \
| grep '${dst_0}@${snap_prefix}-[0-9]' \
| sort -r \
| sed 1,${retention}d \
| sort \
| xargs -n 1 $zfs destroy -r" >> $log 2>&1
else
echo "No se pudo encontrar ninguna instantánea remota para \
destruir." >> $log
fi
# Marcar el fin del script con un delimitador.
echo "**********" >> $log
### FIN DEL SCRIPT
Luego, agregue una tarea a la tabla cron bajo la cuenta del usuario. El script se ejecuta todos los días a las 22:00 (hora local):
# Ejecuta script backup cada día a las 22:00 0 22 * * * /home/carlos/bin/zfsrep.sh
Las entradas del archivo /home/carlos/cronlog se verán así:
********** zfsrep.sh Tue Apr 15 09:45:19 CEST 2025 Tomando la instantánea de hoy: zroot/home@snap-20250415 La instantánea de ayer 'zroot/home@snap-20250414' existe. \ Continuando con la replicacion... receiving incremental stream of zroot/home@snap-20250415 into \ zbackup/solaris/home/carlos@snap-20250415 received 312B stream in 0.91 seconds (341B/sec) receiving incremental stream of zroot/home/carlos@snap-20250415 \ into zbackup/solaris/home/carlos@snap-20250415 received 16.3M stream in 7.07 seconds (2.30M/sec) Replicacion completada. Intentando destruir instantáneas antiguas zroot/home... Destruyendo las siguientes instantáneas antiguas: zroot/home@snap-20250327 Intentando destruir instantáneas antiguas zbackup/solaris... No se pudo encontrar ninguna instantánea para destruir.FreeBSD es genial!.




