DoItYourself

Die Hintergründe

TrueNAS und auch Proxmox bieten soviel mehr als ich brauche und haben ihre eigene Komplexität. Wenn ich darüber nachdenke, was ich für die nähere Zukunft benötige, dann ist das eigentlich nicht viel.

  • Ein gutes Filesystem für die Daten: ZFS.
  • Homelab Standard zum hosten von Services mit möglichst guten Informationen online: docker compose
  • Gängige Pakete direkt am Host installierbar haben: apt Paketmanager bei Debian basierten Distributionen.
  • Open Source wenn sinnvoll einsetzbar
  • Wireguard Netzwerk um keine Ports zuhause öffnen zu müssen: tailscale oder netbird

Das kann ich mit einer Server Distribution wie Debian Server oder Ubuntu Server erreichen. Ubuntu ist in der Serverwelt ein bekannter Name und ich kann mir vorstellen, dass das Ein oder Andere mit Ubuntu einfacher zu erreichen ist als mit Debian. Sollte Cannonical (Firma hinter Ubuntu) mal verrückt spielen, ist der Umstieg zu Debian sicherlich gut machbar. Also probiere ich es mit Trommelwirbel:
Ubuntu Server.

Die Installation

Ist einfach. Ich habe mich durch den Installer durchgearbeitet und sinnvolle Defaults genommen. Die einzige Besonderheit ist, dass ich den SSH Server mit aktiviert habe. So kann ich per SSH den Server konfigurieren.

micronas ade, hallo hpmicro

Das ist der neue Hostname. Nach dem Neustart verbinde ich mich per SSH auf den Server. Danach erledige ich die Basics. Updaten:

sudo apt update && sudo apt upgrade -y

Das Basissetup

Jetzt dokumentiere ich Schritt für Schritt, was ich manuell durchführe. In Zukunft werde ich wohl ein Skript dafür bauen.

ZFS installieren und ersten Pool erstellen

ZFS installieren scheint recht leicht zu sein:

sudo apt install zfsutils-linux

Dann erstelle ich einen Pool. Ich habe 4 4TB HDDs, 2 kleine SSDs für den Pool zur Verfügung. Aktuell brauche ich noch nicht soviel Platz. Also erstelle ich folgendes Layout:

  • 3 HDDs Raid Z1: Damit kann mir eine HDD ausfallen und ich habe 8 TB Speicherplatz. Pool erstellen
  • 1 HDD als Hot Spare. Die sollte automatisch einspringen, sollte eine der 3 HDDs aus dem Pool ausfallen. Dabei muss ich die Eigenschaft autoreplace aktivieren Spare HDD ergänzen Autoreplace aktivieren
  • 2 SSDs nutze ich zum Beschleunigen des Pools: Hier probiere ich einen Mirror als "ZFS Special Device" aus. Diese können laut einer Beschreibung in der Proxmox Dokumentation sowohl Metadaten, Deduplication Tables und kleine Dateien speichern. Das ist für mich interessant, weil so die großen Dateien auf den HDDs gespeichert sind und die kleinen Dateien auf den schnellen SSDs. Special Device Mirror ergänzen Damit die kleinen Dateien wirklich auf die SSDs geschrieben werden, muss ich das für den Pool generieren. Achtung:
    special_small_blocks muss kleiner sein als die recordsize! special_small_blocks einstellen Damit ist der Pool denke ich fürs Erste vorbereitet für die Nutzung.

Erste ZFS Datasets erstellen

Ich starte mit einer sehr einfachen Basisstruktur:

  • app: Peristent Volumes für Docker Services und vergleichbares.
  • backup: Backups, insbesondere von anderen Hosts. Ich werde langfristig mehrere Hosts haben und die können gegenseitig ein Backup Ziel sein. Durch das Backup Dataset erkenne ich schnell und einfach, wo die Backups sind oder gespeichert werden sollen. Hier konfiguriere ich auch eine Kompression um Speicherplatz zu sparen. Erste Datasets

Snapshots einrichten

Hierfür will ich sanoid und syncoid verwenden. Das ist im Ubuntu Repository, also ist die Installation schnell erledigt:

sudo apt install sanoid
sudo mkdir /etc/sanoid/
sudo cp /usr/share/doc/sanoid/examples/sanoid.conf /etc/sanoid/sanoid.conf

Die Datei sanoid.conf passe ich nur leicht an. Ich ergänze die beiden Datasets.

[tank/app]
        use_template = production
        recursive = zfs

[tank/backup]
        use_template = backup
        recursive = zfs

Bis ich rausgefunden habe, ob der Timer für das automatische Erstellen von Snapshots automatisch aktiviert wird (ja wird er!), wurde schon der erste Snapshot erstellt:

zfs list -rt snap tank/app

Für mich zur Dokumentation, ein Rollback läuft mit:

sudo zfs rollback -r <path-to-snapshot>

Es gibt auch einen einfachen Monitor Befehl:

sanoid --monitor-snapshots

Der zeigt gerade kritische Fehler an, weil ich noch keine Daily Snapshopts habe. Ist logisch, habe sanoid erst jetzt aktiviert. Das werde ich die Tage nochmal prüfen.

Backups einrichten

Ich möchte von Anfang an die Backups nach Best Practices einrichten. Dazu gehört für mich, das nicht mit dem root User zu machen, sondern mit dezidierten Usern, die keine root Rechte besitzen. Dafür gibt es einen guten Blog Post bei klarasystems: Improving Replication Security With OpenZFS Delegation Systemuser anlegen:

sudo useradd -m senduser
sudo useradd -m recvuser

Für den Datenaustausch braucht es ssh keys. Diese generiere ich ohne Passwort.

ssh-keygen -t ed25519 -C "syncoid"

Das Private key File (ohne .pub) kopiere ich zu /home/recvuser/.ssh/syncoid. Den Inhalt des syncoid.pub Files kopiere ich ergänze ich im File /home/senduser/.ssh/authorized_keys senduser die notwendigen Rechte für tank/app geben:

sudo zfs allow senduser snapshot,send,hold tank/app

recvuser die notwendigen Rechte für tank/backup erlauben:

sudo zfs allow recvuser receive,create,mount,rollback tank/backup

Jetzt kommt syncoid ins Spiel. Hier ist es noch alles am gleichen host und daher recht sinnlos. Aber zum Testen passt das schon einmal und sobald ich einen weiteren Host ergänze, werde ich das um die Ziellösung erweitern.

sudo zfs create tank/backup/hpmicro
sudo su recvuser
syncoid --recursive --no-privilege-elevation --no-sync-snap --sshkey
/home/recvuser/.ssh/syncoid senduser@localhost:tank/app 
tank/backup/hpmicro/app

Ich aktiviere wieder den Mountpoint, damit ich die Daten des Backups leicht prüfen kann. Den Mountpoint hatte ich zuvor wegen Fehlermeldungen deaktiviert:

sudo zfs set mountpoint=/tank/backup tank/backup

Damit syncoid automatisch läuft, erstelle ich einen Systemd Service mit Timer und speichere sie in /etc/systemd/system/

syncoid.service:

[Unit]
Description=Backup ZFS filesystems
Documentation=man:syncoid(8)
Requires=local-fs.target
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
Environment=TZ=UTC
User=recvuser
ExecStart=/usr/sbin/syncoid --recursive --no-privilege-elevation --no-sync-snap --sshkey /home/recvuser/.ssh/syncoid senduser@localhost:tank/app tank/backup/hpmicro/app

syncoid.timer:

[Unit]
Description=Run Syncoid hourly

[Timer]
OnCalendar=hourly
Persistent=true

[Install]
WantedBy=timers.target

Wichtig nach dem Erstellen der Systemd - Dateien sind folgende Befehle für die Aktivierung der Services:

sudo systemctl daemon-reload
sudo systemctl enable syncoid.timer
sudo systemctl start syncoid.timer

Snapshots und Backups prüfen

Das Mounten eines Snapshots ist leicht möglich und funktioniert recht intuitiv.

sudo mount -t zfs <voller Path des Snapshots> <mountmount z.B. /mnt/temp>

Damit ließen sich auch einzelne Files oder Directories von einem Snapshot oder Backup wiederherstellen. Natürlich nur, wenns nötig ist.

Docker einrichten

Für die Installation nutze ich das Convenience Script: Docker Installation

Monitoring einrichten

Hierfür verwende ich zum Start einen ganz neuen Docker Service CoreControl. CoreControl im ZFS dataset

Das compose.yml sieht wie folgt aus:

services:
  web:
    image: haedlessdev/corecontrol:latest
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      JWT_SECRET: ${JWT_SECRET}
      DATABASE_URL: "postgresql://postgres:postgres@db:5432/postgres"

  agent:
    image: haedlessdev/corecontrol-agent:latest
    restart: unless-stopped
    environment:
      DATABASE_URL: "postgresql://postgres:postgres@db:5432/postgres"
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:17
    restart: unless-stopped
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: postgres
    volumes:
      - ./postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 2s
      timeout: 2s
      retries: 10

Die .env Datei hat nur eine Zeile Inhalt:

JWT_SECRET="<random string"

Und es braucht fürs Monitoring einen glances Container. Hierfür mache ich einen eigenen Ordner tank/app/glances und kopiere folgendes compose.yml hinein:

services:
  glances:
    image: nicolargo/glances:latest
    container_name: glances
    restart: unless-stopped
    ports:
      - "61208:61208"
    pid: "host"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      - GLANCES_OPT=-w --disable-webui

Mit docker compose up -d sind die Services gestartet und schon kann ich im Web-UI von CoreControl den ersten Server konfigurieren und die Monitoring Daten übersichtlich dargestellt betrachten. Ob ich bei CoreControl bleibe, das ist noch nicht so sicher. Aber jetzt habe ich einen ersten Ubuntu Server mit ZFS, Snapshopts und Backups und laufenden Docker Services. Das ist eine gute Basis. Der nächste Schritt ist voraussichtlich, die Daten meines aktuellen Proxmox Hosts hierher zu sichern und den Host als Ubuntu Server neu zu installieren. Aber das ist einer der nächsten Posts.

Matthias