F/OSS gerenciado e hospedado de forma sustentável
Armazenamento de objetos, Redis, Prometheus
na Hetzner, OVH e LeaseWeb
**tl;dr - Explicação linha por linha do meu script de instalação do ZFS ansible para uso no hardware dedicado da Hetzner (Ubuntu 20.04 - âÂÂFocalâÂÂ) â  não é perfeito/mínimo, mas funciona para mim
Há algum tempo, comecei a usar o ZFS em todo o meu hardware bare metal dedicado hospedado na Hetzner para organizar os HDDs e SSDs conectados. Existem muitas opções no espaço (LVM padrão,
mdraid
btrfs, etc), mas escolhi o ZFS por seu conjunto de recursos e ergonomia.
Não vou aborrecer ninguém com o porquê, mas uma das coisas que eu precisava navegar era como instalar versões mais recentes do ZFS no Ubuntu 20.04 (um dos sistemas operacionais suportados pela Hetzner). Encontrei alguns problemas (principalmente pós-instalação) ao configurar o ZFS em meus sistemas, então gostaria de dar uma explicação passo a passo de como fiz isso.
Esta postagem é uma explicação estrofe por estrofe dos meus scripts Ansible que instalam o ZFS.
Antes de saber se vale a pena mudar para ZFS (ou qualquer sistema de arquivos), você provavelmente vai querer RTFM. O ZFS tem muitos detalhes e certamente não sou um especialista nisso, mas saber o como e o porquê, bem como a terminologia e até mesmo a história do projeto é muito importante.
Alguns links para você começar:
Junto com o ZFS (que provavelmente é a quantidade mais desconhecida aqui), você provavelmente deseja estar familiarizado com o Ubuntu e a administração geral de sistemas. Isso é uma grande área para cobrir, mas aqui estão alguns links:
É quase desnecessário dizer, mas se você não estiver muito familiarizado com a administração do sistema Linux neste ponto, provavelmente não deveria estar tentando fazer isso.
Eu pessoalmente escolho ter meus discos em uma configuração um tanto personalizada â eu tenho a configuração RAID1 (espelhamento) via
mdraid, juntamente com partições em cada disco que posso dar ao ZFS para gerenciar. Idealmente, eu teria discos inteiros para dar ao ZFS, mas as partições também funcionam.
configuração do sistema operacional (
installimage), que inclui a configuração do disco, é executado no modo de recuperação da Hetzner e pode ser guiado com um arquivo como o seguinte:
# Declarações de unidade usadas por installimage DRIVE0 /dev/nvme0n1 DRIVE1 /dev/nvme1n1 # Habilita RAID de software (para o disco do sistema operacional) SWRAID 1 SWRAIDLEVEL 1 # Bootloader (geralmente grub) BOOTLOADER grub # Máquina hostame HOSTNAME machine01 # Configuração de partição PART swap swap 32G PART /boot ext4 1G PART / ext4 128G # Esta última partição será feita (wiped& recriado como ZFS posteriormente) PART /root-disk-remaining ext4 all # Você pode especificar imagens que Hetzner usa acessando seu compartilhamento de rede IMAGE /root/.oldroot/nfs/images/Ubuntu-2004-focal-64-minimal.tar. gz
Obviamente, isso é bastante específico de Hetzner, mas faça o que for necessário em seus próprios sistemas para ter partições/unidades disponíveis para uso do ZFS.
zfsutils-linuxand
zfs-zed
No Ansible YAML, a etapa fica assim:
- name: Contém todos os pacotes upstream relacionados ao zfs ansible.builtin.shell: | apt-mark segure zfsutils-linux apt-mark segure zfs-zed
No momento da redação deste post, a versão de
zfs-linux no Ubuntu Focal é 0.8.3. Como nosso objetivo aqui é instalar e continuar usando uma versão mais recente, queremos garantir que qualquer
as atualizações do apt não substituem nossa versão instalada por uma versão mais antiga.
Enquanto estamos aqui, vamos limpar os pacotes também.
- name: Limpar pacotes upstream ZFS (ubuntu) se instalado ignore_errors: sim ansible.builtin.command: | apt purge --allow-change-held-packages zfsutils-linux zfs-zed
Você pode ler os documentos em
apto para ver o que
purge faz â é semelhante a remover, mas também remove arquivos de configuração, se presentes.
Você pode instalar as dependências do OpenZFS da seguinte forma:
- name: Instalar requisitos para compilar 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 # A linha abaixo chama a saída de `uname -r`, por exemplo "5.16.5-arch1- 1"para meu arch system # então a linha resolveria para algo como "linux-headers-5.16.5-arch1-1"(não é válido no Ubuntu, é claro, mas como exemplo) - linux-headers uname_r.stdout }} - python3 - python3-dev - python3-setuptools - python3-cffi - libffi-dev - python3-packaging - git - libcurl4-openssl-dev
Pode haver algumas dependências que não são estritamente necessárias, mas quase todas elas devem ser necessárias.
/opt/zfs
Aqui está o ZFS:
- nome: Criar /opt/zfs ansible.builtin.file: caminho: /opt/zfs estado: diretório
Se você deseja baixar o ZFS:
- nome: Baixar 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"Aqui a substituição
{{ _zfs_version }} (
2.1.1. Você também vai querer fazer o download você mesmo e coletar/gerar uma soma de verificação para usar. Nunca baixe coisas da internet que não deveriam mudar sem um checsum!
{{é a sintaxe de modelagem Ansible) é
E se você quiser copiá-lo do computador onde o Ansible está rodando (é o que eu faço):
- name: Copie o pacote zfs (evite o limite de taxa) ansible.builtin.copy: src: files/zfs/zfs _zfs_version tar.gz"modo: 0755 dest: "/opt/zfs/zfs _zfs_version tar.gz"Independentemente de como você escolher obter a fonte, você precisará descompactá-la, é claro:
- nome: Descompacte o código zfs ansible.builtin.unarchive: src: "/opt/zfs/zfs _zfs_version tar.gz"dest: "/opt/zfs"remote_src: sim
Para iniciar o processo de compilação:
- nome: Configuração e construção do ZFS ansible.builtin.shell: | ./autogen../configure make clean make -j args: chdir: "/opt/zfs/zfs _zfs_version
Se você estiver familiarizado com a criação de coisas a partir do código-fonte, vários projetos usam esse conjunto de ferramentas comum (algumas variantes de
criar, autogen e configurar scripts). Como você pode esperar, isso pode demorar um pouco, então espere um pouco.
Depois de construir o ZFS
- nome: Instalar ZFS ansible.builtin.shell: | make install args: chdir: "/opt/zfs/zfs _zfs_version
Normalmente você pensaria que teríamos terminado *aqui*, mas este post existe porque fazer isso geralmente não é suficiente! Vamos seguir em frente.
Primeiro force o descarregamento do(s) módulo(s) ZFS se estiverem em execução:
- name: Forçar descarregamento do(s) módulo(s) ZFS ansible.builtin.shell: | ./scripts/zfs.-u args: chdir: "/opt/zfs/zfs _zfs_version
Seria ideal *não* executar nenhuma carga de trabalho quando isso acontecesse, como seria de esperar.
Enquanto os módulos são descarregados, podemos instalar alguns helpers:
- name: Auxiliares ZFS pós-instalação ansible.builtin.shell: | ./scripts/zfs-helpers.-i args: chdir: "/opt/zfs/zfs _zfs_version
Após a instalação dos auxiliares, vamos forçar o recarregamento do módulo ZFS:
- name: Forçar o recarregamento do módulo ZFS ansible.builtin.shell: | ./scripts/zfs.args: chdir: "/opt/zfs/zfs _zfs_version
Eu encontrei esse edifício e usando o
O módulo deb (o formato usado pelo Debian para instalação de pacotes) ajudou também a manter a instalação e não ser substituído pelos padrões de pacotes do Ubuntu.
Primeiro crie o pacote ZFS deb a partir do código-fonte:
- nome: Construa o pacote deb do ZFS ansible.builtin.shell: | make deb args: chdir: "/opt/zfs/zfs _zfs_version
E então instale-o
- nome: Instalar pacotes deb do ZFS ansible.builtin.shell: | sim | dpkg -i --force-overwrite deb apt install -f -y deb args: chdir: "/opt/zfs/zfs _zfs_version
Teoricamente, esta etapa *não deveria* ser necessária (ou deveria ser usada sozinha), pois já executamos um processo de instalação, mas descobri que ao fazer uma ou outra eu  haveria situações em que as reinicializações solicitariam o uso de uma versão mais antiga do ZFS (apesar do
apt purge) - particularmente no nível do kernel.
modprobe
Se você deseja habilitar o módulo ZFS que foi instalado imediatamente, use
modprobe:
- nome: Bloco do módulo Modprobe zfs: - nome: Instalar o módulo do kernel zfs community.general.modprobe: nome: estado zfs: presente
Instalar o ZFS significa instalar um módulo do kernel, mas como ainda não o instalamos por meio do Dynamic Kernel Module Support, precisamos habilitar o uso de módulos do kernel instalados localmente:
- name: Certifique-se de que extra esteja na frente ansible.builtin.lineinfile: caminho: /etc/modules-load.d/modules.conf regexp: '^search'linha: "pesquisar atualizações extras embutidas no ubuntu"estado: presente
O que isso faz é garantir que o arquivo que gerencia o caminho de pesquisa do módulo do kernel
/etc/modules-load.d/modules.conf tem uma linha nele que tem
pesquisar atualizações extras especificadas. Normalmente há pelo menos uma linha que começa com
pesquisa, e o que queremos fazer é garantir
locais de módulos extras são pesquisados no início do processo.
Queremos instalar por meio do subsistema DKMS:
- nome: dkms install zfs ansible.builtin.shell: | dkms install zfs _zfs_version }} argumentos: chdir: "/opt/zfs/zfs _zfs_version
Neste ponto, você deve ser capaz de verificar a versão ativa atual do ZFS e deve mostrar algo como isto:
root@machine01 ~ # zfs versão zfs-2.1.1-1 zfs-kmod-2.1.1-1
Existem algumas unidades do SystemD (como de costume, o Digital Ocean tem ótimos documentos) que são criadas, mas precisam ser habilitadas para uso do ZFS:
- name: Certifique-se de que as unidades systemd relacionadas ao zfs estejam habilitadas bloco: - ansible.builtin.systemd: name:itemstate: iniciado habilitado: sim loop: - zfs-import-cache.service - zfs-import.target - zfs-mount.service - zfs-share.service - zfs-zed.service - zfs-volume-wait.service - zfs.target
As variáveis que estão sendo repetidas são semelhantes à execução
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).