Kurzüberblick

Teil 10 der grommunio-2026-Serie zeigt den nachgebauten Active/Standby-Homeserver als konkrete Schritt-für-Schritt-Anleitung. Ziel ist ein logischer Homeserver hs1.cluster.test, der auf zwei Datenknoten laufen kann und über Witness, STONITH, DRBD, /grodata, Pacemaker, Corosync und eine Service-VIP abgesichert wird.

Der finale Lab-Status bleibt PASS WITH CONDITIONS: Der Stack wurde funktional aufgebaut und gegen geplante Moves, harte Knotenausfälle, Partitionen und Witness-Verlust getestet. Gleichzeitig bleiben Grenzen sichtbar: produktives Fencing muss echt sein, DRBD ersetzt kein Backup, bestehende Web-Sessions wurden nicht transparent bewiesen und die Load-Balancer-Anbindung zum hs1-Paar blieb wegen getrennter QEMU-L2-Netze eine bekannte Einschränkung.

Homeserver-HA-Gate

Ergebnis
PASS WITH CONDITIONS

MariaDB-only-HA

Ergebnis
FAIL für vollständige Mail/Web/SMTP-Kontinuität

Web

Ergebnis
PASS WITH CONDITIONS: neuer Login nach Failover belegt

IMAPS

Ergebnis
PASS

SMTP

Ergebnis
PASS

Load Balancer zu hs1

Ergebnis
KNOWN LIMITATION

Backup/Restore-Marker

Ergebnis
PASS WITH CONDITIONS

Getestete Umgebung

Die Umgebung war ein isoliertes QEMU/KVM-Lab auf grommunio 2026.06.1. Produktive ForgeOne-Systeme wurden nicht verändert. Die Werte sind Lab-Werte, keine Hersteller-Sizing-Empfehlung.

Data Node A

Hostname
hs1a.cluster.test
IP
10.210.10.41
Aufgabe
DRBD-Peer und möglicher aktiver Service-Knoten

Data Node B

Hostname
hs1b.cluster.test
IP
10.210.10.42
Aufgabe
DRBD-Peer und möglicher aktiver Service-Knoten

Witness

Hostname
hs1w.cluster.test
IP
10.210.10.43
Aufgabe
Quorum-only, keine Mailboxdaten

Logischer Homeserver

Hostname
hs1.cluster.test
IP
10.210.10.40
Aufgabe
Service-VIP und Zieladresse für Clients
bash
grommunio: 2026.06.1
Storage: /dev/vdb -> /dev/drbd0 -> /grodata
DRBD resource: hs1-grodata
Logical endpoint: hs1.cluster.test / 10.210.10.40

Zielarchitektur

Der wichtige Unterschied ist physischer Knoten gegen logischer Homeserver. hs1a und hs1b sind nur Träger des Dienstestacks. Für Clients zählt hs1.cluster.test mit der VIP 10.210.10.40.

bash
quorum only
hs1w.cluster.test
10.210.10.43
|
hs1a.cluster.test -----+----- hs1b.cluster.test
10.210.10.41 10.210.10.42
DRBD Secondary/Primary DRBD Primary/Secondary
|
hs1.cluster.test
VIP 10.210.10.40

Die Ressourcenreihenfolge ist der Kern der Anleitung: Erst muss Quorum/Fencing stimmen, dann darf DRBD Primary werden, danach wird /grodata gemountet, dann folgen Bind-Mounts, VIP und der grommunio-Dienstestack.

bash
STONITH/quorum
-> DRBD promote
-> mount /grodata
-> bind persistent service paths
-> service VIP
-> mariadb, redis, php-fpm, gromox, antispam, admin-api, nginx

Voraussetzungen

Starte diesen Aufbau nur mit zwei sauberen grommunio Data Nodes auf identischem Softwarestand, einem separaten Witness, statischen IPs, funktionierendem DNS oder konsistenten /etc/hosts-Einträgen, NTP, Root-Zugriff, einem dedizierten DRBD-Datenträger und funktionierendem Fencing.

Vor jedem Umbau muss ein Snapshot oder Backup existieren. DRBD spiegelt Zustände und Fehler; es ist kein Backup und schützt nicht vor versehentlichem Löschen, Korruption oder falscher Administration.

Schritt 1: Baseline prüfen

Bevor Cluster-Software installiert wird, müssen beide Datenknoten gleich aussehen. Die Prüfung entscheidet, ob du überhaupt weitergehen solltest.

bash
hostname -f
cat /etc/os-release
rpm -qa | sort | grep -E "grommunio|gromox|mariadb|redis|nginx"
systemctl --failed
ip -br addr
lsblk
chronyc tracking || timedatectl

Erwartung: beide Data Nodes melden grommunio 2026.06.1, keine unerklärten failed units, gleiche Paketbasis und den zusätzlichen Datenträger /dev/vdb für die spätere DRBD-Ressource.

Schritt 2: Cluster-Netzwerk vorbereiten

Alle Cluster-Namen müssen stabil auflösbar sein. Die getestete hs1-Lab-Konfiguration nutzt 10.210.10.41 für hs1a, 10.210.10.42 für hs1b, 10.210.10.43 für hs1w und 10.210.10.40 als Service-VIP. `/etc/hosts.d/hs1-cluster.example` wurde nicht als getesteter Standardweg belegt und bleibt deshalb nicht als ausführbare Anleitung stehen.

Klassifikation: ILLUSTRATIVE. Nutze DNS oder den auf deiner Distribution tatsächlich aktiven Resolver-Mechanismus; danach müssen `getent hosts` und die Cluster-Kommunikation die Namen konsistent auflösen.

bash
getent hosts hs1a.cluster.test hs1b.cluster.test hs1w.cluster.test hs1.cluster.test
ping -c3 hs1b.cluster.test
ping -c3 hs1w.cluster.test

Nachweis: `20260913-hs1-corosync-pacemaker-baseline.txt` und finale Corosync-Konfiguration mit den Node-IPs und Node-IDs.

Schritt 3: Corosync und Pacemaker installieren und konfigurieren

Im finalen Lab ist hs1w kein qdevice/qnetd, sondern ein vollwertiger dritter Corosync/Pacemaker-Knoten mit Stimmrecht. Auf hs1w dürfen keine produktiven Ressourcen laufen; seine Aufgabe ist Quorum und Kontrollpfad.

Klassifikation: getestet für Installation und Service-Start; getestet für die Corosync-Konfiguration. Die Evidence belegt die finale Konfiguration, nicht einen `crm cluster init/join`-Ablauf. Deshalb wird hier keine init/join-Historie behauptet.

bash
zypper in corosync pacemaker crmsh resource-agents
install -m 0400 -o root -g root /path/to/lab-authkey /etc/corosync/authkey
install -m 0644 -o root -g root corosync.conf /etc/corosync/corosync.conf
systemctl enable --now corosync pacemaker
crm status
corosync-quorumtool -s
ini
totem {
version: 2
cluster_name: grommunio-hs1-ha
transport: knet
crypto_cipher: aes256
crypto_hash: sha256
}
nodelist {
node {
ring0_addr: 10.210.10.41
name: hs1a
nodeid: 1
}
node {
ring0_addr: 10.210.10.42
name: hs1b
nodeid: 2
}
node {
ring0_addr: 10.210.10.43
name: hs1w
nodeid: 3
}
}
quorum {
provider: corosync_votequorum
two_node: 0
}
logging {
to_logfile: yes
logfile: /var/log/cluster/corosync.log
to_syslog: yes
}

Nachweis: `cluster-control/hs1-corosync.conf` und `20260913-hs1-corosync-pacemaker-baseline.txt` mit Expected votes 3, Total votes 3 und Quorum 2.

Schritt 4: Witness korrekt einordnen

Der Begriff Witness beschreibt in diesem Artikel die Rolle von hs1w im Lab. Technisch ist hs1w ein normaler dritter Corosync/Pacemaker-Voting-Node ohne DRBD, ohne `/grodata`, ohne VIP und ohne grommunio-Servicegruppe. Es wurde kein qnetd/qdevice-Design getestet.

Klassifikation: getestet. Die finale CIB sperrt DRBD, Filesystem, Bind-Mounts, VIP und Servicegruppe auf hs1w explizit per Location Constraint.

Schritt 5: STONITH einrichten

Die STONITH-Konfiguration ist Lab-only. Der getestete Agent steuert QEMU über einen Host-Controller. In Produktion muss diese Stelle durch echtes Hardware-, Hypervisor- oder Cloud-Fencing ersetzt werden.

Klassifikation: getestet, aber LAB ONLY.

bash
crm configure <<'EOF'
primitive fence-hs1a stonith:fence_qemu_part10_hs1 \
params plug=hs1a base_url="http://10.0.2.2:18092" pcmk_host_list=hs1a pcmk_reboot_action=off \
op monitor interval=60s timeout=20s
primitive fence-hs1b stonith:fence_qemu_part10_hs1 \
params plug=hs1b base_url="http://10.0.2.2:18092" pcmk_host_list=hs1b pcmk_reboot_action=off \
op monitor interval=60s timeout=20s
EOF

Nachweis: `20260913-final-quant-pacemaker-config.txt`, `20260913-hs1-stonith-resources.txt` und `cluster-control/fence_qemu_part10_hs1`.

Schritt 6: DRBD einrichten

DRBD nutzt im hs1-Lab `/dev/vdb` auf hs1a und hs1b und stellt daraus `/dev/drbd0` beziehungsweise `/dev/drbd/by-res/hs1-grodata/0` bereit. Das veröffentlichte Secret ist bewusst redigiert; der reale Wert gehört nie in Artikel, Screenshots oder Repository.

Klassifikation: getestet wegen redigiertem Secret, ansonsten aus der getesteten Datei übernommen.

bash
zypper in drbd-utils kernel-default-extra drbd-kmp-default
modprobe drbd
install -m 0600 -o root -g root hs1-grodata.res /etc/drbd.d/hs1-grodata.res
drbdadm create-md hs1-grodata
drbdadm up hs1-grodata
drbdadm status hs1-grodata
ini
resource hs1-grodata {
protocol C;
net {
cram-hmac-alg sha256;
shared-secret "<redacted-lab-secret>";
}
disk {
on-io-error detach;
}
on hs1a {
device /dev/drbd0;
disk /dev/vdb;
address 10.210.10.41:7790;
meta-disk internal;
}
on hs1b {
device /dev/drbd0;
disk /dev/vdb;
address 10.210.10.42:7790;
meta-disk internal;
}
}

Nachweis: `cluster-control/hs1-grodata.res`, `20260913-hs1-drbd-module-install.txt`, `20260913-hs1-drbd-connected.txt` und `20260913-hs1-drbd-sync-complete.txt`.

Schritt 7: /grodata und Pacemaker-Ressourcen aufbauen

Die finale Chain beginnt mit DRBD als promotable Clone und startet `/grodata` erst auf dem promovierten Datenknoten. `p-drbd-hs1` und `p-fs-grodata` dürfen nicht nur später referenziert werden; sie müssen explizit erzeugt werden.

Klassifikation: getestet aus finalem CIB.

bash
crm configure <<'EOF'
primitive fence-hs1a stonith:fence_qemu_part10_hs1 \
params plug=hs1a base_url="http://10.0.2.2:18092" pcmk_host_list=hs1a pcmk_reboot_action=off \
op monitor interval=60s timeout=20s
primitive fence-hs1b stonith:fence_qemu_part10_hs1 \
params plug=hs1b base_url="http://10.0.2.2:18092" pcmk_host_list=hs1b pcmk_reboot_action=off \
op monitor interval=60s timeout=20s
primitive p-drbd-hs1 ocf:linbit:drbd \
params drbd_resource=hs1-grodata \
op monitor interval=20s role=Unpromoted timeout=20s \
op monitor interval=10s role=Promoted timeout=20s
clone ms-drbd-hs1 p-drbd-hs1 \
meta promotable=true promoted-max=1 promoted-node-max=1 clone-max=2 clone-node-max=1 notify=true interleave=true target-role=Started
primitive p-fs-grodata Filesystem \
params device="/dev/drbd/by-res/hs1-grodata/0" directory="/grodata" fstype=xfs run_fsck=no \
op start timeout=60s interval=0s \
op stop timeout=60s interval=0s \
op monitor interval=20s timeout=40s \
op_params OCF_CHECK_LEVEL=20
EOF

Schritt 8: Daten migrieren

Die Migration wurde für sieben Pfade verifiziert. Entscheidend ist, dass während der Kopie keine unkontrollierten Writes auf den alten Pfaden stattfinden. Die Lab-Evidence belegt die kopierten Zielzustände; eine vollständige produktionssichere Stop-Sequenz inklusive Postfix wurde nicht als exakte Shell-History belegt.

Klassifikation: getestet für die geprüften Zielzustände; die Stop-Reihenfolge ist als RECOMMENDED markiert und ersetzt keine Wartungsplanung.

bash
systemctl stop nginx grommunio-admin-api grommunio-antispam php-fpm 'redis@grommunio' mariadb gromox-http gromox-midb gromox-zcore gromox-event gromox-timer gromox-imap gromox-pop3 gromox-delivery-queue gromox-delivery
systemctl stop postfix
rsync -aHAX /var/lib/mysql/ /grodata/mysql/
rsync -aHAX /var/lib/redis/ /grodata/redis/
rsync -aHAX /var/lib/gromox/ /grodata/gromox/
rsync -aHAX /var/lib/grommunio-web/ /grodata/grommunio-web/
rsync -aHAX /var/lib/grommunio-antispam/ /grodata/grommunio-antispam/
rsync -aHAX /var/lib/grommunio-dav/ /grodata/grommunio-dav/
rsync -aHAX /var/lib/grommunio-admin-api/ /grodata/grommunio-admin-api/

/grodata/mysql

Besitzer
mysql:mysql
Mode
700

/grodata/redis

Besitzer
redis:redis
Mode
750

/grodata/gromox

Besitzer
gromox:gromox
Mode
770

/grodata/grommunio-web

Besitzer
groweb:groweb
Mode
770

/grodata/grommunio-antispam

Besitzer
groas:grommunio
Mode
750

/grodata/grommunio-dav

Besitzer
root:grodav
Mode
770

/grodata/grommunio-admin-api

Besitzer
grommunio:grommunio
Mode
750

Nachweis: `20260913-hs1-grodata-copy-metrics.txt`, `20260913-hs1-local-dir-prep-port-36122.txt` und `20260913-hs1-local-dir-prep-port-36222.txt`. Keine pauschalen `chown -R`-Korrekturen wurden als Artikelanleitung übernommen.

Schritt 9: Bind-Mounts konfigurieren

Alle sieben Bind-Mounts sind Teil der finalen Resource Group. Eine gekürzte Darstellung nur mit mysql, redis und gromox wäre an dieser Stelle irreführend.

Klassifikation: getestet aus finalem CIB.

bash
crm configure <<'EOF'
primitive p-bind-mysql Filesystem \
params device="/grodata/mysql" directory="/var/lib/mysql" fstype=none options=bind run_fsck=no \
op start timeout=40s interval=0s \
op stop timeout=60s interval=0s \
op monitor interval=20s timeout=40s \
op_params OCF_CHECK_LEVEL=20
primitive p-bind-redis Filesystem \
params device="/grodata/redis" directory="/var/lib/redis" fstype=none options=bind run_fsck=no \
op start timeout=40s interval=0s \
op stop timeout=60s interval=0s \
op monitor interval=20s timeout=40s \
op_params OCF_CHECK_LEVEL=20
primitive p-bind-gromox Filesystem \
params device="/grodata/gromox" directory="/var/lib/gromox" fstype=none options=bind run_fsck=no \
op start timeout=40s interval=0s \
op stop timeout=60s interval=0s \
op monitor interval=20s timeout=40s \
op_params OCF_CHECK_LEVEL=20
primitive p-bind-grommunio-web Filesystem \
params device="/grodata/grommunio-web" directory="/var/lib/grommunio-web" fstype=none options=bind run_fsck=no \
op start timeout=40s interval=0s \
op stop timeout=60s interval=0s \
op monitor interval=20s timeout=40s \
op_params OCF_CHECK_LEVEL=20
primitive p-bind-grommunio-antispam Filesystem \
params device="/grodata/grommunio-antispam" directory="/var/lib/grommunio-antispam" fstype=none options=bind run_fsck=no \
op start timeout=40s interval=0s \
op stop timeout=60s interval=0s \
op monitor interval=20s timeout=40s \
op_params OCF_CHECK_LEVEL=20
primitive p-bind-grommunio-dav Filesystem \
params device="/grodata/grommunio-dav" directory="/var/lib/grommunio-dav" fstype=none options=bind run_fsck=no \
op start timeout=40s interval=0s \
op stop timeout=60s interval=0s \
op monitor interval=20s timeout=40s \
op_params OCF_CHECK_LEVEL=20
primitive p-bind-grommunio-admin-api Filesystem \
params device="/grodata/grommunio-admin-api" directory="/var/lib/grommunio-admin-api" fstype=none options=bind run_fsck=no \
op start timeout=40s interval=0s \
op stop timeout=60s interval=0s \
op monitor interval=20s timeout=40s \
op_params OCF_CHECK_LEVEL=20
group g-grodata-binds p-bind-mysql p-bind-redis p-bind-gromox p-bind-grommunio-web p-bind-grommunio-antispam p-bind-grommunio-dav p-bind-grommunio-admin-api
EOF

Schritt 10: Service-VIP und grommunio-Servicegruppe konfigurieren

Die Servicegruppe startet auf dem aktiven Datenknoten nach `/grodata` und den Bind-Mounts. Postfix ist im getesteten Lab ausdrücklich nicht Teil von `g-grommunio-svc`, sondern bleibt systemd-managed. Das erklärt auch die spätere Queue-Beobachtung: Postfix kann Submission annehmen, während lokale Zustellung zu Gromox auf `::1:24` noch nicht bereit ist.

Klassifikation: getestet aus finalem CIB.

bash
crm configure <<'EOF'
primitive p-vip-hs1 IPaddr2 \
params ip=10.210.10.40 cidr_netmask=24 nic=enp0s3 \
op monitor interval=10s timeout=20s
primitive p-mariadb systemd:mariadb op start timeout=120s interval=0s op stop timeout=120s interval=0s op monitor interval=20s timeout=30s
primitive p-redis-grommunio systemd:redis@grommunio op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30s
primitive p-php-fpm systemd:php-fpm op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30s
primitive p-gromox-http systemd:gromox-http op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30s meta target-role=Started
primitive p-gromox-midb systemd:gromox-midb op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30s meta target-role=Started
primitive p-gromox-zcore systemd:gromox-zcore op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30s
primitive p-gromox-event systemd:gromox-event op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30s
primitive p-gromox-timer systemd:gromox-timer op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30s
primitive p-gromox-imap systemd:gromox-imap op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30s
primitive p-gromox-pop3 systemd:gromox-pop3 op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30s
primitive p-gromox-delivery-queue systemd:gromox-delivery-queue op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30s
primitive p-gromox-delivery systemd:gromox-delivery op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30s meta target-role=Started
primitive p-grommunio-antispam systemd:grommunio-antispam op start timeout=90s interval=0s op stop timeout=90s interval=0s op monitor interval=30s timeout=30s
primitive p-grommunio-admin-api systemd:grommunio-admin-api op start timeout=90s interval=0s op stop timeout=90s interval=0s op monitor interval=30s timeout=30s
primitive p-nginx systemd:nginx op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30s
group g-grommunio-svc p-mariadb p-redis-grommunio p-php-fpm p-gromox-http p-gromox-midb p-gromox-zcore p-gromox-event p-gromox-timer p-gromox-imap p-gromox-pop3 p-gromox-delivery-queue p-gromox-delivery p-grommunio-antispam p-grommunio-admin-api p-nginx \
meta target-role=Started
EOF

Schritt 11: Ordering, Colocation und Witness-Sperren setzen

Die finale Ordnung ist vollständig gruppenbasiert: DRBD-Promotion vor `/grodata`, `/grodata` vor allen sieben Bind-Mounts, Bind-Mounts vor VIP und VIP vor Servicegruppe. hs1w ist für Daten- und Service-Ressourcen gesperrt.

Klassifikation: getestet aus finalem CIB.

bash
crm configure <<'EOF'
colocation col-fs-with-drbd inf: p-fs-grodata ms-drbd-hs1:Promoted
colocation col-binds-with-fs inf: g-grodata-binds p-fs-grodata
colocation col-vip-with-fs inf: p-vip-hs1 p-fs-grodata
colocation col-svc-with-binds inf: g-grommunio-svc g-grodata-binds
colocation col-svc-with-vip inf: g-grommunio-svc p-vip-hs1
location loc-fence-hs1a-not-on-hs1a fence-hs1a -inf: hs1a
location loc-fence-hs1b-not-on-hs1b fence-hs1b -inf: hs1b
location loc-no-drbd-witness ms-drbd-hs1 -inf: hs1w
location loc-no-fs-witness p-fs-grodata -inf: hs1w
location loc-no-binds-witness g-grodata-binds -inf: hs1w
location loc-no-vip-witness p-vip-hs1 -inf: hs1w
location loc-no-svc-witness g-grommunio-svc -inf: hs1w
order ord-drbd-before-fs Mandatory: ms-drbd-hs1:promote p-fs-grodata:start
order ord-fs-before-binds Mandatory: p-fs-grodata:start g-grodata-binds:start
order ord-binds-before-vip Mandatory: g-grodata-binds:start p-vip-hs1:start
order ord-vip-before-svc Mandatory: p-vip-hs1:start g-grommunio-svc:start
EOF

Schritt 12: Logische Homeserver-Identität konfigurieren

Der aktive Stack präsentiert einen logischen Homeserver `hs1.cluster.test`. Beide Datenknoten nutzen dieselbe `host_id`, während nur der Pacemaker-aktive Knoten die Services trägt. EXMDB erlaubt die VIP und die beiden physischen Datenknotenadressen.

Klassifikation: getestet für Werte und Validierung, getestet für die redigierte Ausführung der Konfigurationsänderung.

ini
# /etc/gromox/gromox.cfg
host_id=hs1.cluster.test
# /etc/gromox/http.cfg
host_id=hs1.cluster.test
# /etc/gromox/exmdb_provider.cfg
listen_ip=::
exmdb_hosts_allow=::1 127.0.0.1 10.210.10.40 10.210.10.41 10.210.10.42 ::ffff:10.210.10.40 ::ffff:10.210.10.41 ::ffff:10.210.10.42
bash
grommunio-admin server show hs1.cluster.test
grommunio-admin domain show ha1.example.test
grommunio-admin user show ha-user@ha1.example.test
crm status
findmnt /grodata /var/lib/mysql /var/lib/gromox

Nachweis: `20260913-hs1-gromox-logical-endpoint-config.txt`, `20260913-hs1-exmdb-acl-expanded.txt`, `20260913-hs1-logical-server-domain-user.txt` und `20260913-hs1-full-stack-baseline-active.txt`.

Schritt 13: Erster Start

Nach der Konfiguration startet Pacemaker die komplette Kette. Erwartet werden: STONITH auf einem geeigneten Gegenknoten beziehungsweise hs1w, ein promoteter DRBD-Klon, `/grodata`, sieben Bind-Mounts, VIP und `g-grommunio-svc` auf demselben Datenknoten.

Klassifikation: getestet für die Prüfbefehle.

bash
crm status
crm configure show
findmnt /grodata /var/lib/mysql /var/lib/redis /var/lib/gromox /var/lib/grommunio-web /var/lib/grommunio-antispam /var/lib/grommunio-dav /var/lib/grommunio-admin-api
ip addr show enp0s3 | grep 10.210.10.40

Schritt 14: Baseline-Mailbox-Test

Die Baseline zählt erst, wenn Web, IMAPS und SMTP über die Service-VIP funktionieren und die Queue nach Zustellung leer ist. Test-Credentials und Passwörter bleiben intern und gehören nicht in den Artikel.

Klassifikation: getestet für die getestete Prüflogik, Credentials redigiert.

bash
curl -kI https://10.210.10.40/web/
python3 imaps_probe_redacted.py --host 10.210.10.40 --user ha-user@ha1.example.test
python3 smtp_submission_probe_redacted.py --host 10.210.10.40 --port 587 --user ha-user@ha1.example.test
postqueue -p

Nachweis: `20260913-hs1-vip-mail-final-baseline-redacted.txt`, `20260913-hs1-full-stack-baseline-active.txt`, `final-quant-baseline-protocol-probe.txt` und `final-quant-baseline-web-results.txt`.

HA testen

Jeder Failover-Test wurde nach demselben Muster bewertet: Ausgangszustand, Failure Injection, erwartetes Verhalten, beobachtetes Verhalten, Service-Test, Datenintegrität und Ergebnis.

Geplanter Move

bash
crm resource move g-grommunio-svc hs1b
crm status
drbdadm status hs1-grodata
findmnt /grodata
ip addr show | grep 10.210.10.40
crm resource clear g-grommunio-svc

Ergebnis: PASS. Der geplante Move funktionierte. In der quantitativen Messung wurden fünf geplante Moves mit Mail-Delivery-Recovery zwischen 6.188 und 7.410 Sekunden beobachtet, Median 7.076 Sekunden.

Hard Node Failure

Im Lab wurde der aktive Knoten über die QEMU-Kontrolle hart ausgeschaltet. In Produktion ist der entsprechende Test ein kontrollierter Hypervisor-, Hardware- oder Cloud-Fencing-Test.

bash
# Lab-Beispiel, nicht als Produktionskommando übernehmen:
# aktiven QEMU-Knoten hart ausschalten
crm status
drbdadm status hs1-grodata
findmnt /grodata
ip addr show | grep 10.210.10.40
mailq

Ergebnis: PASS WITH CONDITIONS. Der Stack kam auf dem verbleibenden Knoten wieder hoch. Ein einzelner gültiger Hard-Failure-Service-Sample lag bei 25.798 Sekunden, Mail-Delivery bei 33.206 Sekunden. Das ist ein Lab-Einzelsample und keine belastbare Statistik.

Netzwerkpartition und Split-Brain-Schutz

Die Active-Partition-Tests prüften, ob der Cluster doppelte Ownership verhindert. Entscheidend ist nicht maximale Verfügbarkeit um jeden Preis, sondern kein unsicheres Promote.

Active Partition

Erwartung
eine Seite übernimmt kontrolliert, keine Dual-Primary-Lage
Ergebnis
PASS

Fencing nicht verfügbar

Erwartung
Cluster blockiert sicher statt unsicher zu promoten
Ergebnis
PASS WITH CONDITIONS / SAFE BLOCKED

Alter Primary kehrt zurück

Erwartung
kein automatisches Überschreiben der aktiven Seite
Ergebnis
PASS

Witness-Verlust plus Active-Node-Loss

Wenn der Witness fehlt und danach der aktive Datenknoten ausfällt, darf der verbleibende Knoten nicht blind übernehmen. Im Lab endete dieser Test korrekt in SAFE_UNAVAILABLE.

bash
crm status
corosync-quorumtool -s
# Erwartung ohne Quorum: keine unsichere Promotion, manuelle Recovery nach Runbook

Postfix und Delivery Queue während Hard Failover

Der wichtigste Befund aus den quantitativen Hard-Failure-Tests war ein Readiness-Fenster: Postfix war nicht Teil der Pacemaker-Servicegruppe und konnte SMTP annehmen, während gromox-delivery-queue auf ::1:24 noch nicht bereit war.

bash
Postfix submission accepted mail
-> local delivery to ::1:24 was not ready yet
-> message stayed deferred in Postfix
-> message was later delivered after delivery-queue readiness / queue retry

Das ist keine beobachtete Nachrichtenverlustrate, sondern verzögerte lokale Zustellung. In den geprüften Benchmarkdaten gingen 0/10 verifizierte SMTP-akzeptierte Nachrichten verloren. Daraus wird ausdrücklich kein garantiertes RPO=0 abgeleitet.

Web, IMAP und SMTP bewerten

Web wurde funktional als neuer Login über die hs1-VIP vor und nach Failover belegt. Bestehende Web-Sessions wurden nicht als transparent fortgeführt bewertet; ein historischer Test zeigte nach Reload wieder die Login-Maske.

Web-Neulogin

Abnahme
PASS WITH CONDITIONS

Bestehende Web-Session

Abnahme
NOT PROVEN

IMAPS

Abnahme
PASS

SMTP AUTH/Submission

Abnahme
PASS

Mail-Delivery während Hard Failover

Abnahme
DELAYED möglich, kein Loss in geprüften Samples beobachtet

Load Balancer einordnen

Die frühere LB-Schicht mit HAProxy/VRRP wurde separat aufgebaut. Für das finale hs1-Paar blieb die Ende-zu-Ende-Anbindung aber eine Lab-Grenze, weil die LB-VMs und das hs1-Paar in getrennten QEMU-L2-Segmenten lagen.

bash
LB lab LAN: 10.210.10.20/21/22 auf QEMU socket LAN 230.10.20.26:1210
hs1 HA LAN: 10.210.10.40/41/42/43 auf QEMU socket LAN 230.10.20.27:1211
Ergebnis: gleiche geschriebene IP-Range, aber getrennte Lab-L2-Segmente.

Backup und Restore

DRBD ist kein Backup. Im Lab wurde ein enger Restore-Marker geprüft, aber keine vollständige Backup-Strategie abgenommen. Für Produktion braucht es unabhängige Backups, Restore-Tests, Aufbewahrung, Offsite-Kopien und dokumentierte Recovery-Ziele.

Warum MariaDB-only-HA nicht reicht

Der historische MariaDB-only-Ansatz bleibt wichtig, gehört aber nicht in den Aufbaupfad. Das Lab zeigte: Datenbank-Failover allein reicht nicht für Endnutzer-Kontinuität von Web, IMAP und SMTP. grommunio braucht den konsistenten Homeserver-Stack mit Daten, Diensten, VIP, Quorum und Fencing.

bash
DB moved: teilweise erfolgreich
Admin/Postfix maps: teilweise nutzbar
Web/IMAP/SMTP continuity: nicht ausreichend
MARIADB_HA_GATE = FAIL

Gemessene Failover-Zeiten

Geplanter Homeserver-Move

Messung
5 Samples: min 6.188 s, median 7.076 s, mean 6.929 s, max 7.410 s
Einordnung
publizierbare Lab-Beobachtung für Mail-Delivery-Recovery

Hard-Failure Service-RTO

Messung
1 gültiger Sample: 25.798 s
Einordnung
nur Einzelsample, keine Statistik

Hard-Failure Mail-Delivery

Messung
1 gültiger Sample: 33.206 s
Einordnung
verzögerte Queue-Zustellung, keine SLA-Aussage

SMTP-akzeptierte Nachrichten

Messung
0/10 verifizierte akzeptierte Nachrichten verloren
Einordnung
Beobachtung, kein garantierter RPO=0-Claim

Web-RTO

Messung
nicht belastbar gemessen
Einordnung
keine Zahl veröffentlichen

Technische Abnahme

Cluster Bootstrap

Prüfung
Manuelle Corosync-Konfiguration belegt; init/join-Historie nicht belegt
Ergebnis
PASS WITH CONDITIONS

Witness

Prüfung
hs1w ist normaler dritter Voting-Node, kein qdevice/qnetd
Ergebnis
PASS

STONITH

Prüfung
Lab-Fencing vollständig dokumentiert, produktiv zu ersetzen
Ergebnis
PASS_WITH_CONDITIONS

DRBD

Prüfung
Ressource, Clone und Sync belegt; Secret redigiert
Ergebnis
PASS

/grodata

Prüfung
Filesystem-Ressource und Mounts vorhanden
Ergebnis
PASS

Bind-Mounts

Prüfung
alle sieben Bind-Mounts in Gruppe, Ordering und Colocation
Ergebnis
PASS

Servicegruppe

Prüfung
finale Units und Reihenfolge aus CIB übernommen
Ergebnis
PASS

Postfix

Prüfung
systemd-managed außerhalb Pacemaker dokumentiert; Port 24 erklärt
Ergebnis
PASS

Logischer Homeserver

Prüfung
`hs1.cluster.test`, `host_id` und EXMDB belegt
Ergebnis
PASS

Datenmigration

Prüfung
Zielbesitzer und Modi geprüft; keine pauschalen chown-Kommandos
Ergebnis
PASS

Service-Stop-Sequenz

Prüfung
produktive Stop-Reihenfolge nur als Empfehlung, nicht als Lab-History
Ergebnis
FAIL

Clean-Room-Reproduktion

Prüfung
keine frischen ha2a/ha2b/ha2w ausschließlich nach Artikel aufgebaut
Ergebnis
FAIL

Reproduzierbarkeits-Audit: NOT TESTED = 0, TECHNICAL_EXPANSION_REQUIRED = 2, ILLUSTRATIVE_COMMAND_BLOCKS = 1. Alle nicht vollständig belegten ausführbaren Snippets wurden entweder entfernt, als redigiert/normalisiert markiert oder sichtbar als Beispiel gekennzeichnet.

Troubleshooting und Lessons Learned

DRBD-Modul fehlt: drbd-utils allein reichte im Lab nicht. kernel-default-extra und drbd-kmp-default waren notwendig.

Falsche Homeserver-Identität: Wenn host_id und logischer Homeserver nicht konsistent sind, können EXMDB- oder Zugriffsfehler auftreten.

Fencing unavailable: Das gewünschte Verhalten ist Blockade, nicht riskantes Weiterlaufen. Danach braucht es manuelle Recovery und Cleanup nach Runbook.

Postfix zu früh erreichbar: SMTP-Reachability ist nicht automatisch Mail-Delivery-Readiness. Monitoring sollte Queue, Port 24 und gromox-delivery-queue getrennt betrachten.

Produktionshinweise

Für Produktion fehlen aus diesem Lab bewusst keine kritischen Warnungen: echtes Fencing, unabhängige Backups, Monitoring, dokumentierte Recovery-Prozeduren, wiederholte Hard-Failure-Messungen, Load-Balancer-Ende-zu-Ende-Tests und ein Session-/Reconnect-Konzept gehören vor Go-live auf die Checkliste.

Fazit

Der getestete Weg ist nicht MariaDB-only und nicht einfach Multi-Server. Tragfähig wurde das Lab erst als vollständiger logischer Homeserver: DRBD, /grodata, Bind-Mounts, VIP, Dienstestack, Quorum und STONITH in einer kontrollierten Reihenfolge. Genau diese Reihenfolge macht aus dem Lab-Report eine nachbaubare HA-Anleitung.

grommunio 2026 Schritt für Schritt

Die Beiträge bauen chronologisch aufeinander auf. Starte mit der Appliance und ergänze danach Mail-Security, zentrale Anmeldung, Videokonferenzen, Chat, Dateien, Archiv, Geräteverwaltung, Multitenancy und Hochverfügbarkeit.

grommunio 2026 installieren

grommunio-antispam mit Rspamd einrichten

grommunio-auth mit Keycloak einrichten

grommunio Meet einrichten

grommunio Chat einrichten

grommunio Files und Office einrichten

grommunio Archive einrichten

grommunio MDM einrichten

grommunio Multitenancy klassifizieren

grommunio Cluster und Hochverfügbarkeit (dieser Beitrag)

Cluster-Design prüfen lassen?

ForgeOne unterstützt grommunio-Architektur, HA-Labs, Migrationsplanung, Betrieb, Monitoring und dokumentierte Failover-Runbooks. grommunio-Projekt besprechen