Zum Inhalt springen

Regionenkatalog

Ab mehreren Regionen reicht „Kürzel und Bezeichnung” nicht mehr: zu jeder Region gehören die Domains, unter denen sie erreichbar ist, und die Lebensdauern, die für sie gelten. Das steht in einer JSON-Datei mit allen Regionen, die auf jedem Knoten identisch ausgerollt wird.

Terminal-Fenster
DNSE_REGIONS_FILE=/etc/dnseditor-cloud/regions.json

Ohne die Variable wird genau dieser Pfad erwartet. Liegt dort nichts, gilt weiterhin der alte Weg (DNSE_REGIONS bzw. der eingebaute Katalog) — eine bestehende Installation läuft also unverändert weiter.

{
"session": { "ttl_hours": 12, "touch_interval_minutes": 5 },
"dns": { "frontend_ttl_seconds": 60, "backend_ttl_seconds": 60 },
"ui": { "region_hint": false },
"frontends": ["dns-editor.net"],
"regions": [
{
"code": "eu",
"label": "Europa",
"frontends": ["dns-editor.de", "dns-editor.eu"],
"backends": ["eu01.dns-editor.net", "eu02.dns-editor.net", "eu03.dns-editor.net"],
"dyndns": "dyn.eu.dns-editor.net",
"agents": "agent.eu.dns-editor.net"
}
]
}
FeldBedeutung
codeKürzel der Region; damit wird die Heimatregion einer Organisation gespeichert
labelAnzeigename; fehlt er, steht das Kürzel dort
frontendsdie dieser Region zugeordneten Eingangsdomains
backendsAPI-Domains der Region, in Reihenfolge
dyndns / agentsAdressen, die in den Einrichtungsdialogen ausgegeben werden
frontends (oben)Eingangsdomains ohne Region
session.ttl_hoursLebensdauer einer Anmeldung
session.touch_interval_minutesMindestabstand zwischen zwei Auffrischungen der Sitzungsdauer
dns.*_ttl_secondsTTL der eigenen DNS-Einträge
ui.region_hinterlaubt den Hinweis auf eine passendere Eingangsdomain (Vorgabe: aus)

Nichts davon ist im Programm festgeschrieben — Kürzel, Bezeichnungen, Anzahl der Regionen und alle Domains kommen aus der Datei. Alle Felder außer code sind freiwillig; fehlende Werte werden mit den Vorgaben aufgefüllt. Eine Domain, die nicht dasteht, wird im Operator-Panel als „nicht hinterlegt” gezeigt — nicht erfunden.

Ein Beispiel liegt im Repository unter packaging/regions.example.json.

Der erste Eintrag ist das bevorzugte Ziel, die übrigen sind das Ausweichziel innerhalb derselben Region. Das ist der Grund, warum hier einzelne Namen stehen und nicht ein Name mit mehreren Adressen: Überließe man das Umschalten dem Browser, wäre weder steuerbar noch sichtbar, wann er es tut.

Bei dyndns und agents ist es umgekehrt genau eine Adresse. Ein Router oder ein Cert-Agent wird einmal eingerichtet und wechselt seine Adresse nie selbst; Ausfallsicherheit gehört dort ins DNS (ein Name, mehrere Adressen), nicht in eine Liste, die niemand ausliest.

Ein neutraler Name, der auf Adressen aller Regionen zeigt, gehört unter frontends auf oberster Ebene. Für ihn kann die Oberfläche nichts nachschlagen — sie misst dann, welches Backend am schnellsten antwortet.

Aufgeführt sein muss er trotzdem: Sonst ist seine Herkunft der API nicht bekannt, und der Browser lehnt jeden Aufruf ab.

Die früheren Einzelfelder frontend und backend werden weiter gelesen und vorn in die Listen übernommen. Ein Katalog aus der Zeit davor läuft also unverändert weiter; ein Update erzwingt keinen Rollout.

Sie ordnet die Region einer Eingangsdomain zu, bindet den Benutzer aber nicht: wer über dns-editor.com kommt, bleibt dort. Gewechselt wird nur, welches Backend die Oberfläche anspricht — und das richtet sich nach der Heimatregion der Organisation, nicht nach der gewählten Eingangsdomain.

Ohne placement ist eine Region ein Spaltenwert. Die Zeilen tragen dann zwar die richtige Region, liegen aber dort, wo die Datenbank sie hinlegt — eine Zusage, die man Kunden gegenüber nicht halten könnte.

"placement": "ts_eu" benennt einen vorhandenen Tablespace, an den ORM++ die Partitionen dieser Region bindet:

{ "code": "eu", "label": "Europa", "placement": "ts_eu", "frontends": ["dns-editor.de"] }

Alles oder nichts. Trägt eine Region ein Placement und eine andere nicht, verhindert das den Start. Das ist die eigentliche Entscheidung hinter der Prüfung: ein halb gefüllter Katalog wäre die schlechteste Lage — die Anlage liefe an, ein Teil der Regionen läge physisch richtig, der Rest in der ungebundenen DEFAULT-Partition, und zwar unsichtbar, weil die geo-Spalte in beiden Fällen dasselbe sagt. Ebenso abgelehnt: zwei Regionen auf demselben Tablespace.

Die Tablespaces legt der Betrieb an, nicht die Anwendung

Abschnitt betitelt „Die Tablespaces legt der Betrieb an, nicht die Anwendung“

Replikatzahl und Placement-Blöcke sind eine Betriebsentscheidung. ORM++ legt darum keine Tablespaces an — es prüft nur, ob der deklarierte existiert, und bricht die Migration sonst ab, bevor irgendeine DDL läuft (ErrPlacementNotFound).

Die passenden Anweisungen gibt das Binary aus:

Terminal-Fenster
dnseditor-cloud tablespaces --replicas 3 --zones "eu=eu-1a,eu-1b,eu-1c"

Es gibt sie aus und führt sie nicht aus — der Schritt gehört jemandem, der ihn bewusst tut. Der Grund steht im nächsten Absatz.

Die Bindung entsteht nur beim Anlegen der Partition

Abschnitt betitelt „Die Bindung entsteht nur beim Anlegen der Partition“

ALTER TABLE … SET TABLESPACE ist kein Ersatz. YugabyteDB nimmt es an, meldet „data movement successfully initiated” und schreibt den Katalog um — ohne ysql_beta_feature_tablespace_alteration bewegen sich die Tablets aber nicht. Der Katalog behauptet dann eine Platzierung, die es nicht gibt.

Daraus folgt für den Betrieb: Tablespaces stehen, bevor die erste Migration mit placement läuft. Ein nachträglich angelegter oder geänderter Tablespace wirkt nicht rückwirkend; liegt eine bestehende Partition woanders als deklariert, meldet die Migration ErrPlacementMismatch, statt eine Umbindung vorzutäuschen.

SELECT * FROM yb_local_tablets WHERE table_name LIKE '%_geo_%';

Ausdrücklich nicht über pg_class.reltablespace: die beiden können auseinanderlaufen, und genau das ist die Falle oben. Alles, was nur den Spaltenwert prüft, beweist nichts.

Ein unlesbarer Katalog, doppelte Kürzel, eine Region ohne code oder ein ausdrücklich gesetzter, aber fehlender Pfad verhindern den Start. Das ist gewollt: mit falschen oder stillschweigend zurückgefallenen Backend-Domains weiterzulaufen wäre schlimmer als ein Dienst, der nicht hochkommt — die Knoten würden dann unterschiedliche Adressen ausgeben, und niemand sähe es.

Beim Start steht im Protokoll, was gilt:

level=INFO msg="Regionenkatalog geladen" source=file:/etc/dnseditor-cloud/regions.json
fingerprint=0e309ca7fe00 regions=3

Die Datei muss auf allen Knoten gleich sein. Damit ein halber Rollout auffällt, meldet jeder Knoten den Fingerabdruck seines geladenen Katalogs in seinem Lebenszeichen. Das Operator-Panel zeigt unter System → Regionen den Stand je Knoten und warnt sichtbar, wenn sie auseinanderlaufen.

Der Fingerabdruck steht für den wirksamen Katalog, nicht für die Bytes der Datei: eine andere Einrückung ändert ihn nicht, eine andere Backend-Domain schon.

Ein Katalogwechsel ist ein Neustart — die Datei wird beim Start gelesen und danach nicht mehr.

Die Oberfläche braucht den Katalog, bevor jemand angemeldet ist:

Terminal-Fenster
curl https://eu-central.dns-editor.net/api/v1/regions

Die Antwort enthält nur Kürzel, Bezeichnungen und Domains — also Namen, die ohnehin im DNS stehen. Quelle, Fingerabdruck und die Knotenstände bleiben dem Operator-Panel vorbehalten.

Aus den Frontend-Domains speist sich außerdem die CORS-Liste: eine Region im Katalog heißt, dass ihre Eingangsdomain die API über Kreuz aufrufen darf. Eine zweite Liste an anderer Stelle gibt es bewusst nicht.

Die Frontend-Domains sind gleichwertige Eingänge und werden nie automatisch gewechselt. Was sich anpasst, ist das Backend: Nach dem Login sprechen alle Aufrufe mit der Heimatregion der Organisation.

Vor dem Login gilt die Region der Eingangsdomain. Wer über dns-editor.de kommt, spricht mit eu01 — ohne dass dafür etwas gemessen würde. Die Zuordnung steht im Katalog, und nach dem Login zählt ohnehin die Heimatregion; eine Messung wäre Aufwand ohne Wirkung.

Gemessen wird nur in zwei Fällen: bei einer regionslosen Eingangsdomain, und um die Reihenfolge zu bestimmen, in der fremde Regionen als Ausweichziel probiert werden.

Der Grund ist die Datenhaltung. Die Daten einer Organisation liegen geo-partitioniert in ihrer Heimatregion. Ein „näheres” Backend würde die Entfernung nicht beseitigen, sondern nur hinter den Knoten verschieben — und einen zusätzlichen Sprung addieren.

Dafür gibt es einen öffentlichen Endpunkt, den die Anmeldemaske vor dem Passwort aufruft:

Terminal-Fenster
curl -X POST https://eu01.dns-editor.net/api/v1/auth/resolve \
-H "Content-Type: application/json" \
-d '{"email":"anna@example.com"}'
# → {"region":"an",
# "backend":"an01.dns-editor.net",
# "backends":["an01.dns-editor.net","an02.dns-editor.net","an03.dns-editor.net"]}

backend ist das bevorzugte Ziel, backends die vollständige Liste der Heimatregion — daraus baut die Oberfläche ihre Ausweich-Reihenfolge.

Jede Region kann die Frage beantworten — Identitäten sind global. Die Oberfläche merkt sich das Backend und beginnt beim nächsten Start dort, statt wieder bei ihrer Eingangsregion.

Er ist ohne Anmeldung erreichbar, also ist beides Absicht und durch Tests festgehalten:

  • Ob es die Adresse gibt. Eine unbekannte Adresse bekommt dieselbe Antwort wie eine bekannte ohne besondere Heimat: die primäre Region. Sonst wäre er ein Verzeichnisdienst zum Durchprobieren.
  • Welche Organisationen dahinterstehen. Weder Namen noch Anzahl. Wer mehreren angehört, sieht die Auswahl erst nach dem Passwort.

Dort ist die Frage sinnlos — es gibt genau ein Backend. Antwortet der Endpunkt nicht, bleibt die Oberfläche stillschweigend beim aktuellen. Eine fehlende Regionsauflösung darf keine Anmeldung verhindern.

Antwortet das Backend gar nicht mehr, geht die Oberfläche die übrigen durch — und zwar erst die derselben Region (eu01 → eu02 → eu03), dann fremde. Der Grund ist wieder die Datenhaltung: Der Anmeldetoken gilt zwar überall, aber ein fremdes Backend greift quer zur Datenbank. Das ist ein Notnagel, kein gleichwertiges Ziel.

Zwei Unterscheidungen sind dabei wichtig, weil sie leicht anders erwartet werden:

Eine Fehlerantwort löst kein Ausweichen aus. Kommt ein HTTP-Status zurück, lebt das Backend — es sagt nur nein. Der nächste Knoten sagte dasselbe, und aus einem klaren Fehler würde eine Rundreise.

Schreibende Aufrufe werden nicht wiederholt. Bricht die Verbindung bei einem POST ab, ist nicht bekannt, ob der Server ihn schon ausgeführt hat — die Antwort kann auf dem Rückweg verloren gegangen sein. Ein Wiederholen legte die Zone dann zweimal an. Das Backend wird trotzdem umgestellt, der nächste Versuch läuft also schon auf dem gesunden Knoten.

Sitzt die Organisation in einer anderen Region als die gewählte Eingangsdomain, kann die Oberfläche darauf hinweisen. Freigeschaltet wird das im Katalog:

"ui": { "region_hint": true }

Vorgabe ist aus, und das ist eine bewusste Entscheidung: Der Hinweis lädt zu einem Domainwechsel ein, und der kostet eine neue Anmeldung — eine andere Domain ist ein anderer Ursprung, und der Anmeldetoken liegt im Speicher des ursprünglichen. Der Hinweistext sagt das auch; ohne diesen Satz wäre er eine Einladung, die vor dem Anmeldeformular endet.

Liegen die Regionen dicht beieinander, ist der Gewinn die Mühe nicht wert: Über die Eingangsdomain laufen nur die statischen Dateien und der TLS-Handschlag — alle API-Aufrufe gehen ohnehin an die Heimatregion.

Der Hinweis stützt sich nicht auf eine Messung, sondern auf den Vergleich der Heimatregion mit der Region der Eingangsdomain. Er ist deshalb stabil, auch wenn das Netz gerade schwankt. Gewechselt wird nie automatisch; der Benutzer klickt oder klickt ihn weg.

Die Namen stehen im Katalog, die Adressen ebenfalls — daraus fällt der Zoneninhalt ab. Eine zweite, von Hand gepflegte Zonendatei wäre die Stelle, an der Katalog und DNS auseinanderlaufen, ohne dass es jemand merkt.

Dafür trägt jede Region drei zusätzliche Angaben:

{
"code": "eu",
"edge": ["203.0.113.10", "2001:db8:1::10"],
"health": "/healthz",
"addresses": {
"eu01.dns-editor.net": ["203.0.113.11"],
"eu02.dns-editor.net": ["203.0.113.12"]
}
}

edge sind die Adressen, unter denen die Eingangsdomains dieser Region erreichbar sind — sie gehören der Region, nicht einer einzelnen Domain. addresses ordnet jedem Backend-Namen genau den Rechner zu, den er bezeichnet. health ist der Pfad, den der Nameserver abfragt.

Beim Laden geprüft: keine Nicht-IPs, und kein Name, der der Region nicht gehört. Ein stillschweigend ignorierter Tippfehler hieße: der Rechner fehlt im DNS und niemand merkt es.

NameAntwort
Eingangsdomain mit Regiongeprüft über die Adressen dieser Region
Eingangsdomain ohne Regiongeprüft über alle Regionen, die nächste gewinnt
Backend-Nameschlicht, ohne Prüfung

Der Backend-Name bezeichnet genau einen Rechner. Ein Healthcheck im DNS käme der Ausweich-Kette der Oberfläche in die Quere — beide schalteten unabhängig voneinander um.

Auf einer regionsgebundenen Eingangsdomain gibt es keine Nähe-Auswahl: Es steht nur eine Region zur Wahl. Damit braucht auch nur derjenige eine MaxMind-Datenbank für PowerDNS, der eine regionslose Domain veröffentlicht.

Weil ein defekter Healthcheck nicht auffällt, gehört diese Probe zur Inbetriebnahme — einmal je Zone:

  1. Eine erreichbare und eine tote Adresse in einen Testeintrag setzen.
  2. Etwa 15 Sekunden warten (Prüfintervall × minimumFailures).
  3. dig +short @<ns> test.dns-editor.de A mehrfach abfragen.

Kommt nur die erreichbare Adresse: die Prüfung arbeitet. Kommen beide, gilt alles als tot — dann prüft der Nameserver nicht, was Sie denken, und die Ursache liegt fast immer beim Zertifikat.