โฮสต์อย่างยั่งยืน มีการจัดการ F/OSS ที่เก็บวัตถุ Redis, Prometheus บน Hetzner, OVH และ LeaseWeb **tl;dr - คำอธิบายทีละบรรทัดของสคริปต์การติดตั้ง ZFS ที่ขับเคลื่อนด้วย ansible สำหรับใช้กับฮาร์ดแวร์เฉพาะของ Hetznerà ¢ÂÂs (Ubuntu 20.04 - âÂÂFocalâÂÂ) â  ità ¢Â ไม่สมบูรณ์แบบ/น้อยที่สุด แต่มันใช้ได้ผลสำหรับฉัน เมื่อไม่นานมานี้ ฉันเริ่มใช้ ZFS กับฮาร์ดแวร์เฉพาะสำหรับโลหะเปลือยทั้งหมดของฉันที่โฮสต์ที่ Hetzner เพื่อต่อสู้กับ HDD และ SSD ที่แนบมา มีตัวเลือกมากมายในพื้นที่ (LVM มาตรฐาน เอ็มเดร btrfs ฯลฯ ) แต่ฉันเลือก ZFS เพราะ feaureset และการยศาสตร์ ฉันจะไม่เบื่อใครด้วยเหตุผลว่าทำไม แต่สิ่งหนึ่งที่ฉันต้องนำทางคือวิธีติดตั้ง ZFS เวอร์ชันใหม่กว่าบน Ubuntu 20.04 (หนึ่งในระบบปฏิบัติการที่รองรับที่ Hetzner) ฉันพบปัญหาบางอย่าง (โดยเฉพาะหลังการติดตั้ง) ขณะตั้งค่า ZFS บนระบบของฉัน ดังนั้นฉันจึงต้องการแนะนำวิธีการดำเนินการ โพสต์นี้เป็นคำอธิบายทีละตอนของสคริปต์ Ansible ของฉันที่ติดตั้ง ZFS ก่อนที่คุณจะรู้ว่า ZFS (หรือระบบไฟล์ใดๆ) คุ้มค่าที่จะเปลี่ยนไปใช้หรือไม่ คุณอาจต้องการใช้ RTFM ZFS มีข้อบกพร่องมากมาย และแน่นอนว่าฉันไม่ใช่ผู้เชี่ยวชาญในเรื่องนี้ แต่การรู้วิธีการและเหตุผล ตลอดจนคำศัพท์เฉพาะทาง และแม้แต่ประวัติความเป็นมาของโครงการก็มีความสำคัญมาก ลิงก์บางส่วนเพื่อให้คุณเริ่มต้น: นอกเหนือจาก ZFS (ซึ่งน่าจะเป็นจำนวนที่ไม่รู้จักมากที่สุดที่นี่) คุณอาจต้องการทำความคุ้นเคยกับ Ubuntu และการดูแลระบบทั่วไป Thatà ¢ÂÂs ออกจากพื้นที่ขนาดใหญ่เพื่อครอบคลุม แต่นี่คือลิงค์บางส่วน: แทบจะเป็นไปไม่ได้เลย แต่ถ้าคุณไม่คุ้นเคยกับการดูแลระบบ linux ณ จุดนี้ คุณอาจไม่ควรพยายามทำสิ่งนี้ ฉันเองเลือกที่จะให้ดิสก์ของฉันมีการกำหนดค่าที่ค่อนข้างกำหนดเอง â ฉันมีการตั้งค่า RAID1 (มิเรอร์) ผ่าน mdraid พร้อมกับพาร์ติชันในแต่ละดิสก์ที่ฉันสามารถมอบให้ ZFS จัดการได้ ตามหลักการแล้ว ฉันมีดิสก์ทั้งหมดเพื่อมอบให้กับ ZFS แต่พาร์ติชันก็ใช้งานได้เช่นกัน การตั้งค่าระบบปฏิบัติการ ( installimage) ซึ่งรวมถึงการตั้งค่าดิสก์ที่เรียกใช้จากโหมดช่วยเหลือของ Hetznerà ¢Â และสามารถนำทางด้วยไฟล์ดังต่อไปนี้: # การประกาศไดรฟ์ที่ใช้โดย installimage DRIVE0 /dev/nvme0n1 DRIVE1 /dev/nvme1n1 # เปิดใช้งาน Software RAID (สำหรับดิสก์ OS) SWRAID 1 SWRAIDLEVEL 1 # Bootloader (โดยทั่วไปคือ grub) BOOTLOADER grub # เครื่องโฮสต์ชื่อโฮสต์ machine01 # การกำหนดค่าพาร์ติชั่น PART swap swap 32G PART /boot ext4 1G PART / ext4 128G # พาร์ติชั่นสุดท้ายนี้จะถูกสร้าง (ล้างข้อมูล& สร้างใหม่เป็น ZFS ในภายหลัง) PART /root-disk-remaining ext4 all # คุณสามารถระบุภาพที่ Hetzner ใช้โดยการเข้าถึงเครือข่ายของพวกเขา IMAGE /root/.oldroot/nfs/images/Ubuntu-2004-focal-64-minimal.tar gz เห็นได้ชัดว่านี่เป็นเรื่องเฉพาะของ Hetzner แต่ทำทุกอย่างที่คุณต้องทำบนระบบของคุณเองเพื่อให้มีพาร์ติชั่น / ไดรฟ์สำหรับ ZFS ที่จะใช้ zfsutils-ลินุกซ์และ zfs-zed ใน Ansible YAML ขั้นตอนจะเป็นดังนี้: - ชื่อ: เก็บแพ็คเกจอัปสตรีมที่เกี่ยวข้องกับ zfs ทั้งหมด ansible.buildin.shell: | apt-mark ถือ zfsutils-linux apt-mark ถือ zfs-zed ในขณะที่เขียนโพสต์นี้เวอร์ชันของ zfs-linux ใน Ubuntu Focal คือ 0.8.3 เนื่องจากเป้าหมายของเราที่นี่คือการติดตั้งและใช้เวอร์ชันที่ใหม่กว่าต่อไป เราจึงต้องการตรวจสอบให้แน่ใจว่ามีสิ่งใดเกิดขึ้นบ้าง การอัปเดต apt ไม่ได้แทนที่เวอร์ชันที่ติดตั้งของเราด้วยเวอร์ชันเก่ากว่า ในขณะที่เราอยู่ที่นี่ เรามาล้างแพ็คเกจด้วยกันเถอะ - ชื่อ: ล้างแพ็กเกจอัพสตรีม ZFS (อูบุนตู) หากติดตั้งแล้วละเลยข้อผิดพลาด: ใช่ ansible.buildin.command: | apt purge --allow-change-held-packages zfsutils-ลินุกซ์ zfs-zed คุณสามารถอ่านเอกสารได้ที่ มีแนวโน้มที่จะเห็นอะไร การล้างข้อมูลทำ à ¢Â ità ¢ÂÂs คล้ายกับการลบ แต่ยังลบไฟล์การกำหนดค่าถ้ามี คุณสามารถติดตั้งการพึ่งพาสำหรับ OpenZFS ดังนี้: - ชื่อ: ข้อกำหนดการติดตั้งสำหรับการสร้าง ZFS ansible.buildin.apt: ชื่อ:packagesupdate_cache: ใช่ สถานะ: vars ปัจจุบัน: แพ็คเกจ: - 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.buildin.file: เส้นทาง: /opt/zfs สถานะ: ไดเรกทอรี หากคุณต้องการดาวน์โหลด ZFS: - ชื่อ: ดาวน์โหลด zfs ansible.buildin.get_url: url: "httpsgithub.com/openzfs/zfs/releases/download/zfs _zfs_version zfs _zfs_version tar.gz"checksum:_zfs_tarball_sha256_checksummode: 0755 ปลายทาง: "/opt/zfstar/zfs _zfs_version .gz"นี่คือการทดแทน {{ _zfs_version }} ( 2.1.1. คุณจะต้องการดาวน์โหลดด้วยตัวเองและรวบรวม/สร้างเช็คซัมเพื่อใช้ อย่าดาวน์โหลดสิ่งต่าง ๆ จากอินเทอร์เน็ตที่ไม่ควรเปลี่ยนแปลงโดยไม่มี checsum! {{เป็นรูปแบบไวยากรณ์ของเทมเพลต Ansible) คือ และถ้าคุณต้องการคัดลอกจากคอมพิวเตอร์ที่ Ansible ทำงานอยู่ (นี่คือสิ่งที่ฉันทำ): - ชื่อ: คัดลอกแพ็คเกจ zfs (หลีกเลี่ยงการจำกัดอัตรา) ansible.buildin.copy: src: files/zfs/zfs _zfs_version tar.gz"mode: 0755 dest: "/opt/zfs/zfs _zfs_version tar.gz"ไม่ว่าคุณจะเลือกรับแหล่งที่มาด้วยวิธีใดคุณจะต้องคลายซิปแน่นอน: - ชื่อ: เปิดเครื่องรูดรหัส zfs ansible.buildin.unarchive: src: "/opt/zfs/zfs _zfs_version tar.gz"ปลายทาง: "/opt/zfs"remote_src: ใช่ เพื่อเริ่มกระบวนการสร้าง: - ชื่อ: ตั้งค่าและสร้าง ZFS ansible.buildin.shell: | ./autogen../configure make clean make -j args: chdir: "/opt/zfs/zfs _zfs_version หากคุณคุ้นเคยกับการสร้างสิ่งต่างๆ จากแหล่งที่มา โครงการต่างๆ จะใช้ชุดเครื่องมือทั่วไปนี้ สร้าง สร้างอัตโนมัติ และกำหนดค่าสคริปต์) อย่างที่คุณคาดไว้ อาจใช้เวลาสักครู่ ดังนั้นให้เวลาสักระยะ หลังจากสร้าง ZFS - ชื่อ: ติดตั้ง ZFS ansible.buildin.shell: | ทำการติดตั้ง args: chdir: "/opt/zfs/zfs _zfs_version โดยปกติคุณâÂÂdคิดว่าเราจะทำ *ตรงนี้* แต่โพสต์นี้มีอยู่เพราะการทำเช่นนี้โดยทั่วไปยังไม่เพียงพอ! LetâÂÂsกดต่อไป ขั้นแรกให้บังคับยกเลิกการโหลดโมดูล ZFS หากกำลังทำงานอยู่: - ชื่อ: บังคับยกเลิกการโหลดโมดูล ZFS (ss) ansible.buildin.shell: | ./scripts/zfs.-u args: chdir: "/opt/zfs/zfs _zfs_version จะเป็นการดีที่จะ *ไม่* เรียกใช้เวิร์กโหลดใดๆ เมื่อสิ่งนี้เกิดขึ้น ตามที่คุณคาดไว้ ในขณะที่ไม่ได้โหลดโมดูล เราสามารถติดตั้งตัวช่วยบางอย่างได้: - ชื่อ: หลังการติดตั้ง ZFS Helpers ansible.buildin.shell: | ./scripts/zfs-helpers.-i args: chdir: "/opt/zfs/zfs _zfs_version หลังจากติดตั้งตัวช่วยแล้ว ให้บังคับโหลดโมดูล ZFS ใหม่: - ชื่อ: บังคับโหลดซ้ำของโมดูล ZFS ansible.buildin.shell: | ./scripts/zfs.args: chdir: "/opt/zfs/zfs _zfs_version ฉันพบอาคารนั้นและใช้งาน โมดูล deb (รูปแบบที่ Debian ใช้สำหรับการติดตั้งแพ็คเกจ) ช่วยให้การติดตั้งติดและไม่ถูกแทนที่ด้วยค่าเริ่มต้นของแพ็คเกจ Ubuntu ก่อนอื่นให้สร้างแพ็คเกจ ZFS deb จากซอร์สโค้ด: - ชื่อ: สร้างแพ็คเกจ ZFS deb ansible.buildin.shell: | สร้าง deb args: chdir: "/opt/zfs/zfs _zfs_version แล้วทำการติดตั้ง - ชื่อ: ติดตั้งแพ็คเกจ ZFS deb ansible.buildin.shell: | ใช่ | dpkg -i --force-overwrite deb apt install -f -y deb args: chdir: "/opt/zfs/zfs _zfs_version ในทางทฤษฎี ขั้นตอนนี้ *ไม่ควร* จำเป็น (หรือควรใช้เพียงอย่างเดียว) เนื่องจากเราได้เรียกใช้กระบวนการติดตั้งแล้ว แต่ฉันพบว่าเมื่อทำอย่างใดอย่างหนึ่ง Ià ¢Â Âd มีสถานการณ์ที่การรีสตาร์ทจะทำให้ใช้ ZFS เวอร์ชันเก่ากว่า (แม้ว่า apt purge) â โดยเฉพาะอย่างยิ่งที่ระดับเคอร์เนล ม็อดโพรบ หากคุณต้องการเปิดใช้งานโมดูล ZFS ที่ติดตั้งในทันที ให้ใช้ ม็อดโพรบ: - ชื่อ: Modprobe บล็อกโมดูล zfs: - ชื่อ: ติดตั้งโมดูลเคอร์เนล zfs community.general.modprobe: ชื่อ: สถานะ zfs: ปัจจุบัน การติดตั้ง ZFS หมายถึงการติดตั้งโมดูลเคอร์เนล แต่เนื่องจากเราไม่ได้อบผ่าน Dynamic Kernel Module Support เราจึงจำเป็นต้องเปิดใช้งานโมดูลเคอร์เนลที่ติดตั้งในเครื่องเพื่อใช้: - ชื่อ: ตรวจสอบให้แน่ใจว่าส่วนเสริมอยู่ข้างหน้า ansible.buildin.lineinfile: เส้นทาง: /etc/modules-load.d/modules.conf regexp: '^search'บรรทัด: "ค้นหาการอัปเดตเพิ่มเติมในตัว ubuntu ในตัว"สถานะ: ปัจจุบัน สิ่งนี้ทำให้แน่ใจว่าไฟล์ที่จัดการเส้นทางการค้นหาโมดูลเคอร์เนล /etc/modules-load.d/modules.conf มีบรรทัดที่มี ค้นหาการปรับปรุงพิเศษที่ระบุ โดยปกติจะมีอย่างน้อยหนึ่งบรรทัดที่ขึ้นต้นด้วย ค้นหาและสิ่งที่เราต้องการทำคือทำให้แน่ใจ มีการค้นหาตำแหน่งโมดูลพิเศษในช่วงต้นของกระบวนการ เราต้องการติดตั้งผ่านระบบย่อย DKMS: - ชื่อ: dkms ติดตั้ง zfs ansible.buildin.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 ใช้งานได้: - ชื่อ: ตรวจสอบให้แน่ใจว่าเปิดใช้งานหน่วย systemd ที่เกี่ยวข้องกับ zfs บล็อก: - ansible.buildin.systemd: ชื่อ:itemstate: เริ่มเปิดใช้งาน: ใช่ วนซ้ำ: - 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).