Debian: Software-Raid mit btrfs
Hier wird gezeigt, wie zwei Festplatten als Software-Raid-1 zu einem existierenden System als Speicher hinzugefügt werden. Wir bauen das Software-Raid nicht gleich in die Formatierung beider Festplatten ein (mkfs.btrfs -L data -d raid1 -m raid1 /dev/sdb /dev/sdc /dev/sdd /dev/sde), sondern machen das nacheinander. Somit ist gleich der Weg skizziert, wenn man eine kaputte Platte tauschen muss, oder weitere hinzufügen möchte.
Fehler, Verbesserungen oder Anmerkungen können mir gern per Email geschickt werden.
Vorraussetzungen
- Halbwegs sicherer Umgang mit einer Linux Konsole / Terminal.
- Grundkenntnisse mit Partitionieren, Formatieren und Mounten.
Setup Disk 1
Zuerst werden ein paar Variablen gesetzt, welche das Leben leichter machen sollen. Im besten Fall können somit nacheinander durch wenige Anpassungen verschiedene Festplatten aufgesetzt werden. Danach folgt das Partitionieren. Falls das Werkzeug sgdisk nicht vorhanden ist, kann es mittels apt install gdisk installiert werden. Wobei ich mittlerweile eher selten das interaktive Tool gdisk verwende, sondern lieber gleich das die skriptbare Variante.
Damit das System später selbst das Gerät entschlüsseln kann, verwenden wir eine Schlüsseldatei (Keyfile). Zur Erzeugung holen wir uns 512 Zeichen Zufall aus dem passenden Generator /dev/urandom (/dev/random kann zuweilen lang dauern, weil er höhere Anforderungen an den Zufall hat). Die Schlüsseldatei wird direkt verwendet, um die Verschlüsselung zu initialisieren. Dies hat den Vorteil, dass man das manuelle Passwort nur einmal - für das Hinzufügen - eigeben muss und das Gerät auch gleich mit der Schlüsseldatei öffnen kann.
Für btrfs wird erst das entschlüsselte Gerät gemounten und dann formatiert. Darin legen wir ein Subvolume zur späteren Nutzung an. Dies hat den Vorteil, dass man später weitere Subvolumes innerhalb der gleichen Partition anlegen kann und diese dann an einen anderen Ort mounten bzw. verwenden kann. Deshalb zunächst der Umount mit dem direkt folgenden Mount des Subvolumes.
In die Crypttyp wird der Einrag mit der UUID des Gerätes geschrieben. In die fstab wird der Eintrag mit der UUID aus dem Mapper (des entschlüsselten/geöffneten Gerätes) geschrieben.
lsblk
# Disk variables.
DEV="/dev/sda"
DEVPART="/dev/sda1"
DISKNAME="datadisk1"
CRYPTNAME="crypt_${DISKNAME}"
KEYFILE="/etc/keys/${DISKNAME}.key"
DEVCRYPT=/dev/mapper/${CRYPTNAME}
LABEL="storage"
SUBVOLNAME="@storage1"
MOUNTPOINT="/media/storage"
# Partitioning.
sgdisk -p ${DEV}
sgdisk -o ${DEV}
sgdisk -n 0:0:0 ${DEV}
sgdisk -p ${DEV}
# Create a keyfile.
if [ -f ${KEYFILE} ]; then mv ${KEYFILE} ${KEYFILE}.old; fi
( umask 0077 && dd if=/dev/urandom bs=1 count=512 of=${KEYFILE} conv=excl,fsync )
chmod 600 ${KEYFILE}
# Cryptsetup.
cryptsetup luksFormat -y --type luks2 --cipher=aes-xts-plain --key-size=512 --hash=sha512 --use-urandom --key-slot=7 --key-file ${KEYFILE} ${DEVPART}
cryptsetup luksAddKey --key-file ${KEYFILE} --key-slot=0 ${DEVPART}
cryptsetup luksDump ${DEVPART}
# Open partition.
cryptsetup luksOpen --key-file ${KEYFILE} ${DEVPART} ${CRYPTNAME}
# Format partition.
mkfs.btrfs -L ${LABEL} ${DEVCRYPT}
# Mount partition.
mkdir -p ${MOUNTPOINT}
mount -t btrfs -o noatime,space_cache,commit=120,compress=zstd,autodefrag,inode_cache,defaults ${DEVCRYPT} ${MOUNTPOINT}
# Create subvolume.
btrfs subvolume create ${MOUNTPOINT}/${SUBVOLNAME}
# Umount partition.
cd /
umount ${MOUNTPOINT}
# Mount subvolume of partition.
mount -t btrfs -o noatime,space_cache,commit=120,compress=zstd,autodefrag,inode_cache,defaults,subvol=@${SUBVOLNAME} ${DEVCRYPT} ${MOUNTPOINT}
# Create crypttab entry.
# Important: UUID not PARTUUID
DEVUUID=$(blkid -o value -s UUID ${DEVPART})
echo "${CRYPTNAME} UUID=${DEVUUID} ${KEYFILE} luks,key-slot=7" >> /etc/crypttab
# Create fstab entry.
CRYPTUUID=$(blkid -o value -s UUID /dev/mapper/${CRYPTNAME})
echo "#${DEVCRYPT}" >> /etc/fstab
echo "UUID=${CRYPTUUID} ${MOUNTPOINT} btrfs rw,noatime,compress=zstd,space_cache,autodefrag,inode_cache,commit=120,subvol=/@${SUBVOLNAME},subvol=@${SUBVOLNAME} 0 0" >> /etc/fstabSetup Disk 2
Nun die nächste Disk.
lsblk
# Disk variables.
DEV="/dev/sdb"
DEVPART="/dev/sdb1"
DISKNAME="datadisk2"
CRYPTNAME="crypt_${DISKNAME}"
KEYFILE="/etc/keys/${DISKNAME}.key"
DEVCRYPT=/dev/mapper/${CRYPTNAME}
LABEL="storage2"
SUBVOLNAME="@storage2"
MOUNTPOINT="/media/storage2"
# Partitioning.
sgdisk -p ${DEV}
sgdisk -o ${DEV}
sgdisk -n 0:0:0 ${DEV}
sgdisk -p ${DEV}
# Create a keyfile.
if [ -f ${KEYFILE} ]; then mv ${KEYFILE} ${KEYFILE}.old; fi
( umask 0077 && dd if=/dev/urandom bs=1 count=512 of=${KEYFILE} conv=excl,fsync )
chmod 600 ${KEYFILE}
# Cryptsetup.
cryptsetup luksFormat -y --type luks2 --cipher=aes-xts-plain --key-size=512 --hash=sha512 --use-urandom --key-slot=7 --key-file ${KEYFILE} ${DEVPART}
cryptsetup luksAddKey --key-file ${KEYFILE} --key-slot=0 ${DEVPART}
cryptsetup luksDump ${DEVPART}
# Open partition.
cryptsetup luksOpen --key-file ${KEYFILE} ${DEVPART} ${CRYPTNAME}
# Format partition.
mkfs.btrfs -L ${LABEL} ${DEVCRYPT}
# Mount partition.
mkdir -p ${MOUNTPOINT}
mount -t btrfs -o noatime,space_cache,commit=120,compress=zstd,autodefrag,inode_cache,defaults ${DEVCRYPT} ${MOUNTPOINT}
# Create subvolume.
btrfs subvolume create ${MOUNTPOINT}/${SUBVOLNAME}
btrfs quota enable ${MOUNTPOINT}/${SUBVOLNAME}
btrfs qgroup limit 1T ${MOUNTPOINT}/${SUBVOLNAME}
btrfs qgroup show -pcre ${MOUNTPOINT}/${SUBVOLNAME}
# Umount partition.
cd /
umount ${MOUNTPOINT}
# Mount subvolume of partition.
# Redoing the mount not needed, because we'll merge it into raid1 disk.
#mount -t btrfs -o noatime,space_cache,commit=120,compress=zstd,autodefrag,inode_cache,defaults,subvol=@${SUBVOLNAME} ${DEVCRYPT} ${MOUNTPOINT}
# Create crypttab entry.
# Important: UUID not PARTUUID
DEVUUID=$(blkid -o value -s UUID ${DEVPART})
echo "${CRYPTNAME} UUID=${DEVUUID} ${KEYFILE} luks,key-slot=7" >> /etc/crypttab
# Create fstab entry.
# Not needed, because btrfs will add this via the other device above.
# Just adding the entry commented.
CRYPTUUID=$(blkid -o value -s UUID /dev/mapper/${CRYPTNAME})
echo "#${DEVCRYPT}" >> /etc/fstab
echo "#UUID=${CRYPTUUID} ${MOUNTPOINT} btrfs rw,noatime,compress=zstd,space_cache,autodefrag,inode_cache,commit=120,subvol=/@${SUBVOLNAME},subvol=@${SUBVOLNAME} 0 0" >> /etc/fstabGeräte und Setup anzeigen
Kurze Inventur, was wir angerichtet haben.
btrfs filesystem show
btrfs filesystem usage /media/storageGerät hinzufügen
Beim hinzufügen von Datadisk2 zur unter /media/storage gemounteten Datadisk1 sollte eine Warnung ausgegeben werden. Denn unter Datadisk1 wird das btrfs-Label “storage” verwendet, unter Datadisk2 das Label “storage2”. Nun sollen diese aber unter gleichen Label laufen. :-)
# All disks are decryptet and available via /dev/mapper.
# datadisk1 is mounted to /media/storage.
# datadisk2 not.
# Add: btrfs device add is used to add new devices to a mounted filesystem.
btrfs device add /dev/mapper/crypt_datadisk2 /media/storage
# Balancing: btrfs balance can balance (restripe) the allocated extents across all of the existing devices.
btrfs balance start -dconvert=raid1 -mconvert=raid1 /media/storage
btrfs balance status /media/storage
btrfs filesystem usage /media/storageGerät normal entfernen
Möchte man eine Disk auf regulärem Wege entfernen, ohne dass diese ausgefallen ist, sind dies die Schritte
# datadisk1 is mounted to /media/storage.
# datadisk2 is added to /media/storage.
# We want to remove datadisk1.
btrfs device delete /dev/mapper/crypt_datadisk1 /media/storage
cryptsetup luksClose /dev/mapper/crypt_datadisk1Kaputtes Gerät ersetzen
Der Fall ist eingetreten. Eine Platte ist ausgefallen.
# datadisk1 is broken.
# List.
btrfs filesystem show
# Mount the btrfs array.
mount -o degraded /dev/mapper/crypt_datadisk2 /media/storage
# Replacement.
btrfs replace start 7 /dev/mapper/crypt_datadisk_new /media/storage
btrfs replace status /media/storageManueller Mount
KEYFILE="/etc/keys/datadisk1.key"
DEVPART="/dev/sda1"
CRYPTNAME="crypt_datadisk1"
cryptsetup luksOpen --key-file ${KEYFILE} ${DEVPART} ${CRYPTNAME}
KEYFILE2="/etc/keys/datadisk2.key"
DEVPART2="/dev/sdb1"
CRYPTNAME2="crypt_datadisk2"
cryptsetup luksOpen --key-file ${KEYFILE2} ${DEVPART2} ${CRYPTNAME2}
btrfs filesystem show
# Both disks are configured under label "storage" with balancing as raid1.
# When mounting one device, the other is automatically used.
SUBVOLNAME="@storage1"
MOUNTPOINT="/media/storage"
mount -t btrfs -o noatime,space_cache,commit=120,compress=zstd,autodefrag,inode_cache,defaults,subvol=${SUBVOLNAME} /dev/mapper/${CRYPTNAME} ${MOUNTPOINT}
lsblk
btrfs filesystem usage ${MOUNTPOINT}
# And the way back.
umount ${MOUNTPOINT}
cryptsetup luksClose ${CRYPTNAME2}
cryptsetup luksClose ${CRYPTNAME}Helferlein
# btrfs.
btrfs filesystem show
btrfs filesystem usage /media/storage
# Show device usage.
df -h /media/storage
# Alternate ways to create a keyfile.
head -c 256 /dev/urandom > ${KEYFILE}
( umask 0077 && dd if=/dev/urandom bs=1 count=512 of=${KEYFILE} conv=excl,fsync )
umount ${MOUNTPOINT}
# Close mapper.
cryptsetup luksClose /dev/mapper/crypt_datadisk1
cryptsetup luksClose /dev/mapper/crypt_datadisk2
# Add a key using an keyfile. Important: '--key-file' should be before '--key-slot'.
cryptsetup luksAddKey --key-file ${KEYFILE} --key-slot=5 ${DEVPART} ${KEYFILE2}
# Use keyfile to remove another key.
cryptsetup luksKillSlot --key-file ${KEYFILE} ${DEVPART}Quellen
- https://mutschler.eu/linux/install-guides/ubuntu-btrfs-raid1/
- https://www.thegeekdiary.com/how-to-tune-btrfs-filesystem-for-better-performance/
- https://www.thegeekdiary.com/centos-rhel-how-to-create-and-mount-btrfs-file-system-explained-with-examples/
- https://gitlab.com/cryptsetup/cryptsetup/-/wikis/FrequentlyAskedQuestions
- https://btrfs.wiki.kernel.org/index.php/Using_Btrfs_with_Multiple_Devices