683
Comment:
|
10823
|
Deletions are marked like this. | Additions are marked like this. |
Line 5: | Line 5: |
Questi sono appunti sparsi sul setup di un singolo host con PVE versione 4.4 e un raid1 con ZFS. | Questi sono appunti sparsi sul setup di un singolo host con PVE versione 4.4 e 5.1.3 e un raid1 con ZFS. == Configurazione dei repo PVE no subscription == Questo repository non richiede il pagamento dell'assistenza ma potenzialmente contiene roba instabile. Occhio. * Editare /etc/apt/sources.list.d/pve-enterprise.list e commentare l'unica riga che contiene. * Creare un file /etc/apt/sources.list.d/pve-no-subscription.list e metterci dentro la configurazione per il repo gratuito: {{{ # per PVE 5, basato su Debian Stretch: deb http://download.proxmox.com/debian/pve stretch pve-no-subscription }}} == Limitare la ARC cache di ZFS == * Editare il file {{{/etc/modprobe.d/zfs.conf}}} e scriverci dentro: (per esempio 4G max e 1G min) {{{ options zfs zfs_arc_max=4294967296 options zfs zfs_arc_min=1073741824 }}} * Eseguire {{{update-initramfs -u}}} * Riavviare la macchina Nota: e` possibile limitare la dimensione "a runtime" senza riavviare, usando {{{echo 4294967296 > /sys/module/zfs/parameters/zfs_arc_max}}} ma questo funziona solo la dimensione attuale della ARC cache e` inferiore a quella impostata. Se e` gia` cresciuta oltre, non calera` mai piu` se non riavviando. Ovviamente questa impostazione non e` persistente dopo il reboot. C'e` chi sostiene che eseguendo {{{echo 3 > /proc/sys/vm/drop_caches}}} la cache dovrebbe ridursi... ma io non ci proverei su una macchina in produzione. |
Line 11: | Line 40: |
Line 18: | Line 46: |
Nelle versioni piu` recenti di PVE si può installare il pacchetto zfs-zed che manda allarmi via email. Va impostata la configurazine della email in /etc/zfs/zed.d/zed.rc scommentando la riga ZED_EMAIL_ADDR="root". L'ho provato sulla versione 6 (e` di default) e mi ha segnalato tutti gli eventi tranne quello importante, cioe` quando ho staccato apposta un disco per mandare il pool in degraded, quindi io consiglierei di usare anche la soluzione "fatta in casa" con cron. == Backup su storage remoto dei dump == Questo script si "aggancia" al sistema di backup interno di PVE, allo scopo di fare una seconda copia dei dump delle VM su uno storage esterno (smb, nfs, usb, qualsiasi cosa si possa montare). Questo script cosi` come e` fatto tiene 6 backup settimanali e 4 mensili, quindi sono 10 backup. Tenete bene conto dello spazio necessario! Ad ogni esecuzione di un job di backup, una volta eseguiti i dump di tutte le VM, questo script copia tutti i dump sullo storage remoto, dopo aver archiviato quelli precedenti dentro le directory "daily" e "weekly". * Prima di tutto, creare lo script e renderlo eseguibile. Io lo chiamo {{{/root/pve-remote-backup.sh}}}. {{{ #!/bin/bash # Impostazioni: listfile="/tmp/pve-remote-backup-filelist.txt" mountpoint="/usbdisk" # all'inizio del job, mi assicuro di cancellare # la lista dei files if [ "$1" == "job-start" ]; then echo "JOB-START: cancello la lista dei files" [ -f $listfile ] && rm $listfile exit 0 fi # alla fine del singolo backup mi segno il nome # del file che e` stato creato, salvandolo in /tmp/ if [ "$1" == "backup-end" ]; then echo "BACKUP-END: salvo il nome del file" echo $TARFILE >> $listfile fi # alla fine del job, # monto lo storage remoto, ruoto i vecchi backup se necessario, # e copio tutti i files del backup attuale sullo storage remoto if [ "$1" == "job-end" ]; then echo "JOB-END: Monto lo storage remoto" mount -L usbbackup $mountpoint if mountpoint -q $mountpoint; then echo "JOB-END: Storage remoto montato" # Leggo la lista dei files da copiare e li copio rinominandoli # in modo da togliere il timestamp. while IFS= read -r line do nopath=`echo $line | awk 'END{ n=split ($NF,a,"/"); print a[n]}'` destination=`echo $nopath | awk -F[-.] '{ print $1 "-" $2 "-" $3 "." $6 "." $7}'` if [[ -z "${line// }" ]] ; then echo "JOB-END: ERRORE, trovata una linea vuota nell'elenco di input - la ignoro" else echo "JOB-END: Salvo lo storico per $mountpoint/$destination" if [[ $(date +%u) -eq 7 ]] ; then # se e` domenica salvo in weekly e ne tengo 4 savelog -c4 -l -r weekly $mountpoint/$destination else # se e` un altro giorno salvo in daily e ne tengo 6 savelog -c6 -l -r daily $mountpoint/$destination fi echo "JOB-END: Copio $line su $mountpoint/$destination" cp $line $mountpoint/$destination fi done <"$listfile" # Fine della copia, smonto e ho finito. echo "JOB-END: Smonto lo storage remoto" umount $mountpoint exit 0 else echo "JOB-END: ERRORE, storage remoto non accessibile" exit 1 fi fi }}} * Secondariamente, modificare lo script in modo da fare il mount del vostro storage remoto preferito * Per finire, modificare il file {{{/etc/vzdump.conf}}} inserendo una riga che dice di usare lo script durante i job di backup: {{{ script: /root/pve-remote-backup.sh }}} == Uso di Qemu-agent == Abilitando l'agent nella configurazione della VM, e installando l'agent dentro la VM, è possibile gestire alcune funzioni di comunicazione fra host e guest. Una delle funzioni più comode è quella del freeze del file system nel momento in cui viene fatto uno snapshot (per esempio per i backup) per avere dei backup il più possibile congruenti. Per il file system, il semplice fatto di avere l'agente installato e abilitato è sufficiente. Per un database, tuttavia, è opportuno configurare uno script apposta. Il pacchetto Debian da installare nel guest si chiama {{{qemu-guest-agent}}} === Qemu-agent e Mysql su guest Devuan === Per fare interagire Mysql (o Mariadb) con qemu-agent occorre: * Installare il pacchetto dell'agent * Modificare il file di init {{{/etc/init.d/qemu-guest-agent}}} aggiungendo il parametro "-F" nella variabile DAEMON_ARGS, in queso modo: {{{DAEMON_ARGS="-F"}}} * Riavviare qemu-guest-agent * Creare la directory {{{/etc/qemu}}} * Creare la directory {{{/etc/qemu/fsfreeze-hook.d}}} * Creare lo script {{{/etc/qemu/fsfreeze-hook}}}, contenente quanto segue: {{{ #!/bin/bash # This script is executed when a guest agent receives fsfreeze-freeze and # fsfreeze-thaw command, if it is specified in --fsfreeze-hook (-F) # option of qemu-ga or placed in default path (/etc/qemu/fsfreeze-hook). # When the agent receives fsfreeze-freeze request, this script is issued with # "freeze" argument before the filesystem is frozen. And for fsfreeze-thaw # request, it is issued with "thaw" argument after filesystem is thawed. LOGFILE=/var/log/qga-fsfreeze-hook.log FSFREEZE_D=$(dirname -- "$0")/fsfreeze-hook.d # Check whether file $1 is a backup or rpm-generated file and should be ignored is_ignored_file() { case "$1" in *~ | *.bak | *.orig | *.rpmnew | *.rpmorig | *.rpmsave | *.sample) return 0 ;; esac return 1 } # Iterate executables in directory "fsfreeze-hook.d" with the specified args [ ! -d "$FSFREEZE_D" ] && exit 0 for file in "$FSFREEZE_D"/* ; do is_ignored_file "$file" && continue [ -x "$file" ] || continue printf "$(date): execute $file $@\n" >>$LOGFILE "$file" "$@" >>$LOGFILE 2>&1 STATUS=$? printf "$(date): $file finished with status=$STATUS\n" >>$LOGFILE done exit 0 }}} * Creare lo script {{{/etc/qemu/fsfreeze-hook.d/mysql-flush.sh}}} contenente quanto segue (nota se occorre o meno inserire il parametro per la password nella variabile MYSQL_OPTS): {{{ #!/bin/bash # Flush MySQL tables to the disk before the filesystem is frozen. # At the same time, this keeps a read lock in order to avoid write accesses # from the other clients until the filesystem is thawed. MYSQL="/usr/bin/mysql" MYSQL_OPTS="-uroot" #"-prootpassword" FIFO=/var/run/mysql-flush.fifo # Check mysql is installed and the server running [ -x "$MYSQL" ] && "$MYSQL" $MYSQL_OPTS < /dev/null || exit 0 flush_and_wait() { printf "FLUSH TABLES WITH READ LOCK \\G\n" trap 'printf "$(date): $0 is killed\n">&2' HUP INT QUIT ALRM TERM read < $FIFO printf "UNLOCK TABLES \\G\n" rm -f $FIFO } case "$1" in freeze) mkfifo $FIFO || exit 1 flush_and_wait | "$MYSQL" $MYSQL_OPTS & # wait until every block is flushed while [ "$(echo 'SHOW STATUS LIKE "Key_blocks_not_flushed"' |\ "$MYSQL" $MYSQL_OPTS | tail -1 | cut -f 2)" -gt 0 ]; do sleep 1 done # for InnoDB, wait until every log is flushed INNODB_STATUS=$(mktemp /tmp/mysql-flush.XXXXXX) [ $? -ne 0 ] && exit 2 trap "rm -f $INNODB_STATUS; exit 1" HUP INT QUIT ALRM TERM while :; do printf "SHOW ENGINE INNODB STATUS \\G" |\ "$MYSQL" $MYSQL_OPTS > $INNODB_STATUS LOG_CURRENT=$(grep 'Log sequence number' $INNODB_STATUS |\ tr -s ' ' | cut -d' ' -f4) LOG_FLUSHED=$(grep 'Log flushed up to' $INNODB_STATUS |\ tr -s ' ' | cut -d' ' -f5) [ "$LOG_CURRENT" = "$LOG_FLUSHED" ] && break sleep 1 done rm -f $INNODB_STATUS ;; thaw) [ ! -p $FIFO ] && exit 1 echo > $FIFO ;; *) exit 1 ;; esac }}} * Rendere eseguibili da root i due script appena creati Fatto questo, quando si lancia un backup il DB verrà flushato e lockato in scrittura per un secondo circa, il tempo di creare lo snapshot per il backup, poi verrà immediatamente sbloccato. Il risultato, nel log del guest, è una cosa tipo: {{{ Jul 21 14:24:23 web1 qemu-ga: info: guest-fsfreeze called Jul 21 14:24:23 web1 qemu-ga: info: executing fsfreeze hook with arg 'freeze' Jul 21 14:24:23 web1 qemu-ga: info: executing fsfreeze hook with arg 'thaw' }}} |
PVE ovvero Proxmox Virtual Environment
PVE e` un sistema di virtualizzazione basato su Debian (purtroppo con systemd) e KVM. Ottimo ed economico anche se si vuole comperare il supporto commerciale.
Questi sono appunti sparsi sul setup di un singolo host con PVE versione 4.4 e 5.1.3 e un raid1 con ZFS.
Configurazione dei repo PVE no subscription
Questo repository non richiede il pagamento dell'assistenza ma potenzialmente contiene roba instabile. Occhio.
- Editare /etc/apt/sources.list.d/pve-enterprise.list e commentare l'unica riga che contiene.
- Creare un file /etc/apt/sources.list.d/pve-no-subscription.list e metterci dentro la configurazione per il repo gratuito:
# per PVE 5, basato su Debian Stretch: deb http://download.proxmox.com/debian/pve stretch pve-no-subscription
Limitare la ARC cache di ZFS
Editare il file /etc/modprobe.d/zfs.conf e scriverci dentro: (per esempio 4G max e 1G min)
options zfs zfs_arc_max=4294967296 options zfs zfs_arc_min=1073741824
Eseguire update-initramfs -u
- Riavviare la macchina
Nota: e` possibile limitare la dimensione "a runtime" senza riavviare, usando echo 4294967296 > /sys/module/zfs/parameters/zfs_arc_max ma questo funziona solo la dimensione attuale della ARC cache e` inferiore a quella impostata. Se e` gia` cresciuta oltre, non calera` mai piu` se non riavviando. Ovviamente questa impostazione non e` persistente dopo il reboot. C'e` chi sostiene che eseguendo echo 3 > /proc/sys/vm/drop_caches la cache dovrebbe ridursi... ma io non ci proverei su una macchina in produzione.
Configurazione di un sistema di allarme per email se il raidz di zfs va in degraded
Non e` proprio un avviso in tempo reale, ma queste righe aggiunte al crontab permettono di avere un allarme sufficientemente tempestivo, si spera.
# allarme se si rompe zfs. MAILTO=youremail@example.com 00 6,12,20 * * * root zpool status | grep DEGRADED
Nelle versioni piu` recenti di PVE si può installare il pacchetto zfs-zed che manda allarmi via email. Va impostata la configurazine della email in /etc/zfs/zed.d/zed.rc scommentando la riga ZED_EMAIL_ADDR="root". L'ho provato sulla versione 6 (e` di default) e mi ha segnalato tutti gli eventi tranne quello importante, cioe` quando ho staccato apposta un disco per mandare il pool in degraded, quindi io consiglierei di usare anche la soluzione "fatta in casa" con cron.
Backup su storage remoto dei dump
Questo script si "aggancia" al sistema di backup interno di PVE, allo scopo di fare una seconda copia dei dump delle VM su uno storage esterno (smb, nfs, usb, qualsiasi cosa si possa montare). Questo script cosi` come e` fatto tiene 6 backup settimanali e 4 mensili, quindi sono 10 backup. Tenete bene conto dello spazio necessario! Ad ogni esecuzione di un job di backup, una volta eseguiti i dump di tutte le VM, questo script copia tutti i dump sullo storage remoto, dopo aver archiviato quelli precedenti dentro le directory "daily" e "weekly".
Prima di tutto, creare lo script e renderlo eseguibile. Io lo chiamo /root/pve-remote-backup.sh.
#!/bin/bash # Impostazioni: listfile="/tmp/pve-remote-backup-filelist.txt" mountpoint="/usbdisk" # all'inizio del job, mi assicuro di cancellare # la lista dei files if [ "$1" == "job-start" ]; then echo "JOB-START: cancello la lista dei files" [ -f $listfile ] && rm $listfile exit 0 fi # alla fine del singolo backup mi segno il nome # del file che e` stato creato, salvandolo in /tmp/ if [ "$1" == "backup-end" ]; then echo "BACKUP-END: salvo il nome del file" echo $TARFILE >> $listfile fi # alla fine del job, # monto lo storage remoto, ruoto i vecchi backup se necessario, # e copio tutti i files del backup attuale sullo storage remoto if [ "$1" == "job-end" ]; then echo "JOB-END: Monto lo storage remoto" mount -L usbbackup $mountpoint if mountpoint -q $mountpoint; then echo "JOB-END: Storage remoto montato" # Leggo la lista dei files da copiare e li copio rinominandoli # in modo da togliere il timestamp. while IFS= read -r line do nopath=`echo $line | awk 'END{ n=split ($NF,a,"/"); print a[n]}'` destination=`echo $nopath | awk -F[-.] '{ print $1 "-" $2 "-" $3 "." $6 "." $7}'` if [[ -z "${line// }" ]] ; then echo "JOB-END: ERRORE, trovata una linea vuota nell'elenco di input - la ignoro" else echo "JOB-END: Salvo lo storico per $mountpoint/$destination" if [[ $(date +%u) -eq 7 ]] ; then # se e` domenica salvo in weekly e ne tengo 4 savelog -c4 -l -r weekly $mountpoint/$destination else # se e` un altro giorno salvo in daily e ne tengo 6 savelog -c6 -l -r daily $mountpoint/$destination fi echo "JOB-END: Copio $line su $mountpoint/$destination" cp $line $mountpoint/$destination fi done <"$listfile" # Fine della copia, smonto e ho finito. echo "JOB-END: Smonto lo storage remoto" umount $mountpoint exit 0 else echo "JOB-END: ERRORE, storage remoto non accessibile" exit 1 fi fi
- Secondariamente, modificare lo script in modo da fare il mount del vostro storage remoto preferito
Per finire, modificare il file /etc/vzdump.conf inserendo una riga che dice di usare lo script durante i job di backup:
script: /root/pve-remote-backup.sh
Uso di Qemu-agent
Abilitando l'agent nella configurazione della VM, e installando l'agent dentro la VM, è possibile gestire alcune funzioni di comunicazione fra host e guest. Una delle funzioni più comode è quella del freeze del file system nel momento in cui viene fatto uno snapshot (per esempio per i backup) per avere dei backup il più possibile congruenti. Per il file system, il semplice fatto di avere l'agente installato e abilitato è sufficiente. Per un database, tuttavia, è opportuno configurare uno script apposta.
Il pacchetto Debian da installare nel guest si chiama qemu-guest-agent
Qemu-agent e Mysql su guest Devuan
Per fare interagire Mysql (o Mariadb) con qemu-agent occorre:
- Installare il pacchetto dell'agent
Modificare il file di init /etc/init.d/qemu-guest-agent aggiungendo il parametro "-F" nella variabile DAEMON_ARGS, in queso modo: DAEMON_ARGS="-F"
- Riavviare qemu-guest-agent
Creare la directory /etc/qemu
Creare la directory /etc/qemu/fsfreeze-hook.d
Creare lo script /etc/qemu/fsfreeze-hook, contenente quanto segue:
#!/bin/bash # This script is executed when a guest agent receives fsfreeze-freeze and # fsfreeze-thaw command, if it is specified in --fsfreeze-hook (-F) # option of qemu-ga or placed in default path (/etc/qemu/fsfreeze-hook). # When the agent receives fsfreeze-freeze request, this script is issued with # "freeze" argument before the filesystem is frozen. And for fsfreeze-thaw # request, it is issued with "thaw" argument after filesystem is thawed. LOGFILE=/var/log/qga-fsfreeze-hook.log FSFREEZE_D=$(dirname -- "$0")/fsfreeze-hook.d # Check whether file $1 is a backup or rpm-generated file and should be ignored is_ignored_file() { case "$1" in *~ | *.bak | *.orig | *.rpmnew | *.rpmorig | *.rpmsave | *.sample) return 0 ;; esac return 1 } # Iterate executables in directory "fsfreeze-hook.d" with the specified args [ ! -d "$FSFREEZE_D" ] && exit 0 for file in "$FSFREEZE_D"/* ; do is_ignored_file "$file" && continue [ -x "$file" ] || continue printf "$(date): execute $file $@\n" >>$LOGFILE "$file" "$@" >>$LOGFILE 2>&1 STATUS=$? printf "$(date): $file finished with status=$STATUS\n" >>$LOGFILE done exit 0
Creare lo script /etc/qemu/fsfreeze-hook.d/mysql-flush.sh contenente quanto segue (nota se occorre o meno inserire il parametro per la password nella variabile MYSQL_OPTS):
#!/bin/bash # Flush MySQL tables to the disk before the filesystem is frozen. # At the same time, this keeps a read lock in order to avoid write accesses # from the other clients until the filesystem is thawed. MYSQL="/usr/bin/mysql" MYSQL_OPTS="-uroot" #"-prootpassword" FIFO=/var/run/mysql-flush.fifo # Check mysql is installed and the server running [ -x "$MYSQL" ] && "$MYSQL" $MYSQL_OPTS < /dev/null || exit 0 flush_and_wait() { printf "FLUSH TABLES WITH READ LOCK \\G\n" trap 'printf "$(date): $0 is killed\n">&2' HUP INT QUIT ALRM TERM read < $FIFO printf "UNLOCK TABLES \\G\n" rm -f $FIFO } case "$1" in freeze) mkfifo $FIFO || exit 1 flush_and_wait | "$MYSQL" $MYSQL_OPTS & # wait until every block is flushed while [ "$(echo 'SHOW STATUS LIKE "Key_blocks_not_flushed"' |\ "$MYSQL" $MYSQL_OPTS | tail -1 | cut -f 2)" -gt 0 ]; do sleep 1 done # for InnoDB, wait until every log is flushed INNODB_STATUS=$(mktemp /tmp/mysql-flush.XXXXXX) [ $? -ne 0 ] && exit 2 trap "rm -f $INNODB_STATUS; exit 1" HUP INT QUIT ALRM TERM while :; do printf "SHOW ENGINE INNODB STATUS \\G" |\ "$MYSQL" $MYSQL_OPTS > $INNODB_STATUS LOG_CURRENT=$(grep 'Log sequence number' $INNODB_STATUS |\ tr -s ' ' | cut -d' ' -f4) LOG_FLUSHED=$(grep 'Log flushed up to' $INNODB_STATUS |\ tr -s ' ' | cut -d' ' -f5) [ "$LOG_CURRENT" = "$LOG_FLUSHED" ] && break sleep 1 done rm -f $INNODB_STATUS ;; thaw) [ ! -p $FIFO ] && exit 1 echo > $FIFO ;; *) exit 1 ;; esac
- Rendere eseguibili da root i due script appena creati
Fatto questo, quando si lancia un backup il DB verrà flushato e lockato in scrittura per un secondo circa, il tempo di creare lo snapshot per il backup, poi verrà immediatamente sbloccato. Il risultato, nel log del guest, è una cosa tipo:
Jul 21 14:24:23 web1 qemu-ga: info: guest-fsfreeze called Jul 21 14:24:23 web1 qemu-ga: info: executing fsfreeze hook with arg 'freeze' Jul 21 14:24:23 web1 qemu-ga: info: executing fsfreeze hook with arg 'thaw'