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.
| Bereich | Ergebnis |
|---|---|
| Homeserver-HA-Gate | PASS WITH CONDITIONS |
| MariaDB-only-HA | FAIL für vollständige Mail/Web/SMTP-Kontinuität |
| Web | PASS WITH CONDITIONS: neuer Login nach Failover belegt |
| IMAPS | PASS |
| SMTP | PASS |
| Load Balancer zu hs1 | KNOWN LIMITATION |
| Backup/Restore-Marker | PASS WITH CONDITIONS |
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.
| Rolle | Hostname | IP | Aufgabe |
|---|---|---|---|
| Data Node A | hs1a.cluster.test | 10.210.10.41 | DRBD-Peer und möglicher aktiver Service-Knoten |
| Data Node B | hs1b.cluster.test | 10.210.10.42 | DRBD-Peer und möglicher aktiver Service-Knoten |
| Witness | hs1w.cluster.test | 10.210.10.43 | Quorum-only, keine Mailboxdaten |
| Logischer Homeserver | hs1.cluster.test | 10.210.10.40 | Service-VIP und Zieladresse für Clients |
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
grommunio: 2026.06.1Storage: /dev/vdb -> /dev/drbd0 -> /grodataDRBD resource: hs1-grodataLogical 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.
quorum onlyhs1w.cluster.test10.210.10.43|hs1a.cluster.test -----+----- hs1b.cluster.test10.210.10.41 10.210.10.42DRBD Secondary/Primary DRBD Primary/Secondary|hs1.cluster.testVIP 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.
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.
hostname -fcat /etc/os-releaserpm -qa | sort | grep -E "grommunio|gromox|mariadb|redis|nginx"systemctl --failedip -br addrlsblkchronyc 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.
getent hosts hs1a.cluster.test hs1b.cluster.test hs1w.cluster.test hs1.cluster.testping -c3 hs1b.cluster.testping -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.
zypper in corosync pacemaker crmsh resource-agentsinstall -m 0400 -o root -g root /path/to/lab-authkey /etc/corosync/authkeyinstall -m 0644 -o root -g root corosync.conf /etc/corosync/corosync.confsystemctl enable --now corosync pacemakercrm statuscorosync-quorumtool -s
totem {version: 2cluster_name: grommunio-hs1-hatransport: knetcrypto_cipher: aes256crypto_hash: sha256}nodelist {node {ring0_addr: 10.210.10.41name: hs1anodeid: 1}node {ring0_addr: 10.210.10.42name: hs1bnodeid: 2}node {ring0_addr: 10.210.10.43name: hs1wnodeid: 3}}quorum {provider: corosync_votequorumtwo_node: 0}logging {to_logfile: yeslogfile: /var/log/cluster/corosync.logto_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.
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=20sprimitive 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=20sEOF
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.
zypper in drbd-utils kernel-default-extra drbd-kmp-defaultmodprobe drbdinstall -m 0600 -o root -g root hs1-grodata.res /etc/drbd.d/hs1-grodata.resdrbdadm create-md hs1-grodatadrbdadm up hs1-grodatadrbdadm status hs1-grodata
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.
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=20sprimitive 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=20sprimitive 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=20sclone 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=Startedprimitive 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=20EOF
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.
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-deliverysystemctl stop postfixrsync -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/
| Pfad | Besitzer | Mode |
|---|---|---|
| /grodata/mysql | mysql:mysql | 700 |
| /grodata/redis | redis:redis | 750 |
| /grodata/gromox | gromox:gromox | 770 |
| /grodata/grommunio-web | groweb:groweb | 770 |
| /grodata/grommunio-antispam | groas:grommunio | 750 |
| /grodata/grommunio-dav | root:grodav | 770 |
| /grodata/grommunio-admin-api | grommunio:grommunio | 750 |
/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.
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=20primitive 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=20primitive 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=20primitive 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=20primitive 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=20primitive 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=20primitive 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=20group 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-apiEOF
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.
crm configure <<'EOF'primitive p-vip-hs1 IPaddr2 \params ip=10.210.10.40 cidr_netmask=24 nic=enp0s3 \op monitor interval=10s timeout=20sprimitive p-mariadb systemd:mariadb op start timeout=120s interval=0s op stop timeout=120s interval=0s op monitor interval=20s timeout=30sprimitive p-redis-grommunio systemd:redis@grommunio op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30sprimitive p-php-fpm systemd:php-fpm op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30sprimitive 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=Startedprimitive 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=Startedprimitive p-gromox-zcore systemd:gromox-zcore op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30sprimitive p-gromox-event systemd:gromox-event op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30sprimitive p-gromox-timer systemd:gromox-timer op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30sprimitive p-gromox-imap systemd:gromox-imap op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30sprimitive p-gromox-pop3 systemd:gromox-pop3 op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30sprimitive 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=30sprimitive 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=Startedprimitive p-grommunio-antispam systemd:grommunio-antispam op start timeout=90s interval=0s op stop timeout=90s interval=0s op monitor interval=30s timeout=30sprimitive 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=30sprimitive p-nginx systemd:nginx op start timeout=60s interval=0s op stop timeout=60s interval=0s op monitor interval=20s timeout=30sgroup 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=StartedEOF
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.
crm configure <<'EOF'colocation col-fs-with-drbd inf: p-fs-grodata ms-drbd-hs1:Promotedcolocation col-binds-with-fs inf: g-grodata-binds p-fs-grodatacolocation col-vip-with-fs inf: p-vip-hs1 p-fs-grodatacolocation col-svc-with-binds inf: g-grommunio-svc g-grodata-bindscolocation col-svc-with-vip inf: g-grommunio-svc p-vip-hs1location loc-fence-hs1a-not-on-hs1a fence-hs1a -inf: hs1alocation loc-fence-hs1b-not-on-hs1b fence-hs1b -inf: hs1blocation loc-no-drbd-witness ms-drbd-hs1 -inf: hs1wlocation loc-no-fs-witness p-fs-grodata -inf: hs1wlocation loc-no-binds-witness g-grodata-binds -inf: hs1wlocation loc-no-vip-witness p-vip-hs1 -inf: hs1wlocation loc-no-svc-witness g-grommunio-svc -inf: hs1worder ord-drbd-before-fs Mandatory: ms-drbd-hs1:promote p-fs-grodata:startorder ord-fs-before-binds Mandatory: p-fs-grodata:start g-grodata-binds:startorder ord-binds-before-vip Mandatory: g-grodata-binds:start p-vip-hs1:startorder ord-vip-before-svc Mandatory: p-vip-hs1:start g-grommunio-svc:startEOF
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.
# /etc/gromox/gromox.cfghost_id=hs1.cluster.test# /etc/gromox/http.cfghost_id=hs1.cluster.test# /etc/gromox/exmdb_provider.cfglisten_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
grommunio-admin server show hs1.cluster.testgrommunio-admin domain show ha1.example.testgrommunio-admin user show ha-user@ha1.example.testcrm statusfindmnt /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.
crm statuscrm configure showfindmnt /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-apiip 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.
curl -kI https://10.210.10.40/web/python3 imaps_probe_redacted.py --host 10.210.10.40 --user ha-user@ha1.example.testpython3 smtp_submission_probe_redacted.py --host 10.210.10.40 --port 587 --user ha-user@ha1.example.testpostqueue -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
crm resource move g-grommunio-svc hs1bcrm statusdrbdadm status hs1-grodatafindmnt /grodataip addr show | grep 10.210.10.40crm 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.
# Lab-Beispiel, nicht als Produktionskommando übernehmen:# aktiven QEMU-Knoten hart ausschaltencrm statusdrbdadm status hs1-grodatafindmnt /grodataip addr show | grep 10.210.10.40mailq
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.
| Test | Erwartung | Ergebnis |
|---|---|---|
| Active Partition | eine Seite übernimmt kontrolliert, keine Dual-Primary-Lage | PASS |
| Fencing nicht verfügbar | Cluster blockiert sicher statt unsicher zu promoten | PASS WITH CONDITIONS / SAFE BLOCKED |
| Alter Primary kehrt zurück | kein automatisches Überschreiben der aktiven Seite | PASS |
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.
crm statuscorosync-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.
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.
| Protokoll | Abnahme |
|---|---|
| Web-Neulogin | PASS WITH CONDITIONS |
| Bestehende Web-Session | NOT PROVEN |
| IMAPS | PASS |
| SMTP AUTH/Submission | PASS |
| Mail-Delivery während Hard Failover | DELAYED möglich, kein Loss in geprüften Samples beobachtet |
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.
LB lab LAN: 10.210.10.20/21/22 auf QEMU socket LAN 230.10.20.26:1210hs1 HA LAN: 10.210.10.40/41/42/43 auf QEMU socket LAN 230.10.20.27:1211Ergebnis: 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.
DB moved: teilweise erfolgreichAdmin/Postfix maps: teilweise nutzbarWeb/IMAP/SMTP continuity: nicht ausreichendMARIADB_HA_GATE = FAIL
Gemessene Failover-Zeiten
| Szenario | Messung | Einordnung |
|---|---|---|
| Geplanter Homeserver-Move | 5 Samples: min 6.188 s, median 7.076 s, mean 6.929 s, max 7.410 s | publizierbare Lab-Beobachtung für Mail-Delivery-Recovery |
| Hard-Failure Service-RTO | 1 gültiger Sample: 25.798 s | nur Einzelsample, keine Statistik |
| Hard-Failure Mail-Delivery | 1 gültiger Sample: 33.206 s | verzögerte Queue-Zustellung, keine SLA-Aussage |
| SMTP-akzeptierte Nachrichten | 0/10 verifizierte akzeptierte Nachrichten verloren | Beobachtung, kein garantierter RPO=0-Claim |
| Web-RTO | nicht belastbar gemessen | keine Zahl veröffentlichen |
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
| Prüfbereich | Prüfung | Ergebnis |
|---|---|---|
| Cluster Bootstrap | Manuelle Corosync-Konfiguration belegt; init/join-Historie nicht belegt | PASS WITH CONDITIONS |
| Witness | hs1w ist normaler dritter Voting-Node, kein qdevice/qnetd | PASS |
| STONITH | Lab-Fencing vollständig dokumentiert, produktiv zu ersetzen | PASS_WITH_CONDITIONS |
| DRBD | Ressource, Clone und Sync belegt; Secret redigiert | PASS |
| /grodata | Filesystem-Ressource und Mounts vorhanden | PASS |
| Bind-Mounts | alle sieben Bind-Mounts in Gruppe, Ordering und Colocation | PASS |
| Servicegruppe | finale Units und Reihenfolge aus CIB übernommen | PASS |
| Postfix | systemd-managed außerhalb Pacemaker dokumentiert; Port 24 erklärt | PASS |
| Logischer Homeserver | `hs1.cluster.test`, `host_id` und EXMDB belegt | PASS |
| Datenmigration | Zielbesitzer und Modi geprüft; keine pauschalen chown-Kommandos | PASS |
| Service-Stop-Sequenz | produktive Stop-Reihenfolge nur als Empfehlung, nicht als Lab-History | FAIL |
| Clean-Room-Reproduktion | keine frischen ha2a/ha2b/ha2w ausschließlich nach Artikel aufgebaut | FAIL |
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-antispam mit Rspamd einrichten
grommunio-auth mit Keycloak einrichten
grommunio Files und Office 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






