Archives mensuelles : juillet 2020

ZFS for dummies – FreeBSD ZFS replication

Exemple de réplication d’une jail en ZFS sur FreeBSD

L’environnement d’exemple est celui ou  j’ai divers web, blog, photos, etc., mais le même principe de réplication est utilisé à grande échelle pour un plan de continuité d’activité (PCA) entre des serveurs sur deux  centre de données différent avec des périodes de réplication adaptée aux besoins.

pour mon exemple, /etc/crontab

# chaque jour juste l’incrémental
45 4 * * * root (echo "Subject: ZFS replicate zsync_web incremental " && ( (/usr/bin/time -h /backup/zsync_web incremental) 2>&1 ) ) | sendmail -f FROM@DOMAIN TO@DOMAIN
# le 22 du mois, un full
10 4 22 * * root (echo "Subject: ZFS replicate zsync_web full " && ( (/usr/bin/time -h /backup/zsync_web full) 2>&1 ) ) | sendmail -f FROM@DOMAIN TO@DOMAIN

Je passe sur l’échange de clef SSH entre le host source et celui de destination pour faire la réplication via ssh, et j’utilise aussi shlock.

# pkg info | grep shlock
shlock-2.6.3 Create lock files for use in shell scripts

Le principe ZFS, un bookmark et des snapshot, du zfs send et receive entre deux serveurs.

La syntaxe:
/backup/zsync_web full|incremental|list|show

# /backup/zsync_web list
snapshot jails/web :
jails/web@L1_5 13.2M – 92.4G –
jails/web@L1_6 12.5M – 92.4G –
jails/web@L1_7 18.4M – 92.4G –
jails/web@L1_1 7.01M – 92.4G –
jails/web@L1_2 17.1M – 92.4G –
jails/web@L1_3 5.66M – 92.4G –
jails/web@L1_4 2.16M – 92.4G –
bookmark jails/web :
jails/web#L0_1_bookmark – – – –

Le script au complet:

# zsync / ZFS incremental backup réplication
# FreeBSD 12 - 2021-01 jcmichot _@_ free.org

# replicate/synchronize zfs file system on remote host

DAYWEEK=`date "+%u"`

# /!\ CHANGE "HOSTNAME" /!\ by your replication target hostname
MYTARGET="HOSTNAME"
# /!\ CHANGE "jail/web"/!\ by your source jail to replicate
MYFS="jails/web"
LOCK="/var/tmp/zsync_web.lock"

IGNORE=nozsync
CMD=$1

trap 'rm -f ${LOCK} ; exit 1' 1 2 3 15
if shlock -p $$ -f ${LOCK} ; then

 case $CMD in
  full)

   # dump 0 - full backup day

   # LOCAL: remove all MYFS zsync snapshots and bookmark 
   zfs list -t snapshot | grep -e "$MYFS@L1_" -e "$MYFS@L0_" | awk '{ printf("zfs destroy %s\n", $1 ); }' | sh 
   zfs list -t bookmark | grep "$MYFS#L0_" | awk '{ printf("zfs destroy %s\n", $1 ); }' | sh

   # REMOTE (TARGET), remove all MYFS zsync snapshots 
   REMOTESNAPS=`ssh root@$MYTARGET zfs list -H -t snapshot -o name | grep $MYFS@`
   PROCED="$IGNORE $REMOTESNAPS"
   for p in $PROCED
    do
      case $p in
          $IGNORE)
              ;;
          *)
              ssh root@$MYTARGET zfs destroy $p
              ;;
      esac
    done

   zfs snapshot $MYFS@L0_1
   zfs bookmark $MYFS@L0_1 $MYFS#L0_1_bookmark

   zfs send -cvV $MYFS@L0_1 | ssh root@$MYTARGET zfs receive -F $MYFS@L0_1
   zfs destroy $MYFS@L0_1

   for i in 1 2 3 4 5 6 7
    do
    zfs snapshot $MYFS@L1_$i
    done
  ;;

  incremental)

   zfs destroy $MYFS@L1_$DAYWEEK
   zfs snapshot $MYFS@L1_$DAYWEEK

   # REMOTE (TARGET), remove the DAYWEEK INCREMENTAL snapshot

   REMOTESNAPS=`ssh root@$MYTARGET zfs list -H -t snapshot -o name | grep $MYFS@L1_$DAYWEEK`
   PROCED="$IGNORE $REMOTESNAPS"
   for p in $PROCED
    do
      case $p in
          $IGNORE)
              ;;
          *)
              ssh root@$MYTARGET zfs destroy $p
              ;;
      esac
    done

   zfs send -cvV -i $MYFS'#L0_1_bookmark' $MYFS@L1_$DAYWEEK | ssh root@$MYTARGET zfs receive -F $MYFS@L1_$DAYWEEK
  ;;

  list)
   echo "snapshot $MYFS :";
   zfs list -t snapshot | grep -e $MYFS@L1_ -e $MYFS@L0_
   echo "bookmark $MYFS :";
   zfs list -t bookmark | grep -e $MYFS#

  ;;
  show)
   echo "no zsync running";
  ;;

  *)
   echo "unknown command"
   echo "$0 full|incremental|list|show";
  ;;

 esac

 rm -f ${LOCK}

else

 case $CMD in
  show)
   SPID=`cat ${LOCK}`
   top -ap $SPID
  ;;

  *)
   echo "zsync locked by `cat ${LOCK}`"
  ;;

 esac

 exit 0;

fi

ZFS for dummies – Les snapshot ca sauve de catastrophe

C’est quoi un snapshot (un instantané en Français) pour ZFS ?

Un instantané ZFS est une copie en lecture seule d’un système de fichiers ou d’un volume. La création des snapshot ZFS est quasiment immédiate. Initialement, elle ne consomme pas d’espace disque supplémentaire au sein du pool. Toutefois, à mesure que les données contenues dans le jeu de données actif changent, le snapshot consomme de l’espace disque en continuant à faire référence aux anciennes données et empêche donc de libérer de l’espace disque.

Concrètement cela permet de revenir quasiment immédiatement à la situation d’un système de fichier à l’heure ou au jour voulu, ou juste d’aller chercher un ou des fichiers supprimés par erreur. Cela permet aussi de faire des réplications de système de fichier, de basculer de développement à la production, d’archiver sur d’autres média une sauvegarde, etc.

Comment faire ? Dans mon cas en crontab je lance un script qui va faire des snapshot ZFS. (un par heure, et un chaque jour). Cela représente 31 snapshot  en une semaine, après quoi le script va détruire l’ancien snapshot de l’heure ou du jour pour faire le nouveau.

Exemple sur /usr/home

% zfs list  -t snapshot | grep /usr/home
zroot/usr/home@Thursday        883M      -   317G  -
zroot/usr/home@Friday          112M      -   317G  -
zroot/usr/home@Saturday       49.3M      -   317G  -
zroot/usr/home@Sunday         49.5M      -   317G  -
zroot/usr/home@Monday         71.1M      -   317G  -
zroot/usr/home@Tuesday         258M      -   318G  -
zroot/usr/home@hourly_18      1.22M      -   318G  -
zroot/usr/home@hourly_19      1.13M      -   318G  -
zroot/usr/home@hourly_20      1.05M      -   318G  -
zroot/usr/home@hourly_21      1.09M      -   318G  -
zroot/usr/home@hourly_22      1.07M      -   318G  -
zroot/usr/home@hourly_23      1.16M      -   318G  -
zroot/usr/home@hourly_00       732K      -   318G  -
zroot/usr/home@Wednesday       600K      -   318G  -
zroot/usr/home@hourly_01       644K      -   318G  -
zroot/usr/home@hourly_02       768K      -   318G  -
zroot/usr/home@hourly_03       764K      -   318G  -
zroot/usr/home@hourly_04       948K      -   318G  -
zroot/usr/home@hourly_05      1.18M      -   318G  -
zroot/usr/home@hourly_06      1.20M      -   318G  -
zroot/usr/home@hourly_07      1.44M      -   318G  -
zroot/usr/home@hourly_08      1.36M      -   318G  -
zroot/usr/home@hourly_09      1.43M      -   318G  -
zroot/usr/home@hourly_10      1.36M      -   318G  -
zroot/usr/home@hourly_11      1.30M      -   318G  -
zroot/usr/home@hourly_12      1.50M      -   318G  -
zroot/usr/home@hourly_13      34.8M      -   318G  -
zroot/usr/home@hourly_14      37.9M      -   318G  -
zroot/usr/home@hourly_15      45.2M      -   318G  -
zroot/usr/home@hourly_16      44.7M      -   318G  -
zroot/usr/home@hourly_17      23.3M      -   318G  -

# /etc/crontab ZFS snapshot (hourly & daily)
30 * * * * root /usr/local/bin/backup_snap.sh hourly >/dev/null 2>&1
25 0 * * * root /usr/local/bin/backup_snap.sh daily >/dev/null 2>&1

Le script « backup_snap.sh »:

#!/bin/sh

# défini une propriété de zone que l'on va exclure des snapshot.
# un peu comme le chflags nodump de UFS FreeBSD
#
# zfs set freebsd:nosnap=yes zroot/usr/ports
# zfs set freebsd:nosnap=yes zroot/usr/src
# zfs set freebsd:nosnap=yes zroot/tmp
# zfs set freebsd:nosnap=yes zroot/films
# zfs set freebsd:nosnap=yes zroot/var/tmp
# zfs set freebsd:nosnap=yes zroot/var/crash

# zfs list -o name,type,used,avail,mountpoint,compress,version,freebsd:nosnap

TYPE=$1

LANG="C"
export LANG

case $TYPE in
        daily)
                DATE=`date +"%A"`
        ;;
        hourly)
                DATE=`date +"hourly_%H"`
        ;;
        *)
                DATE=`date +"%A"`
        ;;
esac

# garde une trace de ce qui est installé sur la machine
pkg info >/root/pkg_info.txt

# snapshot destroy recursif
zfs destroy -r zroot@${DATE}

# snapshot recursif
zfs snapshot -r zroot@${DATE}

# efface les snapshot avec la property "freebsd:nosnap"

for d in `zfs list -H -t snapshot -o name,freebsd:nosnap  | grep -E 'yes$' | awk '{ print $1 }'` ; do
        zfs destroy $d
        done

exit 0;

ZFS for dummies – backup avec un minimum de sécurité.

Création d’un /backup en ZFS avec du RAID miroir

# gpart destroy ada2
# gpart destroy ada3
# gpart create -s gpt ada2
# gpart create -s gpt ada3
# gpart add -a 1m -t freebsd-zfs -l disk2 ada2
# gpart add -a 1m -t freebsd-zfs -l disk3 ada3
# zpool create -O compress=lz4 -O atime=off -m /backup backup mirror ada2p1 ada3p1

C’est utilisable sur divers support physique, j’ai par exemple un Raspberry PI avec un /backup sur deux clefs USB SANDISK Cruzer Fit de 64 Go. Moins de 15 Euros la clef chez plusieurs dealer’s online.

ZFS for dummies – Attention je débranche l’alimentation

Que faire, si cela se passe mal en cas de coupure électrique avec un unique disque (dans mon cas un SSD dans un boîtier externe en USB)

Coupure électrique, et pas de chance le boîtier USB externe n’était pas sur onduleur 🙁

dans le dmesg FreeBSD ca donne ca:

ugen0.9: <ASMedia asm1153e> at usbus0 (disconnected)
umass2: at uhub0, port 17, addr 9 (disconnected)
da1 at umass-sim2 bus 2 scbus9 target 0 lun 0
da1: <ASMedia asm1153e 0> s/n 000000000001 detached
(da1:umass-sim2:2:0:0): Periph destroyed
umass2: detached
ugen0.9: <ASMedia asm1153e> at usbus0
umass2 on uhub0
umass2: <ASMedia asm1153e, class 0/0, rev 3.00/1.00, addr 16> on usbus0
umass2: SCSI over Bulk-Only; quirks = 0x0100
umass2:9:2: Attached to scbus9
da1 at umass-sim2 bus 2 scbus9 target 0 lun 0
da1: <ASMedia asm1153e 0> Fixed Direct Access SPC-4 SCSI device
da1: Serial Number 000000001234
da1: 400.000MB/s transfers
da1: 976762MB (2000409264 512 byte sectors)
da1: quirks=0x2<NO_6_BYTE>

# zpool list
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
backup 7.25T 1.34T 5.91T – – 0% 18% 1.00x ONLINE –
zroot 896G 657G 239G – – 27% 73% 1.00x ONLINE –
zssd 952G 128G 824G – – 0% 13% 1.00x UNAVAIL /mnt

# zpool status zssd
pool: zssd
state: UNAVAIL
status: One or more devices are faulted in response to IO failures.
action: Make sure the affected devices are connected, then run ‘zpool clear’.
see: http://illumos.org/msg/ZFS-8000-HC
scan: none requested
config:

NAME STATE READ WRITE CKSUM
zssd UNAVAIL 0 0 0
14572189989752791848 REMOVED 0 0 0 was /dev/da1p2

# zpool clear zssd

# zpool status -v zssd
pool: zssd
state: ONLINE
status: One or more devices has experienced an error resulting in data
corruption. Applications may be affected.
action: Restore the file in question if possible. Otherwise restore the
entire pool from backup.
see: http://illumos.org/msg/ZFS-8000-8A
scan: scrub in progress since Mon Oct 25 17:22:00 2021
128G scanned at 340M/s, 83.0G issued at 221M/s, 128G total
0 repaired, 64.93% done, 0 days 00:03:27 to go
config:

NAME STATE READ WRITE CKSUM
zssd ONLINE 0 0 0
da1p2 ONLINE 0 0 0

errors: Permanent errors have been detected in the following files:

<metadata>:<0x0>
<metadata>:<0x39>
/mnt/zssd/lesarcs

# Remarque le scrub est automatique, il n’est pas utile de le lancer manuellement.

# zpool status -v zssd

pool: zssd
state: ONLINE
scan: scrub repaired 0 in 0 days 00:09:52 with 0 errors on Mon Oct 25 17:31:52 2021
config:

NAME STATE READ WRITE CKSUM
zssd ONLINE 0 0 0
da1p2 ONLINE 0 0 0

Je test avec /sbin/md5 s’il y une différence entre les fichiers du SSD et avec le backup, aucune ! tout est ok 🙂

FreeBSD motion with few camera

Foscam FI9828P+V2, Camera outdoor

Foscam FI9821W-v2, camera indoor

WansView model W4, Camera 1080P

WansView model W2, Camera 1080P (sortie motion, exemple jardin)

Yoluke 5MP 20x Zoom Optique, Audio Bidirectionnel (sortie motion, exemple parking)

Exemple:

record video MP4 with audio in case of motion:

DIR=/motion/fdp-parking_log
DHMSF=`date +"%Y%m%d%H%M%S"`
# ffmpeg record 4 minutes video high resolution,
# transcode audio (pcm_alaw) because pcm_alaw is not supported in .mp4
# NOTE: need to use tcp transport because ffmpeg drop frame with HD camera @12fps :(
# no drop frame with VLC but ugly commande line syntax (and pb with end time)
/usr/local/bin/ffmpeg -hide_banner -loglevel quiet -stats -y \
-rtsp_transport tcp -rtbufsize 3000k -i rtsp://192.168.0.63:554/11 -c:a aac \
-vcodec copy -t 240 -movflags +faststart "$DIR/.parking-$DHMSF-ffmpeg.mp4" &