FreeBSD

Backup zfs

date
23 / 6 / 2011
comments
1

J'ai mis en place un système de backup de mon serveur FreeBSD (dédié) vers un autre serveur FreeBSD (@home). Les deux machines sont en zfs, c'était pour moi l'occasion de tester zfs (send|recv) over ssh. L'idée c'est qu'on envoie les donnés de manière incrémentale entre un snapshot du jour et un snapshot de la veille. Ce que l'on gagne par rapport à des solutions comme rsync c'est de la rapidité et moins d'accès disques (zfs sait exactement ce qui a bougé entre deux snapshot), l'autre avantage c'est sur la machine de backup on a un snapshot par jour, on peut donc facilement retrouver des fichiers supprimés.

#!/bin/sh

set -e

# Used in ssh command, example user@host -p 2222
REMOTE_HOST="diophante"

# Source zfs pool
POOL_SRC="tank"

# zfs sets to backup (relative to POOL_SRC)
SETS="usr/local/vmail usr/local/data usr/local/pgsql/backups usr/home usr/local/git var/backups"

# Destination pool
POOL_DST="tank/backup/${REMOTE_HOST}"

# We use ssh connection sharing
SSH_ARGS="-o ControlPath=~/.ssh/%r@%h:%p"

# zfs snapshot prefix => tank/foo@bck-2011-05-25
PREFIX="bck-"

# Remote zfs command
REMOTE_ZFS="ssh ${SSH_ARGS} ${REMOTE_HOST} sudo zfs"

# Local zfs command
LOCAL_ZFS="sudo zfs"

# Launch master ssh for sharing connections
ssh -MNn ${SSH_ARGS} ${REMOTE_HOST} &
ssh_master_pid=$!

for zfs_set in ${SETS}
do
    # Test if destination exist
    ${LOCAL_ZFS} list -H ${POOL_DST}/${zfs_set} >/dev/null

    date_suffix="${PREFIX}`date +%F`"
    snap="${POOL_SRC}/${zfs_set}@${date_suffix}"
    old_snap=`${REMOTE_ZFS} list -Ht snapshot 2>/dev/null | grep "^${POOL_SRC}/${zfs_set}@${PREFIX}" 2>/dev/null| awk -F' ' '{ print $1 }' 2>/dev/null`
    if [ "${old_snap}" ]
    then

        if [ "${old_snap}" != "`echo ${old_snap} | head -n 1`" ]
        then
            echo "[!] Multiple zfs snapshot found: ${old_snap}"
            echo "[!] Consider changing PREFIX or fix the issue yourself"
            continue
        fi

        if [ "${old_snap}" = "${snap}" ]
        then
            echo "[!] ${snap} exists"
            continue
        fi
    fi
    echo ${REMOTE_ZFS} snapshot "${snap}"
    ${REMOTE_ZFS} snapshot "${snap}"

    if [ "${old_snap}" ]
    then
        extra_args="-i ${old_snap}"
    else
        extra_args=""
    fi

    echo ${REMOTE_ZFS} send $extra_args "${snap}" '|' ${LOCAL_ZFS} recv -F "${POOL_DST}/${zfs_set}"
    ${REMOTE_ZFS} send $extra_args "${snap}" | ${LOCAL_ZFS} recv -F "${POOL_DST}/${zfs_set}"

    if [ "${old_snap}" ]
    then
        echo ${REMOTE_ZFS} destroy "${old_snap}"
        ${REMOTE_ZFS} destroy "${old_snap}"
    fi
done

kill $ssh_master_pid

Le script est aussi disponible sous forme de gist github.

Sur mes deux machines j'ai un user backup qui peut exécuter zfs avec sudo, l'user backup sur la machine de backup peut accéder en ssh à l'user backup (vous suivez ?) sur la machine à sauvegarder au moyen d'une clé ssh dédiée sans mot de passe.

Le script se lance donc sur la machine de backup (en ayant pris soin de créer tous les sets zfs qu'on va sauvegarder). La première fois il va transférer le set en entier, et les jours suivants il va envoyer de l'incrémental, il faut au minimum un jour entre chaque backup mais rien ne vous empêche de mettre l'heure dans le nom du snapshot.

Commentaires, patchs bienvenus.

PS: Ça fait 6 mois que j'ai pas posté sur ce blog, c'est parce que je travaille et même si je trouve encore un peu de temps pour faire mon propre code c'est moins le cas quand il faut le décrire ici. Par contre je maintient une liste de posts à faire sur ce blog, je rattraperais mon retard bientôt.

Mon réseau

Ça faisait un petit moment que je devais refaire ma homepage. C'est chose faite (rechargez la page si vous avez encore l'ancienne en cache, c'est full statique avec un trèèèès long ttl).

J'y décris un peu ce qui se passe dans les trois serveurs que j'administre, pour moi, pour les amis, pour des logiciels libres comme wmfs et pour les causes que je défends avec une association, le cerf de grésigne et un miroir wikileaks.

En modifiant ma map nagios j'ai réussi à faire quelque chose de pas mal pour mieux visualiser la chose :

network

Ça fait maintenant deux ans que l'aventure a commencée, objectif auto-hébergement et auto-formation à l'administration systèmes. Je dois dire que ça a plutôt bien marché puisque l'infrastructure et mes connaissances n'ont cessés de progresser.

  • Fin 2008 Pendant les 3 premiers mois philpep.org n'existait que sur mon portable (sous gentoo, allumé 24h/24), c'était un serveur git pour partager mon code.
  • Début 2009 j'ai récupéré un vieux pentium III gracieusement donné par une association Toulousaine sur lequel j'ai installé FreeBSD (7.0 puis 7.1) qui a commencé à faire du mail.
  • Mai 2009 je récupère un pentium 4 avec plus de RAM.
  • Fin 2009 je m'achète une alix2d3
  • Début 2010 je prends une machine virtuelle chez lost-oasis (sous FreeBSD puis Debian) pour fournir un MX et DNS secondaire.
  • Juillet 2010 je m'achète une nouvelle machine avec plus de RAM et qui consomme moins
  • Fin 2010, la machine virtuelle est maintenant chez Hetzner, et sous FreeBSD 8.1 avec un vpn entre mes deux locations.

Installer et booter une FreeBSD zfs on root depuis Debian/Grub2

date
29 / 11 / 2010
comments
3

J'ai une partition primaire de libre sur mon laptop sous Debian , je comptais y installer une FreeBSD full zfs. Le problème c'est que mon laptop n'a pas (plus) de lecteur cd, et que je me voyais mal faire une installation zfs un peu ardue en pxe et sans avoir la doc dans $BROWSER.

Alors je me dis qu'installer FreeBSD sur la partition libre depuis ma Debian testing avec zfs-fuse est possible. Évidement pas de chroot possible, mais y'a même pas besoin. Le plus dur ça a été de démarrer la FreeBSD avec grub2, mais je suis tombé sur la bonne doc. Voilà la manip sans attendre que qemu se lance.

On installe les petits (gros) tools qu'il nous faut (zfs-fuse est dans testing ou sid) :

sudo apt-get install bsdtar zfs-fuse lftp

On récupère une distribution binnaire de FreeBSD (ici 8.1-RELEASE i386)

mkdir ~/freebsd && cd ~/freebsd
lftp -c "open ftp://ftp.fr.freebsd.org/pub/FreeBSD/releases/i386/8.1-RELEASE/; mirror base"
lftp -c "open ftp://ftp.fr.freebsd.org/pub/FreeBSD/releases/i386/8.1-RELEASE/; mirror kernels"
# Et si vous voulez les man
lftp -c "open ftp://ftp.fr.freebsd.org/pub/FreeBSD/releases/i386/8.1-RELEASE/; mirror manpages"

Ensuite on crée sa pool zfs sur la partition cible (en forçant la version en 14, version de zfs sur FreeBSD)

sudo zpool create -o version=14 tank /dev/sda3
sudo zfs create tank/root
# Ici on peut créer tous les datasets qu'il nous faut

On extract tout ça :

cd ~/freebsd/base && cat base.?? | sudo bsdtar --unlink -xpzf - -C /tank/root
cd ~/freebsd/kernels && cat generic.?? | sudo bsdtar --unlink -xpzf - -C /tank/root/boot
cd ~/freebsd/manpages && cat manpages.?? | sudo bsdtar --unlink -xpzf - -C /tank/root

Les finitions :

# On utilisera le kernel GENERIC
sudo rmdir /tank/root/boot/kernel && sudo mv /tank/root/boot/GENERIC /tank/root/boot/kernel

# On copie le cache zpool pour que la freebsd retrouve "tank"
sudo cp /var/lib/zfs/zpool.cache /tank/root/boot/zfs/

# On évite un warning
sudo touch /tank/root/etc/fstab

# On se fait un rc.conf
cat << EOF | sudo tee /tank/root/etc/rc.conf
hostname="shen.philpep.org"
keymap="fr.iso.acc"
zfs_enable="YES"
EOF

# On met mountpoint / pour tank/root (comme ça tank/root/... se montera à partir de /)
sudo zpool export tank
sudo zpool import -R /mnt tank
sudo zpool set mountpoint=/ tank/root

Et maintenant le plus dur, grub2 :

menuentry 'FreeBSD' {
    insmod zfs
    search -s -l tank
    kfreebsd /root@/boot/kernel/kernel
    kfreebsd_module_elf /root@/boot/kernel/opensolaris.ko
    kfreebsd_module_elf /root@/boot/kernel/zfs.ko
    kfreebsd_module /root@/boot/zfs/zpool.cache type=/boot/zfs/zpool.cache
    set kFreeBSD.vfs.root.mountfrom=zfs:tank/root
}

Donc avec cette syntaxe on peut charger des modules au boot et écrire dans des variables sysctl (chose qu'on fait dans /boot/loader.conf avec le bootloader de FreeBSD).

Ça juste marche, et je trouve ça bien pratique, surtout qu'on peut se servir du pool zfs depuis Debian, et on peut aussi monter l'ext3 depuis FreeBSD.

EDIT: Je ne peut pas garantir que ce soit très fiable tout ça. Prudence donc. Si vous avez des problèmes au boot de FreeBSD (truc du style "alloc magic is broken") vous pouvez essayer de remplacer search -s -l tank par set root=(hd0,3) (avec la pool en /dev/sda3 chez moi).

NSD pour remplacer BIND

date
17 / 11 / 2010
comments
0

Je loue une machine virtuelle chez lost-oasis à (12€ par mois, 256Mo de RAM) pour faire du monitoring nagios, du mx/dns secondaire et du mirror http pour mes autres machines dans mon appart. Elle tourne sur Debian (en paravirtualisation kvm, virtio etc), avec de l'openvz par dessus. 256Mo ça fait pas beaucoup, et en browsant sur mon top, j'ai remarqué que c'était bind qui prenait le plus de mémoire (loin devant postgresql et php-cgi).

Je me met donc à la recherche d'un serveur dns qui serait plus léger que bind et qui fasse aussi bien dns primaire et secondaire pour mes 5 petites zones et je me souviens avoir vu passer une news à propos de l'intégration récente de nsd dans OpenBSD-Current. Ni une ni deux je dégaine mon apt-get install nsd3 et après quelques jours d'utilisation j'en suis très content.

Ce qu'il faut savoir à propos de nsd :

  • C'est un serveur authoritative only (contrairement à bind qui fait aussi cache et récursion)
  • Il est utilisé par quelques uns des root dns servers (on peut donc lui louer une certaine robustesse)
  • Il sait lire les même fichiers de zones que bind
  • La configuration est extrêmement simple
  • Il est bien plus léger en RAM que bind même configuré pour faire la même chose.
  • Il fonctionne très bien avec bind en master (j'ai pas testé dans l'autre sens)

Que du bon donc, laisser moi vous montrer un bout de config comme c'est simple :

server:
    hide-version: yes

# Une config master avec deux slaves 
zone:
    name: "philpep.org"
    zonefile: "master/philpep.org"

    notify: 217.70.177.40 NOKEY
    provide-xfr: 217.70.177.40 NOKEY

    notify: 212.85.155.53 NOKEY
    provide-xfr: 212.85.155.53 NOKEY

# Une config slave avec un master
zone:
    name: "philpep.org"
    zonefile: "slave/philpep.org"

    allow-notify: 82.229.137.130 NOKEY
    request-xfr: AXFR 82.229.137.130 NOKEY

# Apparemment nsd master ne gère que les transferts de zone AXFR (et pas IXFR)
# Ça n'a pas d'incidence l'un est testé puis l'autre si ça marche pas. Mais vous pouvez éviter
# un message de log en mettant AXFR dans request-xfr dans le cas d'un nsd master et slave.

Les zones sont strictement les mêmes que celles de bind.

Bien sûr il est possible de faire des config bien plus velues avec des clés pour faire des zones dynamiques, du chroot etc, voyez nsd.conf(5)

Il y a aussi un utilitaire bien convi pour controler le serveur : nsdc(8). Avant de démarrer le serveur pour la première fois, il faut compiler les zones avec nsdc rebuild.

J'ai trouvé nsd tellement pratique que je l'ai aussi installé en master sur mon serveur FreeBSD (dns/nsd), bind sert toujours pour le cache,récursion et mes zones en local, mais je vais certainement le remplacer par un djbdns ou un dnsmasq

Le script rc de nsd sur FreeBSD /usr/local/etc/rc.d/nsd est pas terrible, utilisez plutôt nsdc ou attendez que mon patch soit accepté :-)

NanoBSD avec / en nfs

date
3 / 11 / 2010
comments
0

Dans un précédent post j'expliquais comment utiliser le script /usr/src/tools/tools/nanobsd.sh des sources FreeBSD pour construire un système FreeBSD pour l'embarqué.

Dans le processus de création d'un tel système, il peut être utile de tester son système sans utiliser la carte flash. On peut adapter le système en le testant sur NFS et n'écrire l'image finale sur la carte flash que quand on a fini.

kernel

Il faut compiler le kernel avec support NFS et NFS comme système de fichier racine

options NFSCLIENT
options NFS_ROOT

dhcpd.conf

Avec l'option root-path on spécifie le path du montage nfs au client dhcp.

filename "pxeboot";
next-server 192.168.0.20; # le serveur tftpd
option root-path "192.168.0.20:/usr/obj/nanobsd.solo/_.w; # le montage NFS

inetd.conf

Le bootloader pxeboot est récuperé via tftp, lui même activé par inetd

tftp    dgram   udp     wait    root    /usr/libexec/tftpd      tftpd -l -s /tftpboot

pxeboot

On compile pxeboot avec un baud de 115200 sur la sortie série.

cd /usr/src/sys/boot
make BOOT_PXELDR_ALWAYS_SERIAL=1 BOOT_COMCONSOLE_SPEED=115200
mkdir /tftpboot
cp i386/pxeldr/pxeboot /tftpboot

nfs

Juste une ligne dans /etc/exports, 192.168.0.1 étant l'IP donnée par mon serveur dhcp à la machine cible.

/usr/obj/nanobsd.solo/_.w -alldirs -maproot=root 192.168.0.1

rc.conf

On active tout ça dans /etc/rc.conf

 inetd_enable="YES"
 nfs_server_enable="YES"
 rpcbind_enable="YES"
 mountd_flags="-r"
 dhcpd_enable="YES"

Et on démarre les services :

 /usr/local/etc/rc.d/isc-dhcpd start
 /etc/rc.d/inetd start
 /etc/rc.d/rpcbind start
 /etc/rc.d/nfsd start

Maintenant il faut modifier le système généré par NanoBSD car il s'attend à avoir la carte flash comme système de fichier.

J'ai juste crée une fonction dans ma config nanobsd (fonction à enlever quand on crée les images disques bien entendu) :

post_nfsroot {
    rm ${NANO_WORLDDIR}/etc/fstab
    rm ${NANO_WORLDDIR}/conf/default/etc/remount
    echo "" > ${NANO_WORLDDIR}/conf/base/etc/fstab
}

late_customize_cmd post_nfsroot

Voilà, n'oubliez pas l'option -i pour gagner le temps de construction des images disques et bon debug :)