Nachhaltig gehostetes, verwaltetes F/OSS Objektspeicher, Redis, Prometheus auf Hetzner, OVH und LeaseWeb **tl;dr - Zeile für Zeile Erklärung meines Ansible-betriebenen ZFS-Installationsskripts zur Verwendung auf der dedizierten Hardware von Hetzner (Ubuntu 20.04 - „Focal“). „Es ist nicht perfekt/minimal, aber es funktioniert für mich Vor einiger Zeit habe ich damit begonnen, ZFS auf all meiner Bare-Metal-Hardware zu verwenden, die bei Hetzner gehostet wird, um die angeschlossenen HDDs und SSDs zu reparieren. Es gibt viele Möglichkeiten im Raum (Standard-LVM, mdraid Btrfs usw.), aber ich habe ZFS wegen seiner Funktionen und seiner Ergonomie gewählt. Ich möchte niemanden mit dem Warum langweilen, aber eines der Dinge, die ich navigieren musste, war, wie man neuere Versionen von ZFS auf Ubuntu 20.04 (einem der unterstützten Betriebssysteme bei Hetzner) installiert. Beim Einrichten von ZFS auf meinen Systemen bin ich auf einige Probleme (insbesondere nach der Installation) gestoßen, daher wollte ich kurz erläutern, wie ich vorgegangen bin. Dieser Beitrag ist eine zeilenweise Erklärung meiner Ansible-Skripte, die ZFS installieren. Bevor Sie wissen, ob es sich lohnt, zu ZFS (oder einem beliebigen Dateisystem) zu wechseln, werden Sie wahrscheinlich zu RTFM wechseln wollen. ZFS hat viele Ins und Ich bin sicherlich kein Experte darin, aber es ist sehr wichtig, das Wie und Warum sowie die Terminologie und sogar die Geschichte des Projekts zu kennen. Ein paar Links zum Einstieg: Zusammen mit ZFS (das hier wahrscheinlich die unbekannteste Größe ist) möchten Sie wahrscheinlich mit Ubuntu und der allgemeinen Systemverwaltung vertraut sein. Das ist ein ziemlich großer Bereich, den es abzudecken gilt, aber hier sind ein paar Links: Es versteht sich fast von selbst, aber wenn Sie mit der Linux-Systemadministration zu diesem Zeitpunkt nicht sehr vertraut sind, sollten Sie dies wahrscheinlich nicht versuchen. Ich persönlich entscheide mich dafür, meine Festplatten in einer etwas benutzerdefinierten Konfiguration zu haben – ich habe RAID1 (Spiegelung) eingerichtet mdraid, zusammen mit Partitionen auf jeder Festplatte, die ich ZFS zur Verwaltung geben kann. Idealerweise hätte ich ganze Festplatten, die ich ZFS übergeben könnte, aber Partitionen funktionieren auch. Betriebssystem-Setup ( installimage), das das Festplatten-Setup enthält, wird im Rettungsmodus von Hetzner ausgeführt und kann mit einer Datei wie der folgenden gesteuert werden: # Vom Installationsimage verwendete Laufwerksdeklarationen DRIVE0 /dev/nvme0n1 DRIVE1 /dev/nvme1n1 # Software-RAID aktivieren (für die Betriebssystemfestplatte) SWRAID 1 SWRAIDLEVEL 1 # Bootloader (im Allgemeinen grub) BOOTLOADER grub # Hostname der Maschine HOSTNAME machine01 # Partition Konfiguration PART swap swap 32G PART /boot ext4 1G PART / ext4 128G # Diese letzte Partition wird erstellt (wiped& später als ZFS neu erstellt) PART /root-disk-remaining ext4 all # Sie können Images angeben, die Hetzner verwendet, indem Sie auf ihre Netzwerkfreigabe zugreifen IMAGE /root/.oldroot/nfs/images/Ubuntu-2004-focal-64-minimal.tar. gz Dies ist offensichtlich ziemlich Hetzner-spezifisch, aber tun Sie alles, was Sie auf Ihren eigenen Systemen tun müssen, um Partitionen/Laufwerke für ZFS zur Verfügung zu haben. zfsutils-linuxand zfs-zed In Ansible YAML sieht der Schritt so aus: - name: Enthält alle zfs-bezogenen Upstream-Pakete ansible.builtin.shell: | apt-mark hold zfsutils-linux apt-mark hold zfs-zed Zum Zeitpunkt des Schreibens dieses Beitrags ist die Version von zfs-linux in Ubuntu Focal ist 0.8.3. Da unser Ziel hier darin besteht, eine neuere Version zu installieren und weiterhin zu verwenden, möchten wir sicherstellen, dass alle apt-Updates ersetzen unsere installierte Version nicht durch eine ältere Version. Während wir hier sind, lasst uns auch die Pakete löschen. - name: ZFS-Upstream-Pakete (Ubuntu) löschen, falls installiert.ignore_errors: ja ansible.builtin.command: | apt purge --allow-change-held-packages zfsutils-linux zfs-zed Sie können die Dokumente weiter lesen geeignet zu sehen, was purge funktioniert ähnlich wie remove, entfernt aber auch Konfigurationsdateien, falls vorhanden. Sie können die Abhängigkeiten für OpenZFS wie folgt installieren: - name: Installationsanforderungen zum Erstellen von ZFS ansible.builtin.apt: name:packagesupdate_cache: ja state: vorhanden 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 # Die folgende Zeile fordert die Ausgabe von `uname -r`, zum Beispiel "5.16.5-arch1- 1"für mein Arch-System #, also würde die Zeile zu etwas wie "linux-headers-5.16.5-arch1-1"auflösen (natürlich nicht gültig auf Ubuntu, aber als Beispiel) - linux-headers uname_r.stdout }} - python3 - python3-dev - python3-setuptools - python3-cffi - libffi-dev - python3-packaging - git - libcurl4-openssl-dev Es kann ein paar Abhängigkeiten geben, die nicht unbedingt erforderlich sind, aber fast alle sollten erforderlich sein. /opt/zfs Hier ist ZFS: - name: /opt/zfs ansible.builtin.file erstellen: Pfad: /opt/zfs state: Verzeichnis Wenn Sie ZFS herunterladen möchten: - Name: Download zfs ansible.builtin.get_url: URL: "httpsgithub.com/openzfs/zfs/releases/download/zfs _zfs_version zfs _zfs_version tar.gz"Prüfsumme:_zfs_tarball_sha256_checksummode: 0755 Ziel: "/opt/zfs/zfs _zfs_version tar .gz"Hier die Substitution {{ _zfs_version }} ( 2.1.1. Sie sollten den Download auch selbst durchführen und eine zu verwendende Prüfsumme sammeln/generieren. Laden Sie niemals Dinge aus dem Internet herunter, die sich ohne Prüfsumme nicht ändern sollen! {{ist die Ansible-Template-Syntax) ist Und wenn Sie es von dem Computer kopieren möchten, auf dem Ansible läuft (das mache ich): - Name: zfs-Paket kopieren (Ratenbegrenzung vermeiden) ansible.builtin.copy: src: files/zfs/zfs _zfs_version tar.gz"Modus: 0755 dest: "/opt/zfs/zfs _zfs_version tar.gz"Unabhängig davon, wie Sie die Quelle erhalten, müssen Sie sie natürlich entpacken: - name: ZFS-Code entpacken ansible.builtin.unarchive: src: "/opt/zfs/zfs _zfs_version tar.gz"dest: "/opt/zfs"remote_src: ja So starten Sie den Build-Prozess: - Name: ZFS einrichten und erstellen ansible.builtin.shell: | ./autogen../configure make clean make -j args: chdir: "/opt/zfs/zfs _zfs_version Wenn Sie mit dem Erstellen von Dingen aus dem Quellcode vertraut sind, verwenden verschiedene Projekte dieses gemeinsame Toolset (einige Varianten von Erstellen, Autogen und Konfigurieren von Skripten). Wie Sie vielleicht erwarten, kann dies eine Weile dauern, also geben Sie ihm etwas Zeit. Nach dem Aufbau von ZFS - name: Installieren Sie ZFS ansible.builtin.shell: | make install args: chdir: "/opt/zfs/zfs _zfs_version Normalerweise würde man meinen, wir wären *genau hier* fertig, aber dieser Beitrag existiert, weil es im Allgemeinen nicht ausreicht, dies zu tun! Lasst uns weitermachen. Erzwingen Sie zuerst das Entladen der ZFS-Module, falls sie ausgeführt werden: - name: Entladen von ZFS-Modul(en) erzwingen ansible.builtin.shell: | ./scripts/zfs.-u args: chdir: "/opt/zfs/zfs _zfs_version Es wäre ideal, wenn dies der Fall ist, *keine* Arbeitslasten auszuführen, wie Sie vielleicht erwarten. Während die Module entladen werden, können wir einige Helfer installieren: - Name: ZFS-Hilfsprogramme nach der Installation ansible.builtin.shell: | ./scripts/zfs-helpers.-i args: chdir: "/opt/zfs/zfs _zfs_version Lassen Sie uns nach der Installation der Hilfsprogramme das Neuladen des ZFS-Moduls erzwingen: - name: Neuladen des ZFS-Moduls erzwingen ansible.builtin.shell: | ./scripts/zfs.args: chdir: „/opt/zfs/zfs _zfs_version Ich habe dieses Gebäude gefunden und benutze das Das deb-Modul (das von Debian für die Paketinstallation verwendete Format) half auch dabei, die Installation festzuhalten und nicht durch Ubuntu-Paketstandards zu ersetzen. Erstellen Sie zuerst das ZFS-Deb-Paket aus dem Quellcode: - Name: ZFS-Deb-Paket erstellen ansible.builtin.shell: | make deb args: chdir: "/opt/zfs/zfs _zfs_version Und dann installieren - name: Installieren Sie die ZFS-Deb-Pakete ansible.builtin.shell: | ja | dpkg -i --force-overwrite deb apt install -f -y deb args: chdir: "/opt/zfs/zfs _zfs_version Theoretisch *sollte* dieser Schritt nicht notwendig sein (oder allein verwendet werden), da wir bereits einen Installationsprozess ausgeführt haben, aber ich habe festgestellt, dass ich das bei dem einen oder anderen getan habe Es gab Situationen, in denen Neustarts dazu führten, dass eine ältere Version von ZFS verwendet wurde (trotz der apt purge) â besonders auf der Kernel-Ebene. modprobe Wenn Sie das installierte ZFS-Modul sofort aktivieren möchten, verwenden Sie Modprobe: - Name: Modprobe zfs-Modulblock: - Name: ZFS-Kernelmodul installieren community.general.modprobe: Name: zfs-Status: vorhanden Die Installation von ZFS bedeutet die Installation eines Kernel-Moduls, aber da wir es noch nicht ganz über Dynamic Kernel Module Support eingebaut haben, müssen wir die Verwendung lokal installierter Kernel-Module aktivieren: - Name: Stellen Sie sicher, dass Extra im Vordergrund steht ansible.builtin.lineinfile: path: /etc/modules-load.d/modules.conf regexp: '^search'line: "search extra updates ubuntu built-in"state: present Dadurch wird sichergestellt, dass die Datei, die den Suchpfad des Kernelmoduls verwaltet /etc/modules-load.d/modules.conf hat eine Zeile darin, die hat Suche nach zusätzlichen Updates angegeben. Normalerweise gibt es mindestens eine Zeile, die mit beginnt suchen, und was wir tun wollen, ist sicherzustellen Zusätzliche Modulstandorte werden früh im Prozess gesucht. Wir möchten über das DKMS-Subsystem installieren: - name: dkms install zfs ansible.builtin.shell: | dkms install zfs _zfs_version }} args: chdir: "/opt/zfs/zfs _zfs_version An diesem Punkt sollten Sie in der Lage sein, die aktuell aktive ZFS-Version zu überprüfen, und sie sollte Ihnen etwa so zeigen: root@machine01 ~ # zfs-Version zfs-2.1.1-1 zfs-kmod-2.1.1-1 Es gibt ein paar SystemD-Einheiten (wie üblich hat Digital Ocean einige großartige Dokumente), die erstellt werden, aber für die Verwendung durch ZFS aktiviert werden müssen: - name: Stellen Sie sicher, dass zfs-bezogene systemd-Einheiten aktiviert sind block: - ansible.builtin.systemd: name:itemstate: started enabled: yes loop: - zfs-import-cache.service - zfs-import.target - zfs-mount.service - zfs-share.service - zfs-zed.service - zfs-volume-wait.service - zfs.target Die Variablen, die durchlaufen werden, ähneln dem Laufen 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).