Hochverfügbarkeit (Pacemaker, DRBD und eine Floating-IP)
Dieses Handbuch beschreibt eine Referenzarchitektur für den Betrieb von grommunio in einem hochverfügbaren (HA) Aktiv/Standby-Cluster mit zwei Knoten und einem dritten Witness-Knoten. Der Speicher wird auf Blockebene mit DRBD repliziert, der Cluster wird von Pacemaker/Corosync verwaltet, und Clients erreichen den aktiven Knoten über eine floating virtual IP (VIP). Bei einem Failover wird der gesamte Stack – Speicher, IP und Dienste – gemeinsam auf den überlebenden Knoten verlagert.
Architekturübersicht
Abschnitt betitelt „Architekturübersicht“- Zwei Datenknoten (
node1,node2) replizieren ein Blockgerät untereinander mit DRBD. Zu jedem Zeitpunkt ist einer primär (aktiv), der andere sekundär. - Der aktive Knoten startet DRBD, mountet das replizierte Volume als XFS unter
/grodata, bindet die Dienstdatenverzeichnisse von/grodata/*auf die Standardpfade/var/lib/*ein, übernimmt die floating VIP und startet alle grommunio/Gromox-Dienste. - Ein Witness-Knoten (
node3) nimmt nur an der Quorum-Abstimmung teil. Er speichert keine Daten und führt keine grommunio-Dienste aus. - Clients lösen
grommunio.example.comüber DNS in die VIP auf, die sich immer auf dem aktiven Knoten befindet.
Knoten und Rollen
Abschnitt betitelt „Knoten und Rollen“| Rolle | Beispiel-Host | Zweck |
|---|---|---|
| Datenknoten 1 | node1 |
DRBD-Peer; berechtigt, den aktiven Stack auszuführen |
| Datenknoten 2 | node2 |
DRBD-Peer; berechtigt, den aktiven Stack auszuführen |
| Witness / Quorum | node3 |
Nur Quorum-Abstimmung – keine Daten, keine Dienste |
| Floating VIP | 10.0.0.10/24 |
Die Dienstadresse, mit der sich Clients verbinden |
Voraussetzungen
Abschnitt betitelt „Voraussetzungen“- Drei Knoten mit derselben Betriebssystem- und grommunio-Paketversion (zwei Datenknoten sowie ein Witness).
- Ein dediziertes Blockgerät auf jedem Datenknoten für DRBD (gleiche Größe auf beiden).
- Eine freie IP-Adresse für die VIP auf der Cluster-Netzwerkschnittstelle
(
eth0in den Beispielen – verwenden Sie Ihren tatsächlichen Netzwerkkartennamen, z. B.ens192). - Zuverlässige Namensauflösung (
/etc/hostsEinträge für alle Knoten), Zeitsynchronisation (chrony) und SSH-Konnektivität zwischen den Knoten. - Auf allen Knoten installierte Cluster-Pakete:
pacemaker,corosync, eine CRM-Shell (crmsh),drbd-utilsundresource-agents.
Cluster-Stack: Corosync & Pacemaker
Abschnitt betitelt „Cluster-Stack: Corosync & Pacemaker“Corosync (/etc/corosync/corosync.conf) definiert den Clusternamen und die drei
Mitgliedsknoten; Pacemaker verwaltet die Ressourcen auf dieser Ebene.
Für diesen Entwurf sind einige clusterweite Eigenschaften von Bedeutung:
- Quorum mit drei Knoten toleriert den Ausfall eines beliebigen Knotens (einschließlich des Witness) ohne Verlust des Quorums.
- Der Witness wird dienstfrei gehalten, wobei Standortbeschränkungen gelten, die den
VIP, das
/grodata-Mount und die Dienstgruppe mit-infauf einer Skala vonnode3bewerten.
Speicher: DRBD und /grodata
Abschnitt betitelt „Speicher: DRBD und /grodata“DRBD-Ressource
Abschnitt betitelt „DRBD-Ressource“Eine einzelne DRBD-Ressource (grodata, Gerät /dev/drbd0) repliziert die zugrunde liegende
Festplatte zwischen den beiden Datenknoten. Nach der anfänglichen vollständigen Synchronisierung wird DRBD
an Pacemaker übergeben, das sie als promotable clone (clone-max=2,
promoted-max=1) verwaltet, sodass jeweils genau ein Knoten als Primärknoten fungiert.
# Inspect replication state before and after any changedrbdadm statuscat /proc/drbdDas Konzept des Einbindens und des Bind-Mounts
Abschnitt betitelt „Das Konzept des Einbindens und des Bind-Mounts“Auf dem aktiven Knoten wird /dev/drbd0 unter /grodata als XFS-Volume eingebunden. Das Datenverzeichnis jedes Dienstes
wird dann von /grodata über einen Bind-Mount auf seinen Standardpfad
/var/lib/*-Pfad bind-gemountet, sodass die persistenten Daten bei einem Failover dem DRBD-Volume folgen.
Quelle unter /grodata |
Ziel der Bind-Mount-Zuordnung | Zweck |
|---|---|---|
/grodata/mysql |
/var/lib/mysql |
MariaDB-Datenverzeichnis |
/grodata/redis |
/var/lib/redis |
Redis-Persistenz |
/grodata/gromox |
/var/lib/gromox |
Gromox-E-Mail-Speicher / Speicherdaten |
/grodata/grommunio-web |
/var/lib/grommunio-web |
Webdaten, Sitzungen, Index |
/grodata/grommunio-antispam |
/var/lib/grommunio-antispam |
Antispam-Daten |
/grodata/grommunio-dav |
/var/lib/grommunio-dav |
DAV-Daten |
/grodata/grommunio-admin-api |
/var/lib/grommunio-admin-api |
Admin-API-Daten |
Im Cluster werden die Bind-Mounts als Filesystem-Primitive mit
fstype=none und options=bind modelliert, die in einer Gruppe (grodata_binds) zusammengefasst sind, sodass sie
alle dem Mount DRBD folgen.
Ressourcen zu Pacemaker
Abschnitt betitelt „Ressourcen zu Pacemaker“Zusammenfassung der Ressourcen
Abschnitt betitelt „Zusammenfassung der Ressourcen“| Ressource | Agent | Rolle |
|---|---|---|
groCluster |
ocf:heartbeat:IPaddr2 |
Der „floating VIP“ |
ms_grodata |
ocf:linbit:drbd (erweiterbar) |
DRBD primär/sekundär |
grodata_mount |
ocf:heartbeat:Filesystem |
XFS-Einbindung von /dev/drbd0 unter /grodata |
grodata_binds |
Gruppe von Filesystem (Bind) |
Die sieben Bind-Mounts |
grommunio_svc |
Gruppe von systemd:* |
Der geordnete grommunio/Gromox-Dienststapel |
Reihenfolge des Dienststarts (grommunio_svc)
Abschnitt betitelt „Reihenfolge des Dienststarts (grommunio_svc)“Die Servicegruppe wird (und wird im umgekehrten Reihenfolge beendet) in einer festgelegten Reihenfolge gestartet, sodass die Abhängigkeiten zuerst aufgerufen werden:
| # | Ressource | Einheit |
|---|---|---|
| 1 | mariadb |
systemd:mariadb |
| 2 | redis-grommunio |
systemd:[email protected] |
| 3 | php-fpm |
systemd:php-fpm |
| 4 | gromox-http |
systemd:gromox-http |
| 5 | gromox-midb |
systemd:gromox-midb |
| 6 | gromox-zcore |
systemd:gromox-zcore |
| 7 | gromox-event |
systemd:gromox-event |
| 8 | gromox-timer |
systemd:gromox-timer |
| 9 | gromox-imap |
systemd:gromox-imap |
| 10 | gromox-pop3 |
systemd:gromox-pop3 |
| 11 | gromox-delivery-queue |
systemd:gromox-delivery-queue |
| 12 | gromox-delivery |
systemd:gromox-delivery |
| 13 | grommunio-antispam |
systemd:grommunio-antispam |
| 14 | grommunio-admin-api |
systemd:grommunio-admin-api |
| 15 | nginx |
systemd:nginx |
Bestellung und Colocation
Abschnitt betitelt „Bestellung und Colocation“Die Einschränkungen erzwingen eine logische Abfolge — DRBD hochfahren → /grodata einbinden →
die Bind-Mounts bereitstellen → den VIP aktivieren → die Dienste starten — und sorgen dafür, dass
alles auf dem primären DRBD-Knoten untergebracht bleibt:
| Einschränkung | Auswirkung |
|---|---|
drbd_before_grodata |
ms_grodata muss vor dem Start von grodata_mount bereitgestellt werden |
grodata_before_binds |
/grodata wird vor den Bind-Mounts eingebunden |
binds_before_grommunio_svc |
Bind-Mounts starten vor den Diensten |
grodata_before_ip / ip_before_grommunio_svc |
Die VIP ist an den /grodata-Stack gebunden und startet vor grommunio_svc |
grodata_on_drbd (Colocation) |
/grodata läuft auf dem zum DRBD beförderten Knoten |
grommunio_svc_on_* (Colocation) |
Dienste laufen zusammen mit dem VIP, /grodata und den Bind-Mounts |
no_*_on_witness (Standort, -inf) |
Der VIP, die Mounts und die Dienste sind vom Witness ausgeschlossen |
Die vollständige Konfiguration finden Sie im Beispiel unten.
Postfix (MTA)
Abschnitt betitelt „Postfix (MTA)“In diesem Zusammenhang läuft Postfix unter systemd und ist keine Cluster-Ressource — es wird auf jedem Knoten separat konfiguriert. Postfix lässt sich über MySQL-Lookup-Maps und einen Milter in grommunio integrieren:
| Parameter | Beispielwert / Pfad |
|---|---|
myhostname |
grommunio.example.com |
virtual_mailbox_domains |
mysql:/etc/postfix/grommunio-virtual-mailbox-domains.cf |
virtual_mailbox_maps |
mysql:/etc/postfix/grommunio-virtual-mailbox-maps.cf |
virtual_alias_maps |
mysql:/etc/postfix/grommunio-virtual-mailbox-alias-maps.cf |
recipient_bcc_maps |
mysql:/etc/postfix/grommunio-bcc-forwards.cf |
virtual_transport |
smtp:[::1]:24 |
smtpd_milters |
inet:localhost:11332 (wenn grommunio-Antispam aktiv ist) |
Sie können Postfix auf eine der drei unterstützten Arten ausführen; wählen Sie die für Ihr Betriebsmodell geeignete aus:
- Nur systemd auf jedem Knoten (wie oben). Ein Standby-Knoten kann weiterhin lokale System-E-Mails versenden, auch wenn er keine aktive Postfix-Rolle innehat.
- Als Pacemaker-Ressource, die der HA-Gruppe hinzugefügt wurde, sodass sie zusammen mit dem Rest des Stacks ein Fallback durchführt.
- Als Klon, der gleichzeitig auf beiden Knoten läuft.
Nach jeder Änderung sollten Sie die Dokumentation mit postconf -n vom Live-
Host abgleichen.
Betriebshandbuch
Abschnitt betitelt „Betriebshandbuch“Status- und Zustandsprüfungen
Abschnitt betitelt „Status- und Zustandsprüfungen“# Clustercrm_mon -1crm statuscrm configure show
# Floating IPip a | grep 10.0.0.10crm resource status groCluster
# DRBD and the mountdrbdadm statuscat /proc/drbdmount | grep /grodatadf -h /grodata
# Services and logssystemctl --failedjournalctl -u corosync -u pacemakerjournalctl -fu gromox-httpjournalctl -fu grommunio-admin-apiRessourcen bereinigen und neu starten
Abschnitt betitelt „Ressourcen bereinigen und neu starten“# Clear failure state (all resources, or a single one)crm resource cleanupcrm resource cleanup <RESOURCE>
# Restart an individual servicecrm resource restart gromox-httpcrm resource restart grommunio-admin-apicrm resource restart nginxKnoten im Standby-Modus / online
Abschnitt betitelt „Knoten im Standby-Modus / online“crm node standby node1 # take a node out of resource placementcrm node online node1 # make it eligible againcrm node online node2 # keep the secondary ready for failoverGeplantes Failover
Abschnitt betitelt „Geplantes Failover“- Überprüfen Sie den Zustand des Clusters:
crm_mon -1– Quorum vorhanden, keine ausgefallenen Ressourcen. - Stellen Sie sicher, dass der Zielknoten online ist und sich nicht im Standby-Modus befindet (
crm node online node2). - Überprüfen Sie den Synchronisierungsstatus von DRBD:
drbdadm statusundcat /proc/drbd. - Den aktiven Knoten in den Standby-Modus versetzen oder die Ressourcen kontrolliert auf den Zielknoten verschieben.
- Auf dem Zielknoten bestätigen: DRBD hochgestuft,
/grodataeingebunden, Bind-Mounts aktiv, VIP aktiv, Dienste gestartet. - Überprüfen Sie die Anwendungsseite: Web-Anmeldung, Admin API, IMAP/SMTP, E-Mail-Warteschlange.
Postfix-Vorgänge
Abschnitt betitelt „Postfix-Vorgänge“postconf -nsystemctl status postfixjournalctl -fu postfixmailqpostqueue -fpostsuper -d ALL # flush the queue — only with operational sign-offSicherung und Wiederherstellung
Abschnitt betitelt „Sicherung und Wiederherstellung“Zu sichernde Konfiguration: /etc/corosync/*; das Pacemaker CIB
(crm configure show > cib.txt, optional cibadmin --query > cib.xml);
/etc/drbd.d/*; /etc/fstab und das /grodata-Mount-Layout; /etc/gromox/*;
/etc/grommunio-common/* (einschließlich TLS-Material); /etc/grommunio-admin-api/*;
/etc/nginx/*; die PHP/php-fpm-Konfiguration; /etc/postfix/*; sowie Host-/Netzwerk-
Dateien (/etc/hosts, /etc/hostname, NetworkManager-Verbindungen, sshd_config).
Zu sichernde Daten: konsistente MariaDB-Dumps und/oder physische Backups von
/grodata/mysql; ein Backup auf Dateiebene von /grodata/gromox; die verbleibenden
/grodata/* Unterverzeichnisse (web, redis, dav, admin-api, antispam); TLS-
Zertifikate und private Schlüssel (mit separater Zugriffskontrolle); sowie die Geheimnisse
aus Ihrem Passwort-/Geheimnis-Manager.
Wiederherstellungsprinzip: Einen Knoten mit identischer Betriebssystem- und Paketbasis bereitstellen,
die Konfiguration des DRBD und die zugehörige Festplatte wiederherstellen (bzw. neu initialisieren), die
Konfiguration aus dem Backup wiederherstellen, die Daten unter /grodata wiederherstellen und die
Bind-Mounts, starten Sie MariaDB konsistent und überprüfen Sie die grommunio/Postfix-Zuordnungen,
aktivieren Sie anschließend die Cluster-Ressourcen in einer kontrollierten Reihenfolge und führen Sie Abnahmetests
durch.
Sicherheit und Absicherung
Abschnitt betitelt „Sicherheit und Absicherung“- Konfigurieren Sie STONITH/Fencing (siehe den oben genannten Hinweis) vor dem Einsatz in der Produktion.
- Verwalten Sie TLS-Privatschlüssel (
/etc/grommunio-common/ssl/server.key) und das Zertifikatsbündel mit restriktiven Dateiberechtigungen. - Bewahren Sie Geheimnisse (Datenbank-Anmeldedaten usw.) in einem Secret Manager auf – niemals in der Dokumentation oder einem Repository.
- Sichern Sie SSH und beschränken Sie den Cluster-/Replikationsverkehr auf ein vertrauenswürdiges Netzwerk.
Beispielkonfiguration
Abschnitt betitelt „Beispielkonfiguration“Eine generische crm configure show-Konfiguration für die oben beschriebene Architektur. Passen Sie die Knotennamen,
die VIP, die Netzwerkkarte und Ihre spezifischen DRBD-/Fencing-Einstellungen an; dies ist ein Beispiel als
Ausgangspunkt, keine fertige Lösung.
node 1: node1 attributes standby=offnode 2: node2 attributes standby=offnode 3: node3 attributes standby=off
primitive groCluster IPaddr2 \ params ip=10.0.0.10 cidr_netmask=24 nic=eth0 \ op monitor interval=15s
primitive grodata ocf:linbit:drbd \ params drbd_resource=grodata \ op monitor interval=15s role=Promoted \ op monitor interval=30s role=Unpromoted
primitive grodata_mount Filesystem \ params device="/dev/drbd0" directory="/grodata" fstype=xfs \ op monitor interval=20s
# One bind-mount primitive per service data directory (fstype=none, options=bind)primitive grodata_mount_bind_mysql Filesystem \ params device="/grodata/mysql" directory="/var/lib/mysql" fstype=none options=bind \ op monitor interval=20s timeout=40sprimitive grodata_mount_bind_redis Filesystem \ params device="/grodata/redis" directory="/var/lib/redis" fstype=none options=bind \ op monitor interval=20s timeout=40sprimitive grodata_mount_bind_gromox Filesystem \ params device="/grodata/gromox" directory="/var/lib/gromox" fstype=none options=bind \ op monitor interval=20s timeout=40sprimitive grodata_mount_bind_grommunio_web Filesystem \ params device="/grodata/grommunio-web" directory="/var/lib/grommunio-web" fstype=none options=bind \ op monitor interval=20s timeout=40sprimitive grodata_mount_bind_grommunio_antispam Filesystem \ params device="/grodata/grommunio-antispam" directory="/var/lib/grommunio-antispam" fstype=none options=bind \ op monitor interval=20s timeout=40sprimitive grodata_mount_bind_grommunio_dav Filesystem \ params device="/grodata/grommunio-dav" directory="/var/lib/grommunio-dav" fstype=none options=bind \ op monitor interval=20s timeout=40sprimitive grodata_mount_bind_grommunio_admin_api Filesystem \ params device="/grodata/grommunio-admin-api" directory="/var/lib/grommunio-admin-api" fstype=none options=bind \ op monitor interval=20s timeout=40s
# Service primitives (one per unit; same op timeouts) — see the start-order tableprimitive mariadb systemd:mariadb \ op monitor interval=30s timeout=30s \ op start interval=0s timeout=60s \ op stop interval=0s timeout=60s# … redis-grommunio, php-fpm, gromox-http, gromox-midb, gromox-zcore, gromox-event,# gromox-timer, gromox-imap, gromox-pop3, gromox-delivery-queue, gromox-delivery,# grommunio-antispam, grommunio-admin-api, nginx (identical pattern)
group grodata_binds \ grodata_mount_bind_mysql grodata_mount_bind_redis grodata_mount_bind_gromox \ grodata_mount_bind_grommunio_web grodata_mount_bind_grommunio_antispam \ grodata_mount_bind_grommunio_dav grodata_mount_bind_grommunio_admin_api
group grommunio_svc \ mariadb redis-grommunio php-fpm gromox-http gromox-midb gromox-zcore \ gromox-event gromox-timer gromox-imap gromox-pop3 gromox-delivery-queue \ gromox-delivery grommunio-antispam grommunio-admin-api nginx
clone ms_grodata grodata \ meta promoted-max=1 promoted-node-max=1 clone-max=2 clone-node-max=1 \ notify=true promotable=true interleave=true
# Ordering: promote DRBD → mount → binds → VIP → servicesorder drbd_before_grodata Mandatory: ms_grodata:promote grodata_mount:startorder grodata_before_binds Mandatory: grodata_mount:start grodata_binds:startorder grodata_before_ip Mandatory: grodata_mount groClusterorder binds_before_grommunio_svc Mandatory: grodata_binds:start grommunio_svc:startorder ip_before_grommunio_svc Mandatory: groCluster:start grommunio_svc:start
# Colocation: keep the whole stack on the DRBD-primary nodecolocation grodata_on_drbd inf: grodata_mount ms_grodata:Promotedcolocation grodata_binds_on_grodata inf: grodata_binds grodata_mountcolocation clusterip_on_grodata inf: groCluster grodata_mountcolocation grommunio_svc_on_grodata inf: grommunio_svc grodata_mountcolocation grommunio_svc_on_binds inf: grommunio_svc grodata_bindscolocation grommunio_svc_on_ip inf: grommunio_svc groCluster
# Keep data and services off the witness nodelocation no_grodata_on_witness groCluster -inf: node3location no_mount_on_witness grodata_mount -inf: node3location no_grommunio_on_witness grommunio_svc -inf: node3
property cib-bootstrap-options: \ have-watchdog=false \ cluster-infrastructure=corosync \ cluster-name=grommuniocluster \ stonith-enabled=falsersc_defaults build-resource-defaults: \ resource-stickiness=1