ZFS
ZFS1 ist ein sehr mächtiges Dateisystem. Es wurde ursprünglich für BSD2-Systeme entwickelt, kann aber auch unter Linux problemlos genutzt werden. ZFS unterstützt nativ Verschlüsselung, Snapshots3 und verschiedene RAID4-Funktionen. Snapshots frieren quasi den Zustand eines ZFS-Volumes ein und man kann diesen Zustand zu einem späteren Zeitpunkt wiederherstellen. Dies ist z.B. vor größeren Updates einer Software praktisch. Auch Backups können mittels Snapshots sicherer erstellt werden, da sich die Daten in einem Snapshot nicht mehr verändern. Die RAID-Funktionen von ZFS erhöhen, je nach gewähltem Typ, die Datensicherheit und/oder die Geschwindigkeit der genutzten Datenträger.
Die Installation erfolgt mittels:
apt install zfs-dkms zfsutils-linux
Sollte zfs-dkms
nicht gefunden werden, muss das Debian contrib
Repo hinzugefügt werden.
Nach der Installation kann ein sog. Pool
5 erzeugt werden:
zpool create tank mirror ata-Samsung_SSD_860_EVO_250GB_S4CJNF0M921306M ata-Samsung_SSD_860_EVO_250GB_S4CJNF0M921370X
Hier wird ein Mirror
(also RAID1) mit zwei Festplatten angelegt. Die IDs der Platten können mittels ls -lah /dev/disk/by-id/
ermittelt werden.
Als nächstes erzeugen wir ein Kennwort für die Festplattenverschlüsselung und legen dieses in einer Datei ab:
pwgen -1 500 > /root/zfs_cryptkey
chmod 600 /root/zfs_cryptkey
Die Datei /root/zfs_cryptkey
sollte gut gesichert werden, bestenfalls in einem Passworttresor oder ähnlichem. Verlieren wir diese Datei, können wir nicht mehr auf die auf unseren ZFS-Volumes gespeicherten Daten zugreifen. Es gibt keine Recoverymöglichkeit (außer ein entsprechendes Daten-Backup natürlich).
Nun können wir innerhalb des Pools
unsere Laufwerke anlegen:
zfs create -o encryption=on -o keyformat=passphrase -o keylocation=file:///root/zfs_cryptkey tank/data
zfs create -o mountpoint=/docker/gitea tank/data/gitea
Zunächst erzeugen wir einen verschlüsselten Container, ohne Mountpoint. Innerhalb davon legen wir dann unsere eigentlichen Laufwerke an. Die Verschlüsselungseinstellungen des übergeordneten Containers werden hierbei übernommen. Genau aus diesem Grund ist ein übergeordnetes Element auch praktisch, notwendig ist es aber nicht zwingend. Durch die Angabe der Mountpoints werden die Laufwerke automatisch ins System eingebunden und stehen sofort zur Nutzung bereit. gitea
ist hier natürlich nur als Beispiel zu verstehen. Ich lege gern ein Volume pro Docker-Container an, dies erleichtert später die Nutzung von Snapshots.
Legen wir noch ein paar Laufwerke an, diese ohne übergeordnetes Element:
zfs create -o encryption=on -o encryption=aes-256-gcm -o keyformat=passphrase -o keylocation=file:///root/zfs_cryptkey -mountpoint=/var/www tank/www
zfs create -o encryption=on -o encryption=aes-256-gcm -o keyformat=passphrase -o keylocation=file:///root/zfs_cryptkey -mountpoint=/opt tank/opt
zfs create -o encryption=on -o encryption=aes-256-gcm -o keyformat=passphrase -o keylocation=file:///root/zfs_cryptkey -mountpoint=/var/lib/docker tank/docker
Achtung: /var/lib/docker
wird ggf. von Docker genutzt. In diesem Fall sollte Docker zunächst gestoppt und die Daten in /var/lib/docker
in ein temporäres Verzeichnis verschoben werden. Nachdem das ZFS Volume erzeugt und gemoutet wurde, kann man dann die Daten wieder dorthin verschieben und Docker wieder starten.
Der Status des Pools lässt sich mittels zpool status
abfragen:
pool: tank
state: ONLINE
scan: scrub repaired 0B in 00:05:22 with 0 errors on Sun Dec 11 00:29:23 2022
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
ata-Samsung_SSD_860_EVO_250GB_S4CJNF0M921306M ONLINE 0 0 0
ata-Samsung_SSD_860_EVO_250GB_S4CJNF0M921370X ONLINE 0 0 0
errors: No known data errors
Um uns automatisch über den Zustand unseres ZFS informieren zu lassen, können wir zed
6 nutzen:
apt install zfs-zed
In die zed
Konfiguration nehmen wir nun unsere Mailadresse auf:
##
# zed.rc
#
# This file should be owned by root and permissioned 0600.
##
##
# Absolute path to the debug output file.
#
#ZED_DEBUG_LOG="/tmp/zed.debug.log"
##
# Email address of the zpool administrator for receipt of notifications;
# multiple addresses can be specified if they are delimited by whitespace.
# Email will only be sent if ZED_EMAIL_ADDR is defined.
# Disabled by default; uncomment to enable.
#
ZED_EMAIL_ADDR="root@example.org"
##
# Name or path of executable responsible for sending notifications via email;
# the mail program must be capable of reading a message body from stdin.
# Email will only be sent if ZED_EMAIL_ADDR is defined.
#
ZED_EMAIL_PROG="mail"
##
# Command-line options for ZED_EMAIL_PROG.
# The string @ADDRESS@ will be replaced with the recipient email address(es).
# The string @SUBJECT@ will be replaced with the notification subject;
# this should be protected with quotes to prevent word-splitting.
# Email will only be sent if ZED_EMAIL_ADDR is defined.
#
ZED_EMAIL_OPTS="-s '@SUBJECT@' @ADDRESS@"
##
# Default directory for zed lock files.
#
#ZED_LOCKDIR="/var/lock"
##
# Minimum number of seconds between notifications for a similar event.
#
ZED_NOTIFY_INTERVAL_SECS=3600
##
# Notification verbosity.
# If set to 0, suppress notification if the pool is healthy.
# If set to 1, send notification regardless of pool health.
#
ZED_NOTIFY_VERBOSE=1
##
# Send notifications for 'ereport.fs.zfs.data' events.
# Disabled by default, any non-empty value will enable the feature.
#
#ZED_NOTIFY_DATA=
##
# Pushbullet access token.
# This grants full access to your account -- protect it accordingly!
# <https://www.pushbullet.com/get-started>
# <https://www.pushbullet.com/account>
# Disabled by default; uncomment to enable.
#
#ZED_PUSHBULLET_ACCESS_TOKEN=""
##
# Pushbullet channel tag for push notification feeds that can be subscribed to.
# <https://www.pushbullet.com/my-channel>
# If not defined, push notifications will instead be sent to all devices
# associated with the account specified by the access token.
# Disabled by default; uncomment to enable.
#
#ZED_PUSHBULLET_CHANNEL_TAG=""
##
# Slack Webhook URL.
# This allows posting to the given channel and includes an access token.
# <https://api.slack.com/incoming-webhooks>
# Disabled by default; uncomment to enable.
#
#ZED_SLACK_WEBHOOK_URL=""
##
# Default directory for zed state files.
#
#ZED_RUNDIR="/var/run"
##
# Turn on/off enclosure LEDs when drives get DEGRADED/FAULTED. This works for
# device mapper and multipath devices as well. Your enclosure must be
# supported by the Linux SES driver for this to work.
#
ZED_USE_ENCLOSURE_LEDS=0
##
# Run a scrub after every resilver
# Disabled by default, 1 to enable and 0 to disable.
#ZED_SCRUB_AFTER_RESILVER=0
##
# The syslog priority (e.g., specified as a "facility.level" pair).
#
ZED_SYSLOG_PRIORITY="daemon.notice"
##
# The syslog tag for marking zed events.
#
ZED_SYSLOG_TAG="zed"
##
# Which set of event subclasses to log
# By default, events from all subclasses are logged.
# If ZED_SYSLOG_SUBCLASS_INCLUDE is set, only subclasses
# matching the pattern are logged. Use the pipe symbol (|)
# or shell wildcards (*, ?) to match multiple subclasses.
# Otherwise, if ZED_SYSLOG_SUBCLASS_EXCLUDE is set, the
# matching subclasses are excluded from logging.
#ZED_SYSLOG_SUBCLASS_INCLUDE="checksum|scrub_*|vdev.*"
ZED_SYSLOG_SUBCLASS_EXCLUDE="history_event"
##
# Use GUIDs instead of names when logging pool and vdevs
# Disabled by default, 1 to enable and 0 to disable.
#ZED_SYSLOG_DISPLAY_GUIDS=1
Anschließend starten wir zed
neu:
/etc/init.d/zfs-zed restart
Außerdem fügen wir ein paar Housekeeping-Job in unsere Crontab7 hinzu:
0 2 1 * * /sbin/zpool scrub tank 2>&1 | mail -s "Scrub status" root@example.org
0 13 1 * * /sbin/zpool status 2>&1 | mail -s "zpool status" root@example.org
Desweiteren bietet es sich an, regelmäßige Snapshots zu erstellen. Hierfür können wir zfsnap
8 nutzen:
apt install zfsnap
Hierfür erzeugen wir noch ein kleines Shellscript:
#!/bin/bash
volumes=$(/usr/sbin/zfs list | /usr/bin/grep 'tank/' | /usr/bin/grep -v docker | /usr/bin/awk '{print $1}')
for x in ${volumes}; do
echo "${x}"
/usr/sbin/zfSnap -v -d -z -S -a 14d ${x}
echo ""
done
echo "tank/docker"
/usr/sbin/zfSnap -v -d -z -S -a 14d tank/docker
Das Script listet alle Volumes im Pool tank
auf. Volumes mit docker
im Namen werden ausgenommen, da Docker, sofern es Daten auf ZFS Dateisystemen ablegt, automatisch Volumes und Snapshot für Images erzeugt. Da wir selbst ein Volume mit dem Namen tank/docker
erzeugt haben, sorgen wir im Anschluss separat noch dafür, dass auch dieser einen Snapshot erhält.
Das Script binden wir als Cronjob ein:
0 23 * * * /root/zfsnap.sh 2>&1 | mail -s "Snapshot status" root@example.org