F/OSS gestito in modo sostenibile Archiviazione oggetti, Redis, Prometheus su Hetzner, OVH e LeaseWeb **tl;dr - Spiegazione riga per riga del mio script di installazione ZFS con tecnologia ansible da utilizzare sull'hardware dedicato di Hetzner (Ubuntu 20.04 - âÂÂFocalâÂÂ) â non è perfetto/minimale, ma per me funziona Qualche tempo fa ho iniziato a utilizzare ZFS su tutto il mio hardware dedicato bare metal ospitato presso Hetzner per gestire gli HDD e gli SSD collegati. Ci sono molte scelte nello spazio (LVM standard, mdraid btrfs, ecc.), ma ho scelto ZFS per le sue caratteristiche ed ergonomia. Non annoierò nessuno con il perché, ma una delle cose di cui avevo bisogno per navigare era come installare le versioni più recenti di ZFS su Ubuntu 20.04 (uno dei sistemi operativi supportati da Hetzner). Ho riscontrato alcuni problemi (in particolare post-installazione) durante l'impostazione di ZFS sui miei sistemi, quindi volevo fornire una panoramica di come l'ho fatto. Questo post è una spiegazione stanza per stanza dei miei script Ansible che installano ZFS. Prima di sapere se vale la pena passare a ZFS (o qualsiasi filesystem), probabilmente vorrai RTFM. ZFS ha molti dettagli e io non ne sono certo un esperto, ma conoscere il come e il perché, così come la terminologia e persino la storia del progetto è molto importante. Alcuni link per iniziare: Insieme a ZFS (che è probabilmente la quantità più sconosciuta qui) probabilmente vorrai avere familiarità con Ubuntu e l'amministrazione generale dei sistemi. Questa è una vasta area da coprire, ma ecco alcuni link: È quasi ovvio, ma se non hai molta familiarità con l'amministrazione del sistema Linux a questo punto, probabilmente non dovresti tentare questo. Personalmente scelgo di avere i miei dischi in una configurazione in qualche modo personalizzata â Ho una configurazione RAID1 (mirroring) tramite mdraid, insieme alle partizioni su ciascun disco che posso affidare a ZFS per la gestione. Idealmente, avrei interi dischi da dare a ZFS, ma anche le partizioni funzionano. configurazione del sistema operativo ( installimage) che include la configurazione del disco viene eseguito dalla modalità di ripristino di Hetzner e può essere guidato con un file come il seguente: # Dichiarazioni unità utilizzate da installimage DRIVE0 /dev/nvme0n1 DRIVE1 /dev/nvme1n1 # Abilita RAID software (per il disco del sistema operativo) SWRAID 1 SWRAIDLEVEL 1 # Bootloader (generalmente grub) BOOTLOADER grub # Nome host macchina HOSTNAME macchina01 # Partizione configuration PART swap swap 32G PART /boot ext4 1G PART / ext4 128G # Verrà eseguita quest'ultima partizione (cancellata& ricreato come ZFS in seguito) PART /root-disk-remaining ext4 all # È possibile specificare le immagini utilizzate da Hetzner accedendo alla loro condivisione di rete IMAGE /root/.oldroot/nfs/images/Ubuntu-2004-focal-64-minimal.tar. gz Questo è ovviamente abbastanza specifico di Hetzner, ma fai tutto ciò che devi fare sui tuoi sistemi per avere partizioni/unità disponibili per ZFS da utilizzare. zfsutils-linux e zfs-zed In Ansible YAML il passaggio è simile al seguente: - name: contiene tutti i pacchetti upstream relativi a zfs ansible.builtin.shell: | apt-mark hold zfsutils-linux apt-mark hold zfs-zed Al momento della stesura di questo post la versione di zfs-linux in Ubuntu Focal è 0.8.3. Poiché il nostro obiettivo qui è installare e continuare a utilizzare una versione più recente, vogliamo assicurarci che qualsiasi Gli aggiornamenti apt non sostituiscono la nostra versione installata con una versione precedente. Già che siamo qui, eliminiamo anche i pacchetti. - nome: elimina i pacchetti ZFS upstream (ubuntu) se installati ignore_errors: sì ansible.builtin.command: | apt purge --allow-change-held-packages zfsutils-linux zfs-zed Puoi leggere i documenti su adatto a vedere cosa purge è simile a remove ma rimuove anche i file di configurazione se presenti. Puoi installare le dipendenze per OpenZFS in questo modo: - name: requisiti di installazione per la creazione di ZFS ansible.builtin.apt: name:packagesupdate_cache: yes state: present vars: packages: - build-essential - autoconf - automake - libtool - gawk - alien - fakeroot - dkms - libblkid-dev - uuid -dev - libudev-dev - libssl-dev - zlib1g-dev - libaio-dev - libattr1-dev - libelf-dev # La riga seguente richiede l'output di `uname -r`, ad esempio "5.16.5-arch1- 1"per il mio sistema arch # in modo che la riga si risolva in qualcosa come "linux-headers-5.16.5-arch1-1"(non valido su Ubuntu ovviamente, ma come esempio) - linux-headers uname_r.stdout }} - python3 - python3-dev - python3-setuptools - python3-cffi - libffi-dev - python3-packaging - git - libcurl4-openssl-dev Potrebbero esserci alcune dipendenze che non sono strettamente necessarie, ma dovrebbero essere necessarie quasi tutte. /opt/zfs Ecco ZFS: - nome: Crea /opt/zfs ansible.builtin.file: percorso: /opt/zfs stato: directory Se vuoi scaricare ZFS: - nome: Scarica zfs ansible.builtin.get_url: url: "httpsgithub.com/openzfs/zfs/releases/download/zfs _zfs_version zfs _zfs_version tar.gz"checksum:_zfs_tarball_sha256_checksummode: 0755 dest: "/opt/zfs/zfs _zfs_version tar .gz"Qui la sostituzione {{ _zfs_version }} ( 2.1.1. Dovrai anche eseguire tu stesso il download e raccogliere/generare un checksum da utilizzare. Non scaricare mai materiale da Internet che non dovrebbe cambiare senza un checksum! {{è la sintassi dei modelli di Ansible) è E se vuoi copiarlo dal computer su cui è in esecuzione Ansible (questo è quello che faccio): - name: Copia il pacchetto zfs (evita il limite di velocità) ansible.builtin.copy: src: files/zfs/zfs _zfs_version tar.gz"mode: 0755 dest: "/opt/zfs/zfs _zfs_version tar.gz"Indipendentemente da come scegli di ottenere la fonte, ovviamente dovrai decomprimerla: - name: Unzip zfs code ansible.builtin.unarchive: src: "/opt/zfs/zfs _zfs_version tar.gz"dest: "/opt/zfs"remote_src: yes Per avviare il processo di compilazione: - nome: Imposta e crea ZFS ansible.builtin.shell: | ./autogen../configure make clean make -j args: chdir: "/opt/zfs/zfs _zfs_version Se hai familiarità con la creazione di cose dal sorgente, vari progetti utilizzano questo set di strumenti comune (alcune varianti di script make, autogen e configure). Come ci si potrebbe aspettare, questo potrebbe richiedere del tempo, quindi concedigli un po'di tempo. Dopo aver creato ZFS - nome: Installa ZFS ansible.builtin.shell: | make install args: chdir: "/opt/zfs/zfs _zfs_version Normalmente penseresti che avremmo finito *proprio qui*, ma questo post esiste perché farlo generalmente non è sufficiente! Andiamo avanti. Per prima cosa forzare lo scaricamento dei moduli ZFS se sono in esecuzione: - name: forza lo scaricamento dei moduli ZFS ansible.builtin.shell: | ./scripts/zfs.-u argomenti: chdir: "/opt/zfs/zfs _zfs_version L'ideale sarebbe *non* eseguire alcun carico di lavoro quando ciò accade, come ci si potrebbe aspettare. Mentre i moduli sono scaricati, possiamo installare alcuni helper: - nome: helper ZFS post-installazione ansible.builtin.shell: | ./scripts/zfs-helpers.-i args: chdir: "/opt/zfs/zfs _zfs_version Dopo che gli helper sono stati installati, carichiamo forzatamente il modulo ZFS: - name: forza il ricaricamento del modulo ZFS ansible.builtin.shell: | ./scripts/zfs.args: chdir: "/opt/zfs/zfs _zfs_version Ho trovato quell'edificio e l'ho usato Il modulo deb (il formato utilizzato da Debian per l'installazione dei pacchetti) ha aiutato anche a far sì che l'installazione si attacchi e non venga sostituita dalle impostazioni predefinite del pacchetto Ubuntu. Per prima cosa crea il pacchetto deb ZFS dal codice sorgente: - nome: Crea pacchetto deb ZFS ansible.builtin.shell: | make deb args: chdir: "/opt/zfs/zfs _zfs_version E poi installalo - nome: installa i pacchetti deb ZFS ansible.builtin.shell: | si | dpkg -i --force-overwrite deb apt install -f -y deb args: chdir: "/opt/zfs/zfs _zfs_version Teoricamente questo passaggio *non dovrebbe* essere necessario (o dovrebbe essere usato da solo), poiché abbiamo già eseguito un processo di installazione, ma ho scoperto che quando si esegue l'uno o l'altro Ci sarebbero situazioni in cui i riavvii richiederebbero l'utilizzo di una versione precedente di ZFS (nonostante il apt purge) â in particolare a livello di kernel. modprobe Se vuoi abilitare il modulo ZFS che è stato installato immediatamente, usa sonda mod: - nome: Modprobe zfs module block: - nome: Installa zfs kernel module community.general.modprobe: nome: zfs state: presente Installare ZFS significa installare un modulo del kernel, ma dal momento che non l'abbiamo ancora inserito tramite Dynamic Kernel Module Support, dobbiamo abilitare l'utilizzo dei moduli del kernel installati localmente: - nome: assicurati che extra sia in primo piano ansible.builtin.lineinfile: percorso: /etc/modules-load.d/modules.conf regexp: '^search'riga: "cerca aggiornamenti aggiuntivi ubuntu built-in"stato: presente Ciò che fa è garantire che il file che gestisce il percorso di ricerca del modulo del kernel /etc/modules-load.d/modules.conf contiene una riga che ha cerca aggiornamenti extraspecificato. Normalmente c'è almeno una riga che inizia con cerca, e quello che vogliamo fare è assicurarci le posizioni dei moduli extra vengono cercate all'inizio del processo. Vorremo installare tramite il sottosistema DKMS: - nome: dkms install zfs ansible.builtin.shell: | dkms install zfs _zfs_version }} args: chdir: "/opt/zfs/zfs _zfs_version A questo punto, dovresti essere in grado di controllare l'attuale versione ZFS attiva e dovrebbe mostrarti qualcosa del genere: root@machine01 ~ # versione zfs zfs-2.1.1-1 zfs-kmod-2.1.1-1 Ci sono alcune unità SystemD (come al solito Digital Ocean ha alcuni ottimi documenti) che vengono create ma devono essere abilitate per l'uso di ZFS: - nome: assicurarsi che le unità systemd relative a zfs siano abilitate blocco: - ansible.builtin.systemd: nome:itemstate: avviato abilitato: sì ciclo: - zfs-import-cache.service - zfs-import.target - zfs-mount.service - zfs-share.service - zfs-zed.service - zfs-volume-wait.service - zfs.target Le variabili su cui viene eseguito il looping sono simili all'esecuzione systemd start and systemd enable . The security-minded reader at home is no doubt cringing into the atmosphere by now, but making sure my kernel upgrades are manual is the only way I’ve found to ensure that the installed version of ZFS was not disabled/unexpectedly altered/broken by kernel upgrades: - name: Hold all kernel upgrades to prevent custom built ZFS from doing fallback ansible.builtin.shell: | apt-mark hold linux-headers-generic apt-mark hold linux-image-generic apt-mark hold {{ uname_r.stdout }} # you'll need that `uname -r` output again here I personally prefer to hold back any kernel upgrades and instead perform them at machine setup rather than during operation. DKMS *should* ensure that with the building of any new kernel the ZFS code is rebuilt but it’s been flaky in the past so I find it hard to trust. Along with all the kernel changes we’ve made so far (good and questionable), one thing we’ll want to do is add the configuration necessary to ensure the kernel module is loaded: - name: Ensure zfs kernel module comes up with next restart tags: [ "zfs:post-install:config" ] block: - name: Add zfs module load file ansible.builtin.template: src: templates/kernel-modules/zfs.conf.j2 dest: /etc/modules-load.d/zfs.conf owner: root group: root mode: 0644 Now that we have ZFS installed (restart once to check I’m going to leave the rest of the cluster setup to you. There are a *lot* of ways to use ZFS and setup zpools (RAID0/1/5/Z Actually using ZFS properly is out of scope (I can only hope I’ve covered *installing* it properly, at least), but please refer to the usual manuals there to set up your ZFS pool and storage requirements. Trying to cover even the basics of how to setup ZFS for your drives once it’s been installed is certainly a lot of reading so we’ll leave it there for today. This is the part where you “draw the rest of the owl” (sorry). txg_timeout While experimenting with some write modes for Postgres on ZFS, I looked into an optimization modes that involved reducing the txg_timeout from it’s default of 5 seconds to 1 second. While I won’t get into the tradeoffs implied by that move (please read my post on Postgres + ZFS), here is the setup that I’ve used for modifying txg_timeout per-machine (some machines might use the optimization some might not): - name: Add systemd unit to support txg timeout customization tags: [ "zfs:post-install:config" ] block: - name: Set current ZFS txg_timeout (to 1) ansible.builtin.shell: | echo 1 > /sys/module/zfs/parameters/zfs_txg_timeout - name: install zfs-config-txg-timeout service ansible.builtin.template: src: templates/zfs-config-txg-timeout.service.j2 dest: /etc/systemd/system/zfs-config-txg-timeout.service owner: root group: root mode: 0644 - name: start & enable zfs-config-txg-timeout service ansible.builtin.systemd: name: zfs-config-txg-timeout.service state: started enabled: yes daemon_reload: yes The template that goes with that looks like this: [Unit] Description=Set ZFS txg_timeout After=zfs.target ConditionPathIsDirectory=/sys/module/zfs [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/bin/bash -c 'echo {{ _zfs_txg_timeout_seconds | default(zfs_txg_timeout_seconds) }} > /sys/module/zfs/parameters/zfs_txg_timeout' # Not needed since we want it to always be whatever the setting is # ExecStop=/usr/bin/bash -c 'echo {{ _zfs_txg_timeout_seconds | default(zfs_txg_timeout_seconds) }} > /sys/module/zfs/parameters/zfs_txg_timeout' [Install] WantedBy=multi-user.target Obviously you’ll want to define {{ _zfs_txg_timeout_seconds }} and the zfs_txg_timeout_seconds. In general, this will make sure that the txg_timeout is set to what you want it to be upon startup after ZFS has started. Wasn’t that easy? If you’re answering no, it wasn’t easy for me to figure out either! I spent a lot of time wondering why DKMS wasn’t working properly (which is why the hack of preventing kernel upgrades is still included) and dealing with other issues. The OpenZFS documentation is pretty great but seems to be missing a guide somewhat like this, so hopefully this post will save people some time going forward when trying to experiment with new ZFS setups on Hetzner. Another thing I’m hoping for with this post is to be corrected – if you see something glaringly wrong in my setup, please reach out. The more people can use low cost infrastructure providers like Hetzner, the more cool software we get and the more interesting/innovative products can be built. To that end I’m working on NimbusWS (I’m behind on this but should launch by end of Q1 2022) – if you’re interested please sign up for the service and kick the tires (free tier usage will be available).