Opis będzie dotyczył instalacja na całym dysku, na którym jedynym systemem będzie nasz Debian. Wszystkie dane które wcześniej były na dysku zostaną utracone. Używamy sektorów o rozmiarach 4KB, nawet jeśli nasz dysk ma sektory 512B warto użyć sektorów logicznych 4K, ponieważ po zmianie dysku na 4KB utracimy bardzo dużo na wydajności. Trzeba zaznaczyć, że poprawne działanie GRUBa z sektorami 4KB jest możliwe tylko na komputrach obsługujących UEFI. Wymóg posiadania minimum 2GB RAM (lepiej 4GB+) przy komputerach z UEFI raczej nie jest już problemem. Zakładamy, że nasz system będzie instalowany na dwóch dyskach na puli "lustrzanej".
Na komputrze uruchamiamy Debiana Bullseye w wersji live, konfigurujemy dostęp do Internetu. W systemie live jest domyślnie użytkownik user z hasłem live.
Dodajemy do repozytoriów standardowych repozytorium contrib
sudo su -
apt update
apt install mc mdadm
mcedit /etc/apt/sources.list
deb http://deb.debian.org/debian bullseye main contrib
apt update
Jeżeli zależy nam na tym by wygodnie kontynuować proces z innego komputera możemy doinstalować serwer SSH:
apt install --yes openssh-server
systemctl restart ssh
Wyłączamy automontowanie, które może przeszkadzać w dalszej pracy
gsettings set org.gnome.desktop.media-handling automount false
Instalujemy ZFS w środowisku instalacyjnym
apt install --yes debootstrap gdisk zfsutils-linux
Należy pamiętać by dyski wskazywać zawsze po id ponieważ zmiana kolejności dysków bądź dopięcie nowego nie będzie wtedy miała wpływu na naszą pulę. Pozwoli to też na łatwą identyfikację dysków - zwykle na etykiecie jest numer dysku który jest użyty w identyfikatorze.
Ustawiamy zmienne odwołujące się do naszych dysków:
DISK_A=/dev/disk/by-id/ata-XXX-YYY1
DISK_B=/dev/disk/by-id/ata-XXX-YYY2
Możemy łatwo sprawdzić do jakiego urządzenia odnośi się alias by-id używając ls -la /dev/disk/by-id
Jeżeli używamy QEMU/KVM to można wskazywać urządzenia przez z /dev/vdX ponieważ domyślnie nie mamy przypisanych identyfikatorów na podstawie numerów seryjnych. Numery seryjne można dodać w przypadku jeśli używamy sterownika dysków virtio. Numer seryjny podajemy jako parametr serial=123123 bądź w przypadku virt-manager w genialnie przetłumaczonym na polski polu "szeregowy" ;)
VMware wymaga ustawienia disk.EnableUUID = "TRUE"
Czyścimy dyski Upewniamy się, że na żadym z dysków nie jest aktywny swap
swapoff -all
Jeżeli na dyskach była wcześniej macierz MD usuwamy ją:
# Sprawdzamy aktywne macierze:
cat /proc/mdstat
# Jeśli są to zatrzymujemy je (zastępujemy md0 właściwym identyfikatorem):
mdadm --stop /dev/md0
# Dla macierzy na całym dysku:
mdadm --zero-superblock --force $DISK
# dla macierzy na partycji
mdadm --zero-superblock --force ${DISK}-part2
Czyściemy tablicę partycji:
sgdisk --zap-all $DISK_A
sgdisk --zap-all $DISK_B
Jeżeli pojawił się komunikat o tym, że kernel nadal używa starej tablicy partycji to możemy użyć part-probe a jeśli to nie pomoże to musimy przeładować system.
Partycjonowanie Partycja EFI:
sgdisk -n1:0:+512M -t1:EF00 $DISK_A
sgdisk -n1:0:+512M -t1:EF00 $DISK_B
Partycja /boot
sgdisk -n2:0:+1G -t2:BF01 $DISK_A
sgdisk -n2:0:+1G -t2:BF01 $DISK_B
Partycja na pulę:
sgdisk -n3:0:0 -t3:BF00 $DISK_A
sgdisk -n3:0:0 -t3:BF00 $DISK_B
Jeżeli dysków w macierzy ma być więcej to powyższy układ partycji należy skopiować na pozostałe dyski.
sgdisk -R /dev/sdb /dev/sda
sgdisk -G /dev/sdb
:warning Koleność dysków w tym poleceniu jest nietypowa. Pierwsze polecenie skopiuje układ partycji z dysku sda na dysk sdb. Drugie polecenie nada nowy, indywidualny GUID na dysku sdb.
Tworzymy pule na partycję /boot
zpool create \
-o cachefile=/etc/zfs/zpool.cache \
-o ashift=12 -d \
-o feature@async_destroy=enabled \
-o feature@bookmarks=enabled \
-o feature@embedded_data=enabled \
-o feature@empty_bpobj=enabled \
-o feature@enabled_txg=enabled \
-o feature@extensible_dataset=enabled \
-o feature@filesystem_limits=enabled \
-o feature@hole_birth=enabled \
-o feature@large_blocks=enabled \
-o feature@livelist=enabled \
-o feature@lz4_compress=enabled \
-o feature@spacemap_histogram=enabled \
-o feature@zpool_checkpoint=enabled \
-O acltype=posixacl -O canmount=off -O compression=lz4 \
-O devices=off -O normalization=formD -O relatime=on -O xattr=sa \
-O mountpoint=/boot -R /mnt \
bpool mirror ${DISK_A}-part2 ${DISK_B}-part2
Ze względu na to, że GRUB nie obsługuje wszystkich funkcji ZFS zaleca się nie zmieniać powyższych parametrów. GRUB montuje bpool tylko w trybie do odczytu, dopiero po załadowaniu całego systemu Debian może modyfikować dane w puli bpool.
zpool create \
-o ashift=12 \
-O acltype=posixacl -O canmount=off -O compression=lz4 \
-O dnodesize=auto -O normalization=formD -O atime=off \
-O xattr=sa -O mountpoint=/ -R /mnt \
rpool mirror ${DISK_A}-part3 ${DISK_B}-part3
atime=off wyłączając oznaczanie dat dostępu do plików zyskując największą wydaność. Jeżeli chcemy zachować balans między wydajnością a działaniem czasów dostępu można zamiast tego dać parametr relatime=on.-part3 przy wskazywaniu miejsca na pulę. Pominięcie wskazania partycji spowoduje, że ZFS na pulę przydzieli cały dysk i utracimy przy tym partycję /boot i EFI.zfs create -o canmount=off -o mountpoint=none rpool/ROOT
zfs create -o canmount=off -o mountpoint=none bpool/BOOTRobiąc snapshot/kopię kontenera uzyskujemy prostą możliwość wersjnowania całego systemu.
Tworzymy datasety dla katalogu głównego i /boot
zfs create -o canmount=noauto -o mountpoint=/ rpool/ROOT/debian
zfs mount rpool/ROOT/debian
zfs create -o mountpoint=/boot bpool/BOOT/debian
Systemów plików ZFS nie trzeba normalnie montować używając mount lub zfs mount. Tutaj mamy wyjątek ponieważ użyliśmy opcji canmount=noauto.
Tworzymy pozostałe datasety
zfs create rpool/home
zfs create -o mountpoint=/root rpool/home/root
chmod 700 /mnt/root
zfs create -o canmount=off rpool/var
zfs create -o canmount=off rpool/var/lib
zfs create rpool/var/log
zfs create rpool/var/spool
Opcjonalne datasety
zfs create -o com.sun:auto-snapshot=false rpool/var/cache
zfs create -o com.sun:auto-snapshot=false rpool/var/tmp
chmod 1777 /mnt/var/tmp
zfs create rpool/opt
zfs create -o canmount=off rpool/usr
zfs create rpool/usr/local
zfs create rpool/var/games
zfs create rpool/var/mail
zfs create rpool/var/snap
zfs create rpool/var/lib/AccountsService
#Docker używa swojego własnego systemu wersjonowania i snapshotów
zfs create -o com.sun:auto-snapshot=false rpool/var/lib/docker
zfs create -o com.sun:auto-snapshot=false rpool/var/lib/nfs
Celem rozbudowanego zestawu datasetów jest rozdzielenie danych użytkownika od systemu. Dzięki temu można dowolnie manipulować danymi użytkowników bez wpływu na system bądź systemem z zachowaniem danych użytkowników w stanie nietkniętym.
Katalog /tmp umieścimy w pamięci RAM (tmpfs) i zrobimy to później
Instalujemy system w wersji minimalnej:
debootstrap bullseye /mnt
System który w ten sposób będzie utworzyny będzie nieskonfigurowany, później skonfigurujemy go ręcznie.
zpool.cache
mkdir /mnt/etc/zfs
cp /etc/zfs/zpool.cache /mnt/etc/zfs/
Nazwa hosta
hostname HOSTNAME
hostname > /mnt/etc/hostname
mcedit /mnt/etc/hosts
#Dodajemy linię:
127.0.1.1 HOSTNAME
Konfiguracja interfejsów sieciowych Odnajdujemy nazwy interfejsów
ip addr show | grep mtu
Tworzymy pliki dla potrzebnych interfejsów zastępując NAZWA właściwą nazwą interfejsu
mcedit /mnt/etc/network/interfaces.d/NAZWA
auto NAME
iface NAME inet dhcp
Jeżeli interfejs nie jest konfigurowany po DHCP to należy odpowiednio zmodyfikować zawartość pliku.
Konfiguracja repozytoriów pakietów
mcedit /mnt/etc/apt/sources.list
deb http://deb.debian.org/debian bullseye main contrib
deb-src http://deb.debian.org/debian bullseye main contrib
deb http://deb.debian.org/debian-security bullseye-security main contrib
deb-src http://deb.debian.org/debian-security bullseye-security main contrib
deb http://deb.debian.org/debian bullseye-updates main contrib
deb-src http://deb.debian.org/debian bullseye-updates main contrib
Przepięcie wirtualnych systemów plików z systemu live do nowego systemu i wykonanie chroot:
mount --rbind /dev /mnt/dev
mount --rbind /proc /mnt/proc
mount --rbind /sys /mnt/sys
chroot /mnt bash --login
Konfiguracja podstawowego systemu
DISK_A=/dev/disk/by-id/ata-XXX-YYY1
DISK_B=/dev/disk/by-id/ata-XXX-YYY2
ln -s /proc/self/mounts /etc/mtab
apt update
apt install --yes console-setup locales mc
Nawet jeśli nasz system będzie używał języka inny niż angielski zawsze dodajemy en_US.UTF-8
dpkg-reconfigure locales tzdata keyboard-configuration console-setup
Instalacja ZFS w nowym systemie
apt install --yes dpkg-dev linux-headers-amd64 linux-image-amd64
apt install --yes zfs-initramfs
echo REMAKE_INITRD=yes > /etc/dkms/zfs.conf
Instalacja GRUB na systemie z UEFI
apt install dosfstools
mkdosfs -F 32 -s 1 -n EFI ${DISK_A}-part1
mkdir /boot/efi
echo /dev/disk/by-uuid/$(blkid -s UUID -o value ${DISK_A}-part1) /boot/efi vfat defaults 0 0 >> /etc/fstab
mount /boot/efi
apt install --yes grub-efi-amd64 shim-signed
GRUB jest instalowany tylko na jednym dysku - później zostanie zainstalowany na drugim by mirror działał prawidłowo.
Usunięcie os-prober
apt purge --yes os-prober
Pakiet jest potrzebny tylko przy instalacji wielu systemów. W innym przypadku generuje tylko niepotrzebne komunikaty.
Ustawiamy hasło roota
passwd
Import puli bpool
Tworzymy moduł systemd który będzie zawsze importował pulę bpool przy stacie systemu.
mcedit /etc/systemd/system/zfs-import-bpool.service
[Unit]
DefaultDependencies=no
Before=zfs-import-scan.service
Before=zfs-import-cache.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/sbin/zpool import -N -o cachefile=none bpool
# Work-around to preserve zpool cache:
ExecStartPre=-/bin/mv /etc/zfs/zpool.cache /etc/zfs/preboot_zpool.cache
ExecStartPost=-/bin/mv /etc/zfs/preboot_zpool.cache /etc/zfs/zpool.cache
[Install]
WantedBy=zfs-import.target
systemctl enable zfs-import-bpool.service
Montowanie /tmp w pamięci RAM (tmpfs) Proces sprowadza się do dodaniu odpowiedniego modułu dla systemd
cp /usr/share/systemd/tmp.mount /etc/systemd/system/
systemctl enable tmp.mount
Instalacja serwera SSH
apt install --yes openssh-server
mcedit /etc/ssh/sshd_config
# Ustawiamy: PermitRootLogin yes
# to tylko tymczasowe póki w systemie nie ma innych użytkowników
Instalacja popcon Nie jest to krok obowiązkowy ale pomaga twórcom Debiana w dobieraniu optymalnych składników systemu
apt install --yes popularity-contest
Sprawdzamy czy GRUB rozpoznaje pulę /boot
grub-probe /boot
Odświeżamy plik initrd
update-initramfs -c -k all
Obejście pozwalające uniknąć problemów z niewspieraniem przez GRUB niektórych funkcji ZFS
mcedit /etc/default/grub
# Ustawiamy: GRUB_CMDLINE_LINUX="root=ZFS=rpool/ROOT/debian"
Rozszerzenie debugowania GRUB
mcedit /etc/default/grub
# Usuwamy quiet z: GRUB_CMDLINE_LINUX_DEFAULT
# Odkomentowujemy: GRUB_TERMINAL=console
Aktualizacja GRUBa
update-grub
Instalacja bootloadera
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=debian --recheck --no-floppy
Ustalenie prawidłowej kolejności montowania systemów plików
Uruchomienie zfs-mount-generator przekaże systemd informacje o tym, że system ma wiele punktów montowania dla różnych katalogów co jest szczególnie ważne w przypadku /var/log i /var/tmp.
mkdir /etc/zfs/zfs-list.cache
touch /etc/zfs/zfs-list.cache/bpool
touch /etc/zfs/zfs-list.cache/rpool
zed -F &
Sprawdzamy czy zed zaktualizował cache patrząc na zawartość plików:
cat /etc/zfs/zfs-list.cache/bpool
cat /etc/zfs/zfs-list.cache/rpool
Jeżeli są puste to wymuszamy ponowną i aktualizacje i sprawdzamy
zfs set canmount=off bpool/BOOT/debian
zfs set canmount=on bpool/BOOT/debian
zfs set canmount=off bpool/ROOT/debian
zfs set canmount=noauto bpool/ROOT/debian
Jeżeli pliki nadal są puste to zatrzymujemy zed (jak poniżej) i uruchamiamy procedurę jeszcze raz.
fg
#Naciskamy Ctrl+C
Usuwamy ze ścieżek /mnt
sed -Ei "s|/mnt/?|/|" /etc/zfs/zfs-list.cache/*
Możemy utworzyć snapshoty świeżego systemu
zfs snapshot bpool/BOOT/debian@install
zfs snapshot rpool/ROOT/debian@install
Warto robić snapshota przed każdą poważniejszą aktualizacją bądź zmianą. Stare snapshoty (w tym ten poinstalacyjny) można w przyszłości usunąć odzyskując nieco miejsca.
Wychodzimy z chroot wracając do środowiska live
exit
Odmontowujemy wszystkie systemy plików
mount | grep -v zfs | tac | awk '/\/mnt/ {print $3}' | xargs -i{} umount -lf {}
zpool export -a
Uruchamiamy ponownie komputer
reboot
Tworzenie nowych użytkowników Logujemy się jako root z ustalonym wcześniej hasłem i wydajemy polecenia zastępująć NAZWA_UŻYTKOWNIKA odpowiednim loginem
username=NAZWA_UŻYTKOWNIKA
zfs create rpool/home/$username
adduser $username
cp -a /etc/skel/. /home/$username
chown -R $username:$username /home/$username
usermod -a -G audio,cdrom,dip,floppy,netdev,plugdev,sudo,video $username
Tworzymy mirror GRUBa
umount /boot/efi
dd if=/dev/disk/by-id/ata-SATA_diskA-part1 of=/dev/disk/by-id/ata-SATA_diskB-part1
efibootmgr -c -g -d /dev/disk/by-id/ata-SATA_diskB -p 2 -L "debian-2" -l '\EFI\debian\grubx64.efi'
mount /boot/efi
Aktualizacja systemu
apt update
apt dist-upgrade --yes
Instalacja zestawów oprogramowania
tasksel
Wybieramy potrzebne zestawy oprogramowania.
Instalacja pozostałego oprogramowania
apt install mc iptraf iperf nmon htop iotop smartmontools lm-sensors wget
Wyłączamy kompresję logów
for file in /etc/logrotate.d/* ; do
if grep -Eq "(^|[^#y])compress" "$file" ; then
sed -i -r "s/(^|[^#y])(compress)/\1#\2/" "$file"
fi
done
Dane w datasetach są kompresowane przez ZFS - podówjna kompresja nic nie daje poza stratą zasobów. Dodatkowo przy braku kompresji logów na poziomie plików mamy cały czas nieskrępowany dostęp do wszystkich logów.
Reboot
reboot
Logujemy się do systemu, sprawdzamy czy nowi użytkownicy działają i czy nie ma problemów z funkcjonowaniem sieci.
Opcjonalnie usuwamy snapshoty poinstalacyjne
sudo zfs destroy bpool/BOOT/debian@install
sudo zfs destroy rpool/ROOT/debian@install
Opcjonalnie wyłączamy konto root
sudo usermod -p '*' root
Wyłączamy dostęp dla roota po SSH
sudo vi /etc/ssh/sshd_config
# Usuwamy: PermitRootLogin yes
sudo systemctl restart ssh