Надійно розміщений, керований F/OSS Об'єктне зберігання, Redis, Prometheus на Hetzner, OVH і LeaseWeb **tl;dr – Порядкове пояснення мого сценарію встановлення ZFS на основі ansible для використання на виділеному апаратному забезпеченні Hetzner (Ubuntu 20.04 - âÂÂFocalâÂÂ) â  це не ідеально/мінімально, але це працює для мене Деякий час тому я почав використовувати ZFS на всьому моєму «голому металевому» спеціальному обладнанні, розміщеному в Hetzner, щоб сперечатися з приєднаними жорсткими дисками та SSD. У просторі є багато варіантів (стандартний LVM, mdraid btrfs тощо), але я вибрав ZFS через набір функцій та ергономічність. Я не буду нудити нікого пояснювати чому, але одна з речей, у якій мені потрібно було зорієнтуватися, це те, як інсталювати новіші версії ZFS на Ubuntu 20.04 (одна з операційних систем, які підтримує Hetzner). Під час налаштування ZFS у моїх системах я зіткнувся з деякими проблемами (зокрема після інсталяції), тому хотів би розповісти, як я це зробив. Ця публікація є поясненням моїх сценаріїв Ansible, які встановлюють ZFS. Перш ніж ви дізнаєтесь, чи варто переходити на ZFS (або будь-яку іншу файлову систему), ви, мабуть, захочете використовувати RTFM. ZFS має багато тонкощів, і я, звичайно, не експерт у цьому, але знати, як і чому, а також термінологію та навіть історію проекту дуже важливо. Кілька посилань для початку: Разом із ZFS (яка, мабуть, найбільш невідома величина тут), ви, ймовірно, захочете ознайомитися з Ubuntu та загальним системним адмініструванням. Це не велика область, але ось кілька посилань: Це майже само собою зрозуміло, але якщо ви на даний момент не дуже знайомі з адмініструванням системи Linux, вам, мабуть, не варто намагатися цього робити. Особисто я обираю диски в дещо нестандартній конфігурації âÂÂ Я налаштував RAID1 (дзеркалювання) через mdraid разом із розділами на кожному диску, які я можу передати ZFS для керування. В ідеалі я мав би цілі диски для ZFS, але розділи також працюють. Налаштування ОС ( installimage), який включає налаштування диска, запускається з режиму відновлення Hetzner's і може керуватися файлом, подібним до такого: # Оголошення диска, які використовує образ встановлення DRIVE0 /dev/nvme0n1 DRIVE1 /dev/nvme1n1 # Увімкнути програмний RAID (для диска ОС) SWRAID 1 SWRAIDLEVEL 1 # Завантажувач (зазвичай grub) BOOTLOADER grub # Машина hostame HOSTNAME machine01 # Розділ конфігурація PART swap swap 32G PART /boot ext4 1G PART / ext4 128G # Буде створено останній розділ (стерто)& пізніше відтворено як ZFS) ЧАСТИНА /root-disk-remaining ext4 all # Ви можете вказати зображення, які Hetzner використовує, отримавши доступ до їх спільного мережевого ресурсу IMAGE /root/.oldroot/nfs/images/Ubuntu-2004-focal-64-minimal.tar. gz Це, очевидно, досить специфічно для Hetzner, але зробіть усе, що вам потрібно, у ваших власних системах, щоб мати доступні розділи/диски для використання ZFS. zfsutils-linuxand zfs-zed У Ansible YAML крок виглядає так: - ім'я: Зберігає всі вихідні пакети, пов'язані з zfs, ansible.builtin.shell: | apt-mark hold zfsutils-linux apt-mark hold zfs-zed На момент написання цього посту версія zfs-linux в Ubuntu Focal — 0.8.3. Оскільки наша мета полягає в тому, щоб встановити та продовжувати використовувати новішу версію, ми хочемо переконатися, що будь-яка оновлення apt не замінюють нашу встановлену версію старішою версією. Поки ми тут, давайте також очистимо пакунки. - ім'я: Очистити вихідні пакети ZFS (ubuntu), якщо встановлено ignore_errors: так ansible.builtin.command: | apt purge --allow-change-held-packages zfsutils-linux zfs-zed Ви можете прочитати документи далі влучний побачити що purge робить – це схоже на видалення, але також видаляє файли конфігурації, якщо вони є. Ви можете встановити залежності для OpenZFS так: - name: Вимоги до встановлення для збірки 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 # Рядок нижче викликає запит `uname -r`, наприклад "5.16.5-arch1- 1"для моєї arch-системи #, тому рядок буде виведено на щось на кшталт "linux-headers-5.16.5-arch1-1"(звичайно, не діє в Ubuntu, але як приклад) - linux-headers uname_r.stdout }} - python3 - python3-dev - python3-setuptools - python3-cffi - libffi-dev - python3-packaging - git - libcurl4-openssl-dev Може бути кілька залежностей, які не є абсолютно необхідними, але майже всі вони повинні бути обов’язковими. /opt/zfs Ось ZFS: - ім'я: Створити /opt/zfs ansible.builtin.file: шлях: /opt/zfs стан: каталог Якщо ви хочете завантажити ZFS: - ім'я: Завантажити zfs ansible.builtin.get_url: url: "httpsgithub.com/openzfs/zfs/releases/download/zfs _zfs_version zfs _zfs_version tar.gz"контрольна сума:_zfs_tarball_sha256_checksummode: 0755 dest: "/opt/zfs/zfs _zfs_version .gz"Ось заміна {{ _zfs_version }} ( 2.1.1. Ви також захочете виконати завантаження самостійно та зібрати/згенерувати контрольну суму для використання. Ніколи не завантажуйте з Інтернету те, що не має змінюватися без контрольної суми! {{синтаксис шаблонів Ansible) є І якщо ви хочете скопіювати його з комп’ютера, де запущено Ansible (це те, що я роблю): - ім'я: Копіювати пакет zfs (уникати обмеження швидкості) ansible.builtin.copy: src: files/zfs/zfs _zfs_version tar.gz"mode: 0755 dest: "/opt/zfs/zfs _zfs_version tar.gz"Незалежно від того, як ви виберете джерело, вам, звичайно, потрібно буде його розпакувати: - ім'я: розархівуйте код zfs ansible.builtin.unarchive: src: "/opt/zfs/zfs _zfs_version tar.gz"dest: "/opt/zfs"remote_src: так Щоб почати процес складання: - ім'я: Налаштування та збірка ZFS ansible.builtin.shell: | ./autogen../configure make clean make -j args: chdir: "/opt/zfs/zfs _zfs_version Якщо ви знайомі зі створенням речей із джерела, різні проекти використовують цей загальний набір інструментів (деякий варіант створювати, автоматично створювати та налаштовувати сценарії). Як ви могли очікувати, це може зайняти деякий час, тож дайте цьому трохи часу. Після створення ZFS - ім'я: Встановити ZFS ansible.builtin.shell: | make install args: chdir: "/opt/zfs/zfs _zfs_version Зазвичай ви думаєте, що ми закінчимо *прямо тут*, але ця публікація існує, тому що зробити це, як правило, недостатньо! Давайте тиснемо далі. Спочатку примусово вивантажте модуль(и) ZFS, якщо вони запущені: - ім'я: примусове вивантаження модуля(ss) ZFS ansible.builtin.shell: | ./scripts/zfs.-u args: chdir: "/opt/zfs/zfs _zfs_version Було б ідеально *не* виконувати жодних робочих навантажень, коли це відбувається, як ви могли очікувати. Поки модулі вивантажуються, ми можемо встановити деякі помічники: - назва: Помічники ZFS після встановлення ansible.builtin.shell: | ./scripts/zfs-helpers.-i args: chdir: "/opt/zfs/zfs _zfs_version Після того, як помічники встановлені, давайте примусово перезавантажимо модуль ZFS: - ім'я: примусове перезавантаження модуля ZFS ansible.builtin.shell: | ./scripts/zfs.args: chdir: "/opt/zfs/zfs _zfs_version Я знайшов цю будівлю та використовував модуль deb (формат, який використовується Debian для інсталяції пакунків) також допоміг змусити інсталяцію закріпитись і не замінюватися стандартними параметрами пакета Ubuntu. Спочатку створіть пакет ZFS deb із вихідного коду: - ім'я: збірка пакета deb ZFS ansible.builtin.shell: | make deb args: chdir: "/opt/zfs/zfs _zfs_version А потім встановіть його - ім'я: інсталювати пакети deb ZFS ansible.builtin.shell: | так | dpkg -i --force-overwrite deb apt install -f -y deb args: chdir: "/opt/zfs/zfs _zfs_version Теоретично цей крок *не має* бути необхідним (або його слід використовувати окремо), оскільки ми вже запустили процес інсталяції, але я виявив, що, роблячи те чи інше, я Виникли б ситуації, коли перезавантаження запропонувало б використати старішу версію ZFS (незважаючи на apt purge) â особливо на рівні ядра. modprobe Якщо ви хочете негайно ввімкнути встановлений модуль ZFS, використовуйте modprobe: - ім'я: блок модуля Modprobe zfs: - ім'я: встановити модуль ядра zfs community.general.modprobe: ім'я: стан zfs: присутній Встановлення ZFS означає інсталяцію модуля ядра, але оскільки ми ще не повністю запекли це через підтримку динамічного модуля ядра, нам потрібно ввімкнути використання локально встановлених модулів ядра: - ім'я: переконайтеся, що додаткове розміщено попереду ansible.builtin.lineinfile: шлях: /etc/modules-load.d/modules.conf регулярний вираз: рядок '^search': "пошук додаткових оновлень, вбудованих у Ubuntu"стан: присутній Це гарантує, що файл, який керує шляхом пошуку модуля ядра У /etc/modules-load.d/modules.conf є рядок, який має пошук зазначених додаткових оновлень. Зазвичай є принаймні один рядок, який починається з пошук, і ми хочемо переконатися пошук додаткових модулів здійснюється на початку процесу. Ми хочемо встановити через підсистему DKMS: - ім'я: dkms install zfs ansible.builtin.shell: | dkms встановити zfs _zfs_version }} args: chdir: "/opt/zfs/zfs _zfs_version На цьому етапі ви зможете перевірити поточну активну версію ZFS, і вона має показати вам щось на зразок цього: root@machine01 ~ # версія zfs zfs-2.1.1-1 zfs-kmod-2.1.1-1 Є кілька модулів SystemD (як зазвичай, Digital Ocean має декілька чудових документів), які створено, але їх потрібно ввімкнути для використання ZFS: - name: Переконайтеся, що блоки systemd, пов'язані з zfs, увімкнено 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 Циклічне проходження змінних схоже на запуск 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).