Duurzaam gehoste, beheerde F/OSS Objectopslag, Redis, Prometheus op Hetzner, OVH en LeaseWeb **tl;dr - Regel voor regel uitleg van mijn door ansible aangedreven ZFS-installatiescript voor gebruik op Dezner's speciale hardware (Ubuntu 20.04 - âÂÂFocalâÂÂ) â Het is niet perfect/minimaal, maar het werkt voor mij Een tijdje geleden begon ik ZFS te gebruiken op al mijn bare metal-specifieke hardware die bij Hetzner werd gehost om de aangesloten HDD's en SSD's te verwarren. Er is veel keuze in de ruimte (standaard LVM, mdraid btrfs, enz.), maar ik koos voor ZFS vanwege zijn functies en ergonomie. Ik zal niemand vervelen met het waarom, maar een van de dingen die ik nodig had om te navigeren was hoe nieuwere versies van ZFS te installeren op Ubuntu 20.04 (een van de ondersteunde besturingssystemen bij Hetzner). Ik kwam enkele problemen tegen (vooral na de installatie) tijdens het instellen van ZFS op mijn systemen, dus ik wilde een overzicht geven van hoe ik het deed. Dit bericht is een strofe-voor-stanza uitleg van mijn Ansible-scripts die ZFS installeren. Voordat je weet of ZFS (of een ander bestandssysteem) de moeite waard is om naar over te schakelen, wil je waarschijnlijk naar RTFM. ZFS heeft veel ins en ik ben er zeker geen expert in, maar het weten van het hoe en waarom, evenals de terminologie en zelfs de geschiedenis van het project is erg belangrijk. Een paar links om je op weg te helpen: Samen met ZFS (wat hier waarschijnlijk de meest onbekende hoeveelheid is) wil je waarschijnlijk bekend zijn met Ubuntu en algemeen systeembeheer. Dat is nogal een groot gebied om te bestrijken, maar hier zijn een paar links: Het spreekt bijna vanzelf, maar als je op dit moment niet erg bekend bent met Linux-systeembeheer, zou je dit waarschijnlijk niet moeten proberen. Ik kies er persoonlijk voor om mijn schijven in een ietwat aangepaste configuratie te hebben â Ik heb RAID1 (mirroring) setup via mdraid, samen met partities op elke schijf die ik aan ZFS kan geven om te beheren. Idealiter zou ik hele schijven hebben om aan ZFS te geven, maar partities werken ook. Besturingssysteem instellen ( installimage) dat schijfinstellingen bevat, wordt uitgevoerd vanuit de reddingsmodus van Hetzner en kan worden geleid met een bestand zoals het volgende: # Drive-declaraties gebruikt door installimage DRIVE0 /dev/nvme0n1 DRIVE1 /dev/nvme1n1 # Schakel Software RAID in (voor de OS-schijf) SWRAID 1 SWRAIDLEVEL 1 # Bootloader (meestal grub) BOOTLOADER grub # Machine hostame HOSTNAME machine01 # Partition configuratie PART swap swap 32G PART /boot ext4 1G PART / ext4 128G # Deze laatste partitie wordt gemaakt (geveegd& later opnieuw gemaakt als ZFS) PART /root-disk-remaining ext4 all # U kunt afbeeldingen specificeren die Hetzner gebruikt door toegang te krijgen tot hun netwerkshare IMAGE /root/.oldroot/nfs/images/Ubuntu-2004-focal-64-minimal.tar. gz Dit is duidelijk nogal Hetzner-specifiek, maar doe wat je moet doen op je eigen systemen om partities/schijven beschikbaar te hebben die ZFS kan gebruiken. zfsutils-linuxand zfs-zed In Ansible YAML ziet de stap er als volgt uit: - naam: Bewaar alle zfs-gerelateerde upstream-pakketten ansible.builtin.shell: | apt-mark hold zfsutils-linux apt-mark hold zfs-zed Op het moment van schrijven van dit bericht is de versie van zfs-linux in Ubuntu Focal is 0.8.3. Aangezien ons doel hier is om een ​​nieuwere versie te installeren en te blijven gebruiken, willen we ervoor zorgen dat elke apt-updates vervangen onze geïnstalleerde versie niet door een oudere versie. Terwijl we hier zijn, laten we ook de pakketten opschonen. - naam: ZFS upstream (ubuntu) pakketten opschonen indien geïnstalleerd ignore_errors: ja ansible.builtin.command: | apt purge --allow-change-held-packages zfsutils-linux zfs-zed U kunt de documenten lezen op geschikt om te zien wat purge is vergelijkbaar met verwijderen, maar verwijdert ook configuratiebestanden, indien aanwezig. U kunt de afhankelijkheden voor OpenZFS als volgt installeren: - name: Installatievereisten voor het bouwen van 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 # De regel hieronder vraagt ​​om de uitvoer van `uname -r`, bijvoorbeeld "5.16.5-arch1- 1"voor mijn arch-systeem # zodat de regel zou worden omgezet in zoiets als "linux-headers-5.16.5-arch1-1"(natuurlijk niet geldig op Ubuntu, maar als voorbeeld) - linux-headers uname_r.stdout }} - python3 - python3-dev - python3-setuptools - python3-cffi - libffi-dev - python3-packaging - git - libcurl4-openssl-dev Er kunnen een paar afhankelijkheden zijn die niet strikt noodzakelijk zijn, maar ze zouden bijna allemaal vereist moeten zijn. /opt/zfs Hier is ZFS: - naam: Creëer /opt/zfs ansible.builtin.file: pad: /opt/zfs state: directory Als u ZFS wilt downloaden: - naam: Download 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"Hier de vervanging {{ _zfs_versie }} ( 2.1.1. U wilt ook zelf downloaden en een controlesom verzamelen/genereren om te gebruiken. Download nooit dingen van internet die niet zouden moeten veranderen zonder een checksum! {{is de Ansible-templating-syntaxis) is En als je het wilt kopiëren vanaf de computer waarop Ansible draait (dit is wat ik doe): - naam: kopieer zfs-pakket (vermijd snelheidslimiet) ansible.builtin.copy: src: files/zfs/zfs _zfs_version tar.gz"mode: 0755 dest: "/opt/zfs/zfs _zfs_version tar.gz"Ongeacht hoe je ervoor kiest om de broncode te krijgen, je moet het natuurlijk uitpakken: - naam: Unzip zfs code ansible.builtin.unarchive: src: "/opt/zfs/zfs _zfs_version tar.gz"dest: "/opt/zfs"remote_src: ja Om het bouwproces te starten: - naam: Setup en Build ZFS ansible.builtin.shell: | ./autogen../configure make clean make -j args: chdir: "/opt/zfs/zfs _zfs_version Als je bekend bent met het bouwen van dingen vanaf de bron, gebruiken verschillende projecten deze gemeenschappelijke toolset (een variant van scripts maken, autogeneren en configureren). Zoals je zou verwachten, kan dit even duren, dus geef het wat tijd. Na het bouwen van ZFS - naam: Installeer ZFS ansible.builtin.shell: | make install args: chdir: "/opt/zfs/zfs _zfs_version Normaal gesproken zou je denken dat we klaar zijn *hier*, maar dit bericht bestaat omdat dit over het algemeen niet genoeg is! Laten we doorgaan. Forceer eerst het ontladen van de ZFS-module(s) als ze actief zijn: - naam: geforceerd ontladen van ZFS-module(s) ansible.builtin.shell: | ./scripts/zfs.-u argumenten: chdir: "/opt/zfs/zfs _zfs_version Het zou ideaal zijn om *geen* werklast te hebben wanneer dit gebeurt, zoals je zou verwachten. Terwijl de modules worden uitgeladen, kunnen we enkele helpers installeren: - naam: Post-Install ZFS Helpers ansible.builtin.shell: | ./scripts/zfs-helpers.-i args: chdir: "/opt/zfs/zfs _zfs_version Nadat de helpers zijn geïnstalleerd, gaan we de ZFS-module geforceerd opnieuw laden: - naam: geforceerd herladen van ZFS-module ansible.builtin.shell: | ./scripts/zfs.args: chdir: "/opt/zfs/zfs _zfs_version Ik heb gevonden dat het bouwen en gebruiken van de deb-module (het formaat dat door Debian wordt gebruikt voor pakketinstallatie) hielp ook om de installatie vast te houden en niet te vervangen door Ubuntu-pakketstandaarden. Bouw eerst het ZFS deb-pakket vanuit de broncode: - naam: Build ZFS deb-pakket ansible.builtin.shell: | maak deb args: chdir: "/opt/zfs/zfs _zfs_version En installeer het dan - naam: Installeer ZFS deb-pakketten ansible.builtin.shell: | ja | dpkg -i --force-overwrite deb apt install -f -y deb args: chdir: "/opt/zfs/zfs _zfs_version Theoretisch zou deze stap * niet * nodig moeten zijn (of zou alleen moeten worden gebruikt), aangezien we al een installatieproces hebben uitgevoerd, maar ik heb ontdekt dat ik bij het doen van het ene of het andere Âzou situaties hebben waarin opnieuw opstarten ertoe zou leiden dat een oudere versie van ZFS moet worden gebruikt (ondanks de apt purge) â vooral op kernelniveau. modprobe Als u de ZFS-module die onmiddellijk is geïnstalleerd wilt inschakelen, gebruikt u modsonde: - naam: Modprobe zfs-moduleblok: - naam: Installeer zfs-kernelmodule community.general.modprobe: naam: zfs-status: aanwezig Het installeren van ZFS betekent het installeren van een kernelmodule, maar aangezien we het nog niet helemaal ingebakken hebben via Dynamic Kernel Module Support, moeten we het gebruik van lokaal geïnstalleerde kernelmodules inschakelen: - naam: Zorg ervoor dat extra vooraan staat ansible.builtin.lineinfile: path: /etc/modules-load.d/modules.conf regexp: '^search'line: "search extra updates ubuntu built-in"state: present Wat dit doet, is ervoor zorgen dat het bestand dat het zoekpad van de kernelmodule beheert /etc/modules-load.d/modules.conf bevat een regel met zoek extra updates gespecificeerd. Normaal gesproken is er minstens één regel die begint met zoeken, en wat we willen doen is ervoor zorgen extra modulelocaties worden vroeg in het proces gezocht. We willen installeren via het DKMS-subsysteem: - naam: dkms install zfs ansible.builtin.shell: | dkms install zfs _zfs_version }} args: chdir: "/opt/zfs/zfs _zfs_version Op dit punt zou je de huidige actieve ZFS-versie moeten kunnen controleren, en het zou je zoiets als dit moeten laten zien: root@machine01 ~ # zfs-versie zfs-2.1.1-1 zfs-kmod-2.1.1-1 Er zijn een paar SystemD-eenheden (zoals gewoonlijk heeft Digital Ocean een aantal geweldige documenten) die zijn gemaakt, maar moeten worden ingeschakeld voor gebruik door ZFS: - naam: Zorg ervoor dat zfs-gerelateerde systemd-eenheden zijn ingeschakeld blok: - ansible.builtin.systemd: naam:itemstate: gestart ingeschakeld: ja lus: - zfs-import-cache.service - zfs-import.target - zfs-mount.service - zfs-share.service - zfs-zed.service - zfs-volume-wait.service - zfs.target De variabelen die worden doorgelust, lijken op hardlopen 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).