Zrównoważony hosting, zarządzany F/OSS Obiektowa pamięć masowa, Redis, Prometheus w Hetzner, OVH i LeaseWeb **tl;dr - Wyjaśnienie linia po linii mojego skryptu instalacyjnego ZFS opartego na ansible do użytku na dedykowanym sprzęcie firmy Hetzner (Ubuntu 20.04 - âÂÂFocalâÂÂ) â to nie jest idealne/minimalne, ale u mnie działa Jakiś czas temu zacząłem używać ZFS na całym moim dedykowanym sprzęcie hostowanym w firmie Hetzner, aby walczyć z podłączonymi dyskami twardymi i dyskami SSD. Istnieje wiele możliwości wyboru w przestrzeni (standardowe LVM, mdraid btrfs itp.), ale wybrałem ZFS ze względu na jego funkcjonalność i ergonomię. Nie będę nikogo zanudzać wyjaśnieniem, dlaczego, ale jedną z rzeczy, których potrzebowałem, było zainstalowanie nowszych wersji ZFS na Ubuntu 20.04 (jeden z obsługiwanych systemów operacyjnych w firmie Hetzner). Napotkałem pewne problemy (szczególnie po instalacji) podczas konfigurowania ZFS w moich systemach, więc chciałem przedstawić przewodnik, jak to zrobiłem. Ten post jest szczegółowym wyjaśnieniem moich skryptów Ansible, które instalują ZFS. Zanim dowiesz się, czy warto przełączyć się na ZFS (lub jakikolwiek inny system plików), prawdopodobnie będziesz chciał skorzystać z RTFM. ZFS ma wiele tajników i na pewno nie jestem w tym ekspertem, ale znajomość jak i dlaczego, a także terminologii, a nawet historii projektu jest bardzo ważna. Kilka linków na początek: Wraz z ZFS (który jest tutaj prawdopodobnie najbardziej nieznaną ilością) prawdopodobnie chcesz znać Ubuntu i ogólną administrację systemami. To spory obszar do omówienia, ale oto kilka linków: To prawie oczywiste, ale jeśli w tym momencie nie jesteś zbyt zaznajomiony z administracją systemem Linux, prawdopodobnie nie powinieneś tego podejmować. Osobiście wybieram, aby moje dyski były w nieco niestandardowej konfiguracji — mam konfigurację RAID1 (dublowanie) przez mdraid wraz z partycjami na każdym dysku, które mogę przekazać ZFS do zarządzania. Idealnie byłoby, gdybym miał całe dyski do oddania do ZFS, ale partycje też działają. konfiguracja systemu operacyjnego ( installimage), który obejmuje konfigurację dysku, jest uruchamiany z trybu ratunkowego firmy Hetzner i może być prowadzony za pomocą pliku podobnego do następującego: # Deklaracje dysków używane przez obraz instalacyjny DRIVE0 /dev/nvme0n1 DRIVE1 /dev/nvme1n1 # Włącz programowy RAID (dla dysku systemu operacyjnego) SWRAID 1 SWRAIDLEVEL 1 # Bootloader (ogólnie grub) BOOTLOADER grub # Nazwa hosta maszyny NAZWA_HOSTA machine01 # Partycja konfiguracja PART swap swap 32G PART /boot ext4 1G PART / ext4 128G # Ta ostatnia partycja zostanie wykonana (wyczyszczona& odtworzony później jako ZFS) CZĘŚĆ /root-disk-remaining ext4 all # Możesz określić obrazy używane przez firmę Hetzner, uzyskując dostęp do ich udziału sieciowego IMAGE /root/.oldroot/nfs/images/Ubuntu-2004-focal-64-minimal.tar. gz Jest to oczywiście dość specyficzne dla Hetznera, ale zrób wszystko, co musisz zrobić na swoich własnych systemach, aby mieć dostępne partycje/dyski do wykorzystania przez ZFS. zfsutils-linuxand zfs-zed W Ansible YAML krok wygląda następująco: - name: Przechowuj wszystkie pakiety nadrzędne związane z ZFS ansible.builtin.shell: | apt-mark hold zfsutils-linux apt-mark hold zfs-zed W chwili pisania tego postu wersja zfs-linux w Ubuntu Focal to 0.8.3. Ponieważ naszym celem jest zainstalowanie i dalsze korzystanie z nowszej wersji, chcemy mieć pewność, że dowolna apt aktualizacje nie zastępują naszej zainstalowanej wersji starszą wersją. Skoro już tu jesteśmy, wyczyśćmy również pakiety. - nazwa: Wyczyść pakiety nadrzędne ZFS (ubuntu), jeśli są zainstalowane ignore_errors: yes ansible.builtin.command: | apt purge --allow-change-holded-packages zfsutils-linux zfs-zed Możesz przeczytać dokumenty na warto zobaczyć co purge działa podobnie do usuwania, ale usuwa również pliki konfiguracyjne, jeśli są obecne. Możesz zainstalować zależności dla OpenZFS w następujący sposób: - name: Wymagania instalacyjne do budowania 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 # Poniższa linia wywołuje wyjście `uname -r`, na przykład "5.16.5-arch1- 1” dla mojego systemu arch #, więc linia rozwiązałaby się na coś w rodzaju „linux-headers-5.16.5-arch1-1” (oczywiście nie działa na Ubuntu, ale jako przykład) - linux-headers uname_r.stdout }} - python3 - python3-dev - python3-setuptools - python3-cffi - libffi-dev - python3-packaging - git - libcurl4-openssl-dev Może istnieć kilka zależności, które nie są bezwzględnie konieczne, ale prawie wszystkie powinny być wymagane. /opt/zfs Oto ZFS: - nazwa: Utwórz /opt/zfs ansible.builtin.file: ścieżka: /opt/zfs stan: katalog Jeśli chcesz pobrać ZFS: - nazwa: Pobierz zfs ansible.builtin.get_url: url: "httpsgithub.com/openzfs/zfs/releases/download/zfs _zfs_version zfs _zfs_version tar.gz"suma kontrolna:_zfs_tarball_sha256_checksummode: 0755 dest: "/opt/zfs/zfs _zfs_version tar .gz"Tutaj zamiana {{ _zfs_version }} ( 2.1.1. Będziesz także chciał samodzielnie pobrać i zebrać/wygenerować sumę kontrolną do użycia. Nigdy nie pobieraj z Internetu rzeczy, których nie można zmienić bez sprawdzenia! {{jest składnią szablonów Ansible) jest A jeśli chcesz skopiować go z komputera, na którym działa Ansible (to właśnie robię): - name: Kopiuj pakiet zfs (unikaj limitu szybkości) ansible.builtin.copy: src: files/zfs/zfs _zfs_version tar.gz"mode: 0755 dest: "/opt/zfs/zfs _zfs_version tar.gz"Niezależnie od tego, jak zdecydujesz się uzyskać źródło, musisz je oczywiście rozpakować: - name: Rozpakuj kod zfs ansible.builtin.unarchive: src: "/opt/zfs/zfs _zfs_version tar.gz"dest: "/opt/zfs"remote_src: yes Aby rozpocząć proces kompilacji: - nazwa: Skonfiguruj i zbuduj ZFS ansible.builtin.shell: | ./autogen../configure make clean make -j args: chdir: "/opt/zfs/zfs _zfs_version Jeśli jesteś zaznajomiony z budowaniem rzeczy ze źródeł, różne projekty korzystają z tego wspólnego zestawu narzędzi (niektóre warianty tworzenie, automatyczne generowanie i konfigurowanie skryptów). Jak można się spodziewać, może to zająć trochę czasu, więc daj mu trochę czasu. Po zbudowaniu ZFS - nazwa: Zainstaluj ZFS ansible.builtin.shell: | make install argumenty: chdir: "/opt/zfs/zfs _zfs_version Normalnie można by pomyśleć, że skończymy *tutaj*, ale ten post istnieje, ponieważ robienie tego zwykle nie wystarcza! Idźmy naprzód. Najpierw wymuś rozładowanie modułów ZFS, jeśli są uruchomione: - nazwa: Wymuś wyładowanie modułu(ss) ZFS ansible.builtin.shell: | ./scripts/zfs.-u args: chdir: "/opt/zfs/zfs _zfs_version Idealnie byłoby *nie* uruchamiać żadnych obciążeń, gdy tak się dzieje, jak można się spodziewać. Podczas gdy moduły są rozładowywane, możemy zainstalować kilku pomocników: - nazwa: Pomocnicy ZFS po instalacji ansible.builtin.shell: | ./scripts/zfs-helpers.-i args: chdir: "/opt/zfs/zfs _zfs_version Po zainstalowaniu pomocników wymuśmy przeładowanie modułu ZFS: - nazwa: Wymuś przeładowanie modułu ZFS ansible.builtin.shell: | ./scripts/zfs.args: chdir: "/opt/zfs/zfs _zfs_version Znalazłem ten budynek i korzystam z moduł deb (format używany przez Debiana do instalacji pakietów) pomógł również w utrzymaniu instalacji i nie został zastąpiony przez domyślne pakiety Ubuntu. Najpierw zbuduj pakiet deb ZFS z kodu źródłowego: - nazwa: Zbuduj pakiet deb ZFS ansible.builtin.shell: | make deb argumenty: chdir: "/opt/zfs/zfs _zfs_version A następnie zainstaluj go - nazwa: Zainstaluj pakiety deb ZFS ansible.builtin.shell: | tak | dpkg -i --force-overwrite deb apt install -f -y deb argumenty: chdir: "/opt/zfs/zfs _zfs_version Teoretycznie ten krok *nie powinien* być konieczny (lub powinien być wykonywany samodzielnie), ponieważ już uruchomiliśmy proces instalacji, ale odkryłem, że robiąc jedno lub drugie Âbyłyby sytuacje, w których ponowne uruchomienie spowodowałoby monit o użycie starszej wersji ZFS (pomimo apt purge) — szczególnie na poziomie jądra. sonda modów Jeśli chcesz włączyć natychmiast zainstalowany moduł ZFS, użyj próbnik modów: - nazwa: Blok modułu Modprobe zfs: - nazwa: Zainstaluj moduł jądra zfs community.general.modprobe: nazwa: stan zfs: obecny Instalowanie ZFS oznacza instalowanie modułu jądra, ale ponieważ nie do końca upiekliśmy go za pomocą obsługi dynamicznych modułów jądra, musimy umożliwić korzystanie z lokalnie zainstalowanych modułów jądra: - name: Upewnij się, że extra znajduje się z przodu ansible.builtin.lineinfile: path: /etc/modules-load.d/modules.conf wyrażenie regularne: '^search'line: "search extra aktualizacje ubuntu wbudowane"stan: obecny Zapewnia to, że plik zarządzający ścieżką wyszukiwania modułów jądra /etc/modules-load.d/modules.conf zawiera linię, która ma wyszukaj określone dodatkowe aktualizacje. Zwykle jest co najmniej jedna linia, która zaczyna się od szukać, a my chcemy się upewnić dodatkowe lokalizacje modułów są wyszukiwane na wczesnym etapie procesu. Będziemy chcieli zainstalować przez podsystem DKMS: - nazwa: dkms zainstaluj zfs ansible.builtin.shell: | dkms zainstaluj zfs _zfs_version }} args: chdir: "/opt/zfs/zfs _zfs_version W tym momencie powinieneś być w stanie sprawdzić aktualną aktywną wersję ZFS, która powinna pokazać coś takiego: root@machine01 ~ # wersja zfs zfs-2.1.1-1 zfs-kmod-2.1.1-1 Istnieje kilka jednostek SystemD (jak zwykle Digital Ocean ma kilka świetnych dokumentów), które są tworzone, ale muszą być włączone, aby ZFS mógł korzystać: - name: Upewnij się, że jednostki systemowe związane z ZFS są włączone blok: - ansible.builtin.systemd: name:itemstate: uruchomione włączone: tak pętla: - zfs-import-cache.service - zfs-import.target - zfs-mount.service - zfs-share.service - zfs-zed.service - zfs-volume-wait.service - zfs.target Zapętlane zmienne są podobne do biegania 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).