Saturday, January 11, 2020

PSA -- A word about backups.

Backups are important.

RAID is not a backup!!!

ZFS provides redundancy features much better than traditional RAID, however like RAID, it is not a backup solution in itself.  ZFS does however provide features that make it easy to backup a ZFS dataset.  I have been periodically backing up the LFS system I am building to an external hard drive, and thought I should share how those backups are being done.

 

Current LFS backups.

 

Current zpools.

I have two zpools on my LFS build host system:
 livecd gentoo # zpool list  
 NAME           SIZE ALLOC  FREE EXPANDSZ  FRAG  CAP DEDUP HEALTH ALTROOT  
 gentooScratch 3.72G 3.34G  391M        -   65%  89% 1.00x ONLINE -  
 rootPool       119G 21.2G 97.8G        -    9%  17% 1.00x ONLINE -  
   

The gentooScratch is a small file backed pool on the gentoo boot thumb drive that contains build-host persistence changes needed across reboots.  This includes home directory, and scripts and source needed to perform the LFS bootstrap steps.

The rootPool is a pool backed by a single partition on one of the installed M.2 NVME drive.  It contains all the LFS base source downloads, and the LFS target partition $LFS.

 

Preparing for backup.

Zfs provides features that make for easy backups.  This starts with using snapshots.  A snapshot records the exact state of the filesystem at the time the snapshot was taken.

 livecd gentoo # zfs snapshot -r gentooScratch@`date +backup_%Y%m%d_%H%M`  
 livecd gentoo # zfs snapshot -r rootPool@`date +backup_%Y%m%d_%H%M`  

The recursive option on the snapshot command (-r) for the entire pool will create snapshots for every file system in the pool.

I have also mounted an external USB hard drive formatted as ext4 under /mnt/backups and created a new date based directory '2019-01-10' under the backup directory.

 

Performing the backup.

 livecd gentoo # zfs send -R gentooScratch/persistentHomeGentoo@backup_20200111_0116 > /mnt/backups/2019-01-10/persistentHomeGentoo.zfs  
 livecd gentoo # zfs send -R gentooScratch/persistentPortageDistfiles@backup_20200111_0116 > /mnt/backups/2019-01-10/persistentPortageDistfiles.zfs  
 livecd gentoo # zfs send -R gentooScratch/persistentPortageTmp@backup_20200111_0116 > /mnt/backups/2019-01-10/persistentPortageTmp.zfs  
 livecd gentoo # zfs send -R gentooScratch/scripts@backup_20200111_0116 > /mnt/backups/2019-01-10/scripts.zfs  
 livecd gentoo # zfs send -R gentooScratch/sources@backup_20200111_0116 > /mnt/backups/2019-01-10/sources.zfs  
 livecd gentoo # zfs send -R rootPool/root_fs@backup_20200111_0116 > /mnt/backups/2019-01-10/rootPool-root_fs_recursive.zfs  
 livecd gentoo # cd /mnt/backups/2019-01-10/  
 livecd 2019-01-10 # ls -lh *  
 -rw-r--r-- 1 root root 3.3G Jan 11 01:24 persistentHomeGentoo.zfs  
 -rw-r--r-- 1 root root 31M Jan 11 01:25 persistentPortageDistfiles.zfs  
 -rw-r--r-- 1 root root 86K Jan 11 01:26 persistentPortageTmp.zfs  
 -rw-r--r-- 1 root root 21G Jan 11 01:32 rootPool-root_fs_recursive.zfs  
 -rw-r--r-- 1 root root 659K Jan 11 01:27 scripts.zfs  
 -rw-r--r-- 1 root root 74M Jan 11 01:28 sources.zfs  
 livecd 2019-01-10 #   

The 'zfs send' command creates a stream of data that can be used to reconstruct the file system up to the snapshot that was sent.  The '-R' option is a recursive option that will include all descendant data sets.

As as an example the 'zfs send -R gentooScratch/sources@backup_20200111_0116 > /mnt/backups/2019-01-10/sources.zfs' command performs a full backup from the creation of the sources file system, and all descendant filesystems, up to the snapshot I made in the preparation step above which got labeled as 'backup_20200111_0116'.  This backup should contain the following files systems and mount points: 

 ZFS File System                             Mount Point
 gentooScratch/sources                       /gentooScratch/sources  
 gentooScratch/sources/gentoo                /gentooScratch/sources/gentoo  
 gentooScratch/sources/gentoo/cpuid2cpuflags /gentooScratch/sources/gentoo/cpuid2cpuflags  
 gentooScratch/sources/lfs_book              /gentooScratch/sources/lfs_book  

And can be seen in the `ls -lh` command performed in the destination backup directory:
-rw-r--r-- 1 root root 74M Jan 11 01:28 sources.zfs

I go on and use the xz compression command so that my backups take less space on my backup drive.
 livecd 2019-01-10 # xz -v9eT 0 *.zfs  
 persistentHomeGentoo.zfs (1/6)  
  100 %   2308.9 MiB / 3305.7 MiB = 0.698  21 MiB/s    2:34         
 persistentPortageDistfiles.zfs (2/6)  
  100 %     28.0 MiB / 30.0 MiB = 0.933  2.7 MiB/s    0:10         
 persistentPortageTmp.zfs (3/6)  
  100 %      7632 B / 85.0 KiB = 0.088                    
 rootPool-root_fs_recursive.zfs (4/6)  
  100 %     14.6 GiB / 20.5 GiB = 0.709  24 MiB/s   14:48         
 scripts.zfs (5/6)  
  100 %    59.6 KiB / 658.3 KiB = 0.090                    
 sources.zfs (6/6)  
  100 %    5623.1 KiB / 73.9 MiB = 0.074  2.7 MiB/s    0:27    livecd 2019-01-10 #


A backup is not a backup if it can't be restored!!!

Testing that the backup can be restored.

Preparing a restore location.

The first step needed to test that a backup can be restored is a place to restore the backup to.  Normally a backup would be restored to it's original location.  However for this we are
  1. Testing the backup
  2. Original system the backup came from is still functioning with original data.
For now, to demonstrate the restore and test,  I am using a currently unused HDD that will eventually become part of my LFS server's data pool.
 livecd gentoo # zpool create -o ashift=12 -o comment="Backups Testing Area" -o altroot="/backups" tempTestDataPool /dev/sdg  

 livecd gentoo # zpool list  
 NAME               SIZE  ALLOC    FREE EXPANDSZ  FRAG  CAP DEDUP HEALTH ALTROOT  
 gentooScratch     3.72G  3.35G    377M        -   65%  90% 1.00x ONLINE -  
 rootPool           119G  21.3G   97.7G        -    9%  17% 1.00x ONLINE -  
 tempTestDataPool  2.72T   288K   2.72T        -    0%   0% 1.00x ONLINE /backups
 
 livecd gentoo # zpool status  
    pool: gentooScratch  
   state: ONLINE  
    scan: none requested  
  config:  
     NAME                                        STATE   READ WRITE CKSUM  
     gentooScratch                               ONLINE     0     0     0  
       /mnt/cdrom/scratch/LFSBootstrap/disk1.img ONLINE     0     0     0  
  errors: No known data errors  
   
    pool: rootPool  
   state: ONLINE  
    scan: none requested  
  config:  
     NAME                                        STATE   READ WRITE CKSUM  
     rootPool                                    ONLINE     0     0     0  
      nvme0n1p6                                  ONLINE     0     0     0  
  errors: No known data errors  
   
    pool: tempTestDataPool  
   state: ONLINE  
    scan: none requested  
  config:  
     NAME                                        STATE   READ WRITE CKSUM  
     tempTestDataPool                            ONLINE     0     0     0  
      sdg                                        ONLINE     0     0     0  
  errors: No known data errors  
 livecd gentoo #   
   

The 'altroot' option is important, since my restore test location is on the same box, and I don't want the restored filesystem to attempt to mount over the original source location.  With the altroot value, all mount points of filesystems in this zpool will be mounted relative to that altroot location, instead of the original location.

Now create file system locations that the backups can be restored to:

 livecd gentoo # zfs create -o mountpoint=/backupPool tempTestDataPool/backups  
 livecd gentoo # zfs create tempTestDataPool/backups/scratch  
 livecd gentoo # zfs create tempTestDataPool/backups/scratch/home   
 livecd gentoo # zfs create tempTestDataPool/backups/scratch/dist  
 livecd gentoo # zfs create tempTestDataPool/backups/scratch/tmp   
 livecd gentoo # zfs create tempTestDataPool/backups/scratch/scripts  
 livecd gentoo # zfs create tempTestDataPool/backups/scratch/src    
 livecd gentoo # zfs create tempTestDataPool/backups/root  
 livecd gentoo # zfs create tempTestDataPool/backups/root/all_root_fs_backup
 livecd gentoo # zfs mount -a livecd gentoo # ls /backupPool/
[Note no file systems under the specified mount point of /backupPool]
 livecd gentoo # ls /backups/ 
 backupPool tempTestDataPool  
[Note the actual filesystems get mounted under the '/backups/' altroot]
 livecd gentoo #   

Performing a restore.

Now I will use the 'zfs receive' command to restore the data.

 livecd gentoo # ls /mnt/backups/2019-01-10/  
 persistentHomeGentoo.zfs.xz    persistentPortageTmp.zfs.xz    scripts.zfs.xz  
 persistentPortageDistfiles.zfs.xz rootPool-root_fs_recursive.zfs.xz sources.zfs.xz  
 livecd gentoo # xzcat /mnt/backups/2019-01-10/persistentHomeGentoo.zfs.xz | zfs receive -F tempTestDataPool/backups/scratch/home  
 livecd gentoo # xzcat /mnt/backups/2019-01-10/persistentPortageTmp.zfs.xz | zfs receive -F tempTestDataPool/backups/scratch/tmp  
 livecd gentoo # xzcat /mnt/backups/2019-01-10/scripts.zfs.xz | zfs receive -F tempTestDataPool/backups/scratch/scripts  
 livecd gentoo # xzcat /mnt/backups/2019-01-10/persistentPortageDistfiles.zfs.xz | zfs receive -F tempTestDataPool/backups/scratch/dist  
 livecd gentoo # xzcat /mnt/backups/2019-01-10/rootPool-root_fs_recursive.zfs.xz | zfs receive -F tempTestDataPool/backups/root/all_root_fs_backup  
 livecd gentoo # xzcat /mnt/backups/2019-01-10/sources.zfs.xz | zfs receive -F tempTestDataPool/backups/scratch/src    
 livecd gentoo # ls /backups
 backupPool  home  tempTestDataPool  tmp  usr   
 livecd gentoo # ls /backups/backupPool/root/all_root_fs_backup/
 esp  home  opt  sources  tmp  usr livecd gentoo #

For each of the 5 file systems I backed up above, I xzcat (to decompress the backup file) and pipe the data stream into the 'zfs receive' command.  The '-F' option forces the restore, overwriting any existing data with the version from the backup.  I also specify the zpool and zfs filesystem location I want to restore each backup to.  I did a quick ls to see the restored locations, and the recieve commands completed without any errors, so I can be decently confident that the backup was good.

Validating the restore.

Even though I am confident that the backup was good, I will go through the procedure of validating the files to ensure that my backup method is working.

The first backup to verify is the persistentHomeGentoo backup.  Performing my zfs list, looking for home I see the following:

 livecd gentoo # zfs list | grep -i home  
 gentooScratch/persistentHomeGentoo                                 3.17G  257M  714M /home/gentoo  
 rootPool/root_fs/home                                              3.95G 94.0G   96K /rootPool/root_fs/home  
 rootPool/root_fs/home/gentooExtra                                  3.95G 94.0G 3.95G /home/gentoo/extraSpace  
 tempTestDataPool/backups/root/all_root_fs_backup/home              3.95G 2.61T   96K /backups/backupPool/root/all_root_fs_backup/home  
 tempTestDataPool/backups/root/all_root_fs_backup/home/gentooExtra  3.95G 2.61T 3.95G /backups/home/gentoo/extraSpace  
 tempTestDataPool/backups/scratch/home                              3.24G 2.61T  737M /backups/home/gentoo  
 livecd gentoo # 

Performing a diff between '/home/gentoo' and '/backups/home/gentoo' will also validate the 'rootPool/root_fs/home/gentooExtra' and 'tempTestDataPool/backups/root/all_root_fs_backup/home/gentooExtra'.  Another problem I will find for the home directory comparison will be any changes since the backup, so what I really want to do is compare it against the snapshot the backup was made from.  Running the following diff command will show me any differences between the backup, and the snapshot:

 livecd gentoo # diff -rq /home/gentoo/.zfs/snapshot/backup_20200111_0116/ /backups/home/gentoo  
 diff: /home/gentoo/.zfs/snapshot/backup_20200111_0116/.kde4/cache-livecd: No such file or directory  
 diff: /backups/home/gentoo/.kde4/cache-livecd: No such file or directory  
 diff: /home/gentoo/.zfs/snapshot/backup_20200111_0116/.kde4/socket-livecd: No such file or directory  
 diff: /backups/home/gentoo/.kde4/socket-livecd: No such file or directory  
 diff: /home/gentoo/.zfs/snapshot/backup_20200111_0116/.kde4/tmp-livecd: No such file or directory  
 diff: /backups/home/gentoo/.kde4/tmp-livecd: No such file or directory  
 diff: /home/gentoo/.zfs/snapshot/backup_20200111_0116/.mozilla/firefox/7040su8h.default-release/lock: No such file or directory  
 diff: /backups/home/gentoo/.mozilla/firefox/7040su8h.default-release/lock: No such file or directory  
 diff: /home/gentoo/.zfs/snapshot/backup_20200111_0116/.mozilla/firefox/hmud4qrk.default-1558998297270/lock: No such file or directory  
 diff: /backups/home/gentoo/.mozilla/firefox/hmud4qrk.default-1558998297270/lock: No such file or directory  
 livecd gentoo #   

There appears to be some differences, however looking closer, these are 'diff' errors, not actual differences.  For each file, it complains about 'No such file or directory' for both locations.  Examining the missing files/directories, it turns out that the directories/files are symbolic links to elsewhere in the system for temporary files that have since been cleaned up.  I would consider this to  be a validated backup.

The next backup to validate is the persistentPortageTmp, using the command:
 livecd gentoo # diff -qr /tmp/portage/.zfs/snapshot/backup_20200111_0116/ /backups/tmp/portage/  
 livecd gentoo #      

This shows no difference, so another validated backup.

The next backup to validate is the scripts backup.  I have not made any changes to the scripts folder since the backup, so no need to compare against a specific snapshot
 livecd gentoo # diff -qr /gentooScratch/scripts/ /backups/backupPool/scratch/scripts/  
 livecd gentoo #   
This shows no difference, so another validated backup.

The next backup to validate is the  persistentPortageDistfiles.  Once again I have made no changes, so I can just compare the directories instead of a snapshot.
 livecd gentoo # diff -qr /usr/portage/distfiles/ /backups/usr/portage/distfiles/  
 livecd gentoo #   
This shows no difference, so another validated backup.

The next backup to validate is the sources backup.  I have not made any changes to the sources folder since the backup, so no need to compare against a specific snapshot
 livecd gentoo # diff -qr /gentooScratch/sources/ /backups/backupPool/scratch/src/  
 livecd gentoo #
This shows no difference, so another validated backup.

The final backup to validate is the full recursive $LFS root location using

 livecd gentoo # diff -qr /rootPool/root_fs/ /backups/backupPool/root/all_root_fs_backup/  
 diff: /rootPool/root_fs/sources/bison/bison/build-aux/move-if-change: No such file or directory  
 diff: /backups/backupPool/root/all_root_fs_backup/sources/bison/bison/build-aux/move-if-change: No such file or directory  
 diff: /rootPool/root_fs/sources/bison/bison/data/m4sugar/foreach.m4: No such file or directory  
 diff: /backups/backupPool/root/all_root_fs_backup/sources/bison/bison/data/m4sugar/foreach.m4: No such file or directory  
 diff: /rootPool/root_fs/sources/bison/bison/data/m4sugar/m4sugar.m4: No such file or directory  
 diff: /backups/backupPool/root/all_root_fs_backup/sources/bison/bison/data/m4sugar/m4sugar.m4: No such file or directory  
 diff: /rootPool/root_fs/sources/bison/bison/m4/m4.m4: No such file or directory  
 diff: /backups/backupPool/root/all_root_fs_backup/sources/bison/bison/m4/m4.m4: No such file or directory  
 diff: /rootPool/root_fs/sources/kmod/kmod/testsuite/rootfs-pristine/test-loaded/sys/module/btusb/drivers/usb:btusb: No such file or directory  
 diff: /backups/backupPool/root/all_root_fs_backup/sources/kmod/kmod/testsuite/rootfs-pristine/test-loaded/sys/module/btusb/drivers/usb:btusb: No such file or directory  
 diff: /rootPool/root_fs/sources/m4/m4/COPYING: No such file or directory  
 diff: /backups/backupPool/root/all_root_fs_backup/sources/m4/m4/COPYING: No such file or directory  
 diff: /rootPool/root_fs/sources/m4/m4/INSTALL: No such file or directory  
 diff: /backups/backupPool/root/all_root_fs_backup/sources/m4/m4/INSTALL: No such file or directory  
 diff: /rootPool/root_fs/sources/m4/m4/build-aux/compile: No such file or directory  
 diff: /backups/backupPool/root/all_root_fs_backup/sources/m4/m4/build-aux/compile: No such file or directory  
 diff: /rootPool/root_fs/sources/m4/m4/build-aux/config.guess: No such file or directory  
 diff: /backups/backupPool/root/all_root_fs_backup/sources/m4/m4/build-aux/config.guess: No such file or directory  
 diff: /rootPool/root_fs/sources/m4/m4/build-aux/config.sub: No such file or directory  
 diff: /backups/backupPool/root/all_root_fs_backup/sources/m4/m4/build-aux/config.sub: No such file or directory  
 diff: /rootPool/root_fs/sources/m4/m4/build-aux/depcomp: No such file or directory  
 diff: /backups/backupPool/root/all_root_fs_backup/sources/m4/m4/build-aux/depcomp: No such file or directory  
 diff: /rootPool/root_fs/sources/m4/m4/build-aux/install-sh: No such file or directory  
 diff: /backups/backupPool/root/all_root_fs_backup/sources/m4/m4/build-aux/install-sh: No such file or directory  
 diff: /rootPool/root_fs/sources/m4/m4/build-aux/mdate-sh: No such file or directory  
 diff: /backups/backupPool/root/all_root_fs_backup/sources/m4/m4/build-aux/mdate-sh: No such file or directory  
 diff: /rootPool/root_fs/sources/m4/m4/build-aux/texinfo.tex: No such file or directory  
 diff: /backups/backupPool/root/all_root_fs_backup/sources/m4/m4/build-aux/texinfo.tex: No such file or directory  
 diff: /rootPool/root_fs/sources/texinfo/texinfo/js/build-aux/texinfo.tex: No such file or directory  
 diff: /backups/backupPool/root/all_root_fs_backup/sources/texinfo/texinfo/js/build-aux/texinfo.tex: No such file or directory  
 livecd gentoo #

Once again, similar to the gentoo's host home direcorty we have some diff errors, but no differences.  I took a look at some of the 'missing' files, and once again they are symbolic links, some of which are absolute and expecting the 'chroot' environment of using '$LFS'.  Since every 'missing' file is the same between the two datasets, this backup is also 'valid'.

Future backups.

Once the LFS system is fully up and running, I plan on having some automated backups and some real time replication to another server.  At that time I will go over extended zfs send/recv syntax, including incremental, and (near) realtime replication for additional backup strategies.  For now I just wanted to point out I am not 'relying' on ZFS redundancy or RAID as a backup solution, and show you what my 'current' solution is so I do not loose any work I have currently put into my Linux From Scratch server build.






No comments:

Post a Comment