Der Switch, den du nicht kaufst

Ein Proxmox-Cluster aus drei Knoten mit Ceph will ein schnelles Netz zwischen den Knoten. Die übliche Antwort ist ein 100-Gbit-Switch, und der übliche Einwand ist, was der kostet.

Für drei Knoten gibt es eine andere Antwort: verkabele sie direkt im Dreieck miteinander und route darüber. Überhaupt kein Switch im Speicherweg.

Das billigste Bauteil in jedem Entwurf ist das, das du nicht kaufst, und es ist das einzige, das nie ausfällt.

Das bringt vier Dinge.

Die Kosten des Switch verschwinden. Du brauchst Netzwerkkarten und drei Kabel, keinen Switch mit 100 oder 200 Gbit und der passenden Portzahl.

Der Datenweg hat keinen einzelnen Ausfallpunkt. Ein Switch, der ausfällt oder neu startet, nimmt den ganzen Ost-West-Verkehr des Clusters mit. Knoten, die direkt miteinander verkabelt sind, ist es gleich, was mit einem Switch anderswo im Gebäude passiert.

Der schwere Verkehr liegt auf eigenen Drähten. Live-Migration und Ceph-Replikation bleiben auf dem Mesh, statt mit Büro- und Verwaltungsverkehr zu konkurrieren.

Es zu vergrößern ist Kabelarbeit, keine Frage des Portbudgets. Es gibt keine zentrale Kiste, die eine Decke für Bandbreite oder Portzahl setzt, das Fabric wächst also, solange jeder Server einen freien PCIe-Slot hat. OpenFabric routet von allein über neue Verbindungen.

Und eine ehrliche Grenze, denn sie zählt mehr als die vier Vorteile. Ein Full Mesh braucht ein Kabel zwischen jedem Knotenpaar. Drei Knoten sind drei Kabel. Vier sind sechs. Fünf sind zehn. Die Verkabelung wächst schneller als die Knotenzahl, und dieser Entwurf übersteht nichts über einen kleinen Cluster hinaus, ohne auf etwas Geswitchtes wie Leaf-Spine zu wechseln.

Drei Knoten sind genau die Stelle, an der ein Full Mesh Sinn hat. Darüber hinaus lässt sich mit zwei Mesh-Ports pro Knoten noch ein Ring bauen — und der braucht eine Sache, die dieser Aufbau sonst vermeidet, siehe unten.

Was gebaut wird

Drei Proxmox-VE-Hosts, jeder mit zwei fest zugeordneten 100-Gbit-Schnittstellen, so ins Dreieck verkabelt, dass jeder Knoten zwei direkte Nachbarn hat.

Proxmox SDN erledigt das Routing. OpenFabric ist das Protokoll: es rechnet den besten Weg über das Mesh aus, und wenn ein Kabel gezogen wird oder eine Verbindung wegfällt, routet es über den verbleibenden Weg um. Niemand muss sich anmelden.

Das Fabric wohnt in 10.10.10.0/24, reserviert für das Mesh und nichts anderes — nicht für die Verwaltung, nicht für Gäste, nicht für Speicheradressen, nicht für irgendetwas von außen.

KnotenMesh-AdresseMesh-Schnittstellen
mesh110.10.10.1/32nic1, nic2
mesh210.10.10.2/32nic1, nic2
mesh310.10.10.3/32nic1, nic2

Jeder Knoten bekommt ein /32, keine Scheibe des Subnetzes. Das ist der Sinn eines gerouteten Mesh statt eines gebrückten. Die Adresse bezeichnet den Knoten, OpenFabric verkündet sie, und die zwei physischen Verbindungen sind bloß Wege, ihn zu erreichen. Proxmox legt eine Dummy-Loopback-Schnittstelle an, die sie hält.

Das Dreieck aus drei Knoten, und auf welcher NIC jedes Kabel landet2,5-Gbit-SwitchVerwaltung + Clientmesh110.10.10.1/32mesh210.10.10.2/32mesh310.10.10.3/32DAC-01nic1 ↔ nic1DAC-03nic2 ↔ nic2DAC-02mesh2 nic2 ↔ mesh3 nic1nic0nic0nic0Jeder Knoten erreicht die anderen zwei direkt, jeder Mesh-Sprung ist also ein Sprung. Diegestrichelten nic0-Linien sind der separate 2,5-Gbit-Verwaltungsweg — nie Teil des Fabric, undder Grund, warum du dich noch anmelden kannst, wenn das Mesh kaputt ist.
Drei Kabel, sechs Ports und zwei Wege zu jedem Knoten. Zieh irgendein einzelnes Kabel, und jeder Knoten ist weiter erreichbar — die verbleibenden zwei Verbindungen bilden eine Kette, um die OpenFabric herumroutet.

Die Verkabelung

Aktive Glasfaser-DAC-Kabel, im Dreieck, mit Jumbo Frames auf beiden Mesh-Schnittstellen jedes Knotens.

KabelVonNach
DAC-01mesh1 nic1mesh2 nic1
DAC-02mesh2 nic2mesh3 nic1
DAC-03mesh3 nic2mesh1 nic2

Aktive Glasfaser statt Kupfer-DAC, aus zwei Gründen, die eher mit dem Rack als mit dem Netz zu tun haben:

  • Kabelführung. Aktive Glasfaser-DACs sind dünner und weit biegsamer als Kupfer, sie lassen sich also sauber verlegen und stapeln sich nicht hinter den Servern.
  • Luftstrom. Weniger Kabelmasse hinter dem Gehäuse heißt weniger Störung des Luftstroms von vorn nach hinten, und das zählt, wenn mehrere schnelle Verbindungen in denselben paar Höheneinheiten landen.

Zwei Netze, nicht eines

Das Mesh ist nicht das einzige Netz, und es darf nicht zu einem werden.

Jeder Knoten hat nic0 an einem 2,5-Gbit-Switch, Proxmox gegenüber als Brücke vmbr0 dargestellt. Die trägt die Weboberfläche, den Verwaltungszugang und den Client-Verkehr. Sie ist auch der Weg, den du beim Bauen des Fabric nutzt, und deshalb muss sie davon unabhängig sein.

nic0 wird bewusst aus dem Fabric herausgelassen. Beim Anlegen der Fabric-Knoten werden nur nic1 und nic2 ausgewählt.

Das Mesh trägt drei Dinge:

  • Ceph. Replikation, Wiederherstellung und Backfill von Knoten zu Knoten für den hyperkonvergenten Speicher.
  • Virtuelles Client-Netz. VXLAN-gestützte VNets ziehen Gastnetze über alle drei Knoten und nutzen das geroutete Mesh als Unterlage.
  • Corosync, als zweiter Weg. Der Verkehr für die Cluster-Mitgliedschaft läuft über das Verwaltungsnetz und das Mesh, das Quorum hängt also nicht davon ab, dass eines von beiden allein überlebt.
Was auf dem Verwaltungsnetz reitet, was auf dem Mesh, und das Eine auf beiden2,5-Gbit-Verwaltungsnetznic0 → vmbr0 → SwitchProxmox-WeboberflächeVerwaltungszugangVerkehr zu Clients100-Gbit-Mesh, geroutetnic1 + nic2 → direktes DAC, kein SwitchCeph-Replikation, Wiederherstellung, BackfillVirtuelle VXLAN-Client-NetzeLive-MigrationCorosync — beide WegeDie Cluster-Mitgliedschaft hängt nicht davon ab, dass ein Netz allein überlebt.Die Trennung ist der Entwurf. Die Verwaltung bleibt erreichbar, in welchem Zustand die100-Gbit-Schnittstellen auch sind, und das macht es sicher, das Fabric aus der Weboberfläche zubauen — und zurückzurollen.
Corosync ist das Einzige auf beiden. Alles andere hat genau ein Zuhause — und der Verwaltungszugang ist der, der weiterlaufen muss, während du am anderen etwas änderst.

Die Regel, die es wert ist, auf das Änderungsticket zu schreiben: Verwaltung und Client-Zugang bleiben jederzeit über den 2,5-Gbit-Switch verfügbar, in welchem Zustand die 100-Gbit-Schnittstellen auch sind.

Alles über die Weboberfläche

Dieser Aufbau geschieht vollständig in der Proxmox-Weboberfläche. Das ist eine bewusste Wahl, keine Grenze der Werkzeuge.

Bewusst nicht genutzt:

  • /etc/network/interfaces von Hand bearbeiten.
  • FRR-Konfigurationsdateien von Hand bearbeiten.
  • vtysh als Baumethode.

Proxmox erzeugt die darunterliegende Netz- und Routing-Konfiguration aus den SDN-Objekten, die du festlegst. Wenn etwas sich wirklich nicht in der Oberfläche setzen lässt, ist das es wert, als Voraussetzung genannt zu werden, statt es still auf der Kommandozeile zu richten. Der Nächste, der die Weboberfläche öffnet, wird nicht wissen, dass du das getan hast.

Ausgaben von der Kommandozeile erscheinen unten nur als Beleg, nie als Bauschritt.

Der Aufbau

1. Öffne die Proxmox-Weboberfläche und geh auf Datacenter → SDN → Fabrics.

Die Ansicht Datacenter SDN Fabrics in Proxmox mit der Schaltfläche Add Fabric

2. Leg das Fabric an. Gib ihm einen Namen, das Mesh-Präfix und die Zeitgeber.

Der Dialog Create OpenFabric mit Name auf Mesh, IPv4-Präfix 10.10.10.0/24, Hello Interval 1 und CSNP Interval 1

Hello- und CSNP-Intervalle von 1 bringen den Zustand so schnell wie möglich nach, wenn sich etwas ändert, und genau das willst du auf einem Fabric dieser Größe. Der Preis ist mehr Geplauder auf der Steuerebene. Auf drei Knoten mit je zwei Verbindungen belanglos, einen zweiten Gedanken wert, falls das Fabric je wächst.

3. Füge jeden Knoten mit Add node hinzu. Gib ihm eine Adresse aus dem Mesh-Bereich und häkle die Schnittstellen an, die mitmachen.

Der Dialog Create Node für mesh1 mit IPv4 10.10.10.1 und ausgewählten nic1 und nic2

Achte darauf, was nicht angehäkelt ist: nic0 bleibt draußen, und vmbr0 behält die Verwaltungsadresse. Nutze Create another für die ersten zwei Knoten und Create beim letzten.

4. Prüf das Ergebnis, bevor du es anwendest.

Die Fabric-Liste mit dem Fabric Mesh über OpenFabric auf 10.10.10.0/24 und mesh1, mesh2 und mesh3 auf 10.10.10.1, .2 und .3, jeweils mit nic1 und nic2

Drei Knoten, drei Adressen, nic1, nic2 auf jedem, alle als new markiert — es ist noch nichts geschrieben.

5. Wende die SDN-Konfiguration an.

Die Ansicht SDN Status mit den Schaltflächen Apply und Dry-Run und Zonenstatus ok auf allen drei Knoten

Neben Apply gibt es ein Dry-Run, wenn du erst sehen willst, was es vorhat.

Wissen, dass es geklappt hat

Die Statusansicht sollte auf allen drei Knoten sowohl den Zonen- als auch den Fabric-Eintrag als ok zeigen, und keine ausstehenden Änderungen mehr.

SDN Status mit Zonen- und Fabric-Eintrag im Status ok auf mesh1, mesh2 und mesh3

Dann prüf das Fabric aus der Sicht eines Knotens selbst. Zuerst die Routen — jeder Knoten sollte ein /32 zu jedem anderen haben, und die Spalte Via sagt dir, welchen Nachbarn er dafür nutzt.

Fabric Mesh auf dem Knoten mesh1, Reiter Routes mit 10.10.10.2/32 über 10.10.10.2 und 10.10.10.3/32 über 10.10.10.3

Dann die Nachbarn. Zwei, beide Up, auf einem Dreieck aus drei Knoten.

Fabric Mesh auf dem Knoten mesh1, Reiter Neighbors mit mesh2 und mesh3 beide Up

Dann die Schnittstellen, und dort zeigt sich die Gestalt der Sache: dummy_Mesh als Loopback, der die Router-Adresse hält, und nic1 und nic2 als Point-To-Point statt als Broadcast-Segmente.

Fabric Mesh auf dem Knoten mesh1, Reiter Interfaces mit dummy_Mesh als Loopback und nic1 und nic2 als Point-To-Point, alle Up

Zum Schluss der Beweis von Ende zu Ende.

Shell auf dem Knoten mesh1 mit Ping auf 10.10.10.2 und 10.10.10.3, je vier Pakete, 0 % Verlust, mittlere Umlaufzeit 0,134 ms und 0,141 ms

Kein Verlust, und Mittel von 0,134 ms und 0,141 ms. Beide Nachbarn sind einen direkten Sprung entfernt, und das ist, was ein Dreieck dir gibt.

Die Prüfung, die es wert ist und die kein Bildschirmfoto zeigen kann: zieh ein Kabel und stell fest, dass alles weiter erreichbar ist. Das ist der ganze Grund, ein geroutetes Mesh statt zweier Punkt-zu-Punkt-Verbindungen zu wählen. Damit ist es die einzige Prüfung, auf die es ankommt.

Über drei Knoten hinaus: der Ring

Ein Dreieck ist ein Full Mesh. Jeder Knoten hat ein direktes Kabel zu jedem anderen, jeder Sprung ist ein Sprung, und kein Knoten trägt je Verkehr, der nicht sein eigener ist.

Diese Eigenschaft kaufen dir zwei Mesh-Ports pro Knoten bei drei Knoten, und genau die verlierst du bei vier. Nicht einen Teil davon. Alles. Ein Full Mesh aus vier Knoten braucht drei Ports pro Knoten. Mit zwei ist das Meiste, was du verkabeln kannst, ein Ring.

Ein Ring ändert das Verkehrsmodell. Nachbarknoten haben weiter ein direktes Kabel, aber Knoten auf gegenüberliegenden Seiten des Rings nicht — ihr Verkehr muss über einen Knoten dazwischen. Und dieser Knoten muss bereit sein, Pakete zwischen seinen zwei Mesh-Schnittstellen weiterzuleiten, und das tut Linux standardmäßig nicht. Der Kernel dokumentiert ip_forward als „Forward Packets between interfaces“ mit „Default: 0 (disabled)“ — also aus.

Ein Ring aus vier Knoten: gegenüberliegende Knoten haben kein Kabel, ein Knoten leitet also für sie weitermesh110.10.10.1mesh2leitet weitermesh310.10.10.3mesh410.10.10.4mesh1 → mesh3kein Kabel dazwischengeht also über mesh2Transitknotenleitet weiter zwischennic1 und nic2Full Mesh bei 4 Knoten6 Kabel, 3 Ports pro Knotenkein Transit, kein WeiterleitenRing: 4 Kabel, 2 Ports —und deshalb bist du hierZwei der sechs Knotenpaare haben kein direktes Kabel. Ihren Verkehr trägt ein Nachbar, dessenVerbindungen damit die Ceph-Replikation anderer Knoten zusätzlich zur eigenen tragen — derPreis, den das Dreieck nicht hat.
Zwischen mesh1 und mesh3 gibt es kein Kabel. Ihr Verkehr geht über mesh2 oder mesh4, und dieser Knoten leitet ihn nur weiter, weil das Weiterleiten auf den zwei Schnittstellen eingeschaltet ist, auf denen er ankommt.

Schalte es für die Mesh-Schnittstellen ein, und nur für die:

# /etc/sysctl.d/99-mesh-forwarding.conf
net.ipv4.conf.nic1.forwarding = 1
net.ipv4.conf.nic2.forwarding = 1
sysctl --system

Lies sie zurück, statt es anzunehmen:

sysctl net.ipv4.conf.nic1.forwarding net.ipv4.conf.nic2.forwarding

Die Einstellung pro Schnittstelle ist hier der richtige Umfang, und sie wirkt für sich. Das globale net.ipv4.ip_forward ist keine Voraussetzung. Die Entscheidung des Kernels über das Weiterleiten liest den Wert der empfangenden Schnittstelle:

#define IN_DEV_FORWARD(in_dev)   IN_DEV_CONF_GET((in_dev), FORWARDING)

IN_DEV_CONF_GET gibt die Einstellung dieses Geräts zurück, kein UND mit der globalen. Also leiten nic1 und nic2 Transitverkehr für das Fabric weiter, während nic0 und vmbr0 genau das bleiben, was sie sein sollen: Host-Schnittstellen, die nicht routen. Den globalen Schalter anzuwerfen würde jede Schnittstelle der Kiste zum Router machen, auch die, die zu deinem Büronetz zeigt. Das braucht dieser Entwurf nicht.

Eine Sache über den globalen IPv4-Schalter, obwohl du ihn nicht setzt: net.ipv4.ip_forward ist ein Massensetzer, und deshalb warnt die Kernel-Dokumentation, dass eine Änderung daran „resets all configuration parameters to their default state“ — alle Konfigurationsparameter auf ihren Vorgabezustand zurücksetzt. Wenn irgendetwas anderes auf dem Host ihn je schreibt, überschreibt es diese Werte pro Schnittstelle. Gut zu wissen, bevor du einen Nachmittag damit verbringst, warum der Transit aufgehört hat.

IPv6 ist die Ausnahme, und die einzige Stelle, an die der globale Schalter gehört. Die Kernel-Dokumentation sagt es direkt unter conf/all/forwarding:

Enable global IPv6 forwarding between all interfaces. IPv4 and IPv6 work differently here; the force_forwarding flag must be used to control which interfaces may forward packets.

Auf Deutsch: globales IPv6-Weiterleiten zwischen allen Schnittstellen einschalten; IPv4 und IPv6 arbeiten hier verschieden, und mit dem Flag force_forwarding wird gesteuert, welche Schnittstellen Pakete weiterleiten dürfen.

Es gibt also kein IPv6-Gegenstück zum sauberen Vorgehen pro Schnittstelle von oben. Trägt das Fabric IPv6, schaltest du das Weiterleiten global ein und begrenzt es dann mit force_forwarding, dokumentiert als „Enable forwarding on this interface only — regardless of the setting on conf/all/forwarding“, also Weiterleiten nur auf dieser Schnittstelle, unabhängig von der Einstellung unter conf/all/forwarding. Beachte, dass dasselbe Überschreiben umgekehrt gilt: conf.all.forwarding auf 0 zu setzen setzt force_forwarding auf jeder Schnittstelle zurück.

Der Aufbau oben lässt das IPv6-Präfix des Fabric leer, davon gilt hier also nichts — es zählt nur, wenn du eines hinzufügst.

Achte darauf, was das Weiterleiten nicht ändert: OpenFabric hat das /32 jedes Knotens schon verkündet und den Weg über den Ring schon ausgerechnet. Weiterleiten ist die fehlende Erlaubnis, nicht der fehlende Verstand. Die Routing-Tabelle war die ganze Zeit richtig. Der Kernel hat sich bloß geweigert, als Router zu handeln.

Was der Ring gegenüber dem Dreieck kostet:

  • Transitverkehr. Auf einem Ring aus vier Knoten überqueren die zwei diagonalen Paare einen Knoten dazwischen, ihr Verkehr verbraucht also die Bandbreite dieses Knotens zusätzlich zu seiner eigenen. Ceph merkt das zuerst, weil Replikation von allen zu allen läuft und nicht von Nachbar zu Nachbar.
  • Ein zusätzlicher Sprung Latenz auf diesen Wegen, obendrauf auf die üblichen Werte unter einer Millisekunde eines Entwurfs ohne Switch.
  • Weniger Luft für Ausfälle. Eine kaputte Verbindung macht aus einem Ring eine Kette: noch vollständig verbunden, aber mit längeren Wegen und mehr Transit. Ein zweiter Bruch teilt den Cluster. Ein Dreieck verträgt einen Bruch ganz ohne Transit.

Und es wird auf eine Weise schlimmer, die leichter zu zeichnen als zu beschreiben ist. Nimm einen fünften Knoten dazu, und die Hälfte aller Knotenpaare im Cluster hängt davon ab, dass jemand anderes weiterleitet:

Ein Ring aus fünf Knoten: die Hälfte der Knotenpaare hängt jetzt davon ab, dass jemand anderes weiterleitetmesh1mesh2mesh3mesh4mesh5Kabel — direkt, ein Sprungkein Kabel — ein Nachbar leitet weiterFünf Knoten, je zwei Ports10 Knotenpaare insgesamt5 haben ein direktes Kabel5 nicht, sie gehen über NachbarnJeder Knoten leitet jetzt Verkehrweiter, der nicht sein eigener ist.Stattdessen ein Full Mesh?10 Kabel und 4 Ports pro Knoten— zwei NICs mehr in jedem Server,und dort hört der Entwurf auf.Bei drei Knoten geht nichts über Transit. Bei vier zwei Paare. Bei fünf die Hälfte — und eineinziger Bruch verlängert jeden Weg.
Zehn Knotenpaare, fünf Kabel. Die gestrichelten Linien sind Paare ohne Kabel zwischen sich — jedes davon ist Ceph-Verkehr, der über die Verbindungen eines Dritten reitet. Das Full Mesh, das das vermeiden würde, will vier Ports pro Server.

Das ist die echte Decke dieses Entwurfs, und es ist nicht das Routing-Protokoll. OpenFabric kommt gut zurecht. Es ist, dass die Ports pro Knoten festliegen, und deshalb macht über drei Knoten hinaus jede neue Kiste mehr von deinem Verkehr zum Transit eines anderen.

Und die ehrliche Anmerkung, denn für einen Aufbau, der bis hierher nur über die Weboberfläche lief, zählt sie: ein sysctl ist keine Handlung in der Weboberfläche. Nach der Regel von oben ist das damit eine Voraussetzung, die genannt werden muss, und nicht etwas, das man still auf der Kommandozeile richtet — schreib es ins Runbook, denn der Nächste, der das SDN-Fenster öffnet, sieht ein gesundes Fabric und keinen Hinweis darauf, dass ein Ring von einer Datei in /etc/sysctl.d abhängt.

Rückbau

Der Rückbau ist der Aufbau in umgekehrter Richtung, in derselben Oberfläche: lösche die SDN-Objekte, die für das Mesh angelegt wurden, wende die Konfiguration an und stell fest, dass der Verwaltungszugang unberührt ist.

Dieser letzte Schritt ist der Grund, warum nic0 und der 2,5-Gbit-Switch da sind. Wenn das Zurückrollen des Mesh dich die Weboberfläche kosten könnte, war der Entwurf falsch, bevor du angefangen hast.

Bevor du anfängst

  • Der Verwaltungszugang ist wirklich unabhängig vom Mesh. Prüf es, nimm es nicht an.
  • Alle drei Knoten sind gesund, bevor irgendeine SDN-Änderung kommt.
  • Knotennamen, Schnittstellennamen und Verkabelung sind aufgeschrieben, denn wenn nic1 auf einem Host nic2 auf einem anderen ist, wird das ein schlechter Nachmittag.
  • Jumbo Frames sind auf beiden Mesh-Schnittstellen gesetzt, und die MTU rechnet den Overhead von VXLAN auf der Unterlage mit ein.
  • Der Mesh-Bereich ist reserviert und wird nirgends sonst genutzt.

Quellen

  • Proxmox VE — Software-Defined Network — die Dokumentation zu SDN Fabrics. Fabrics „provide automated routing between nodes in a cluster“, OpenFabric ist „based on IS-IS and optimized for the spine-leaf topology common in data centers“, jeder Knoten braucht eine eigene Router-ID, und „a dummy ’loopback’ interface with the router-id is automatically created“
  • Proxmox VE — Cluster Manager — das Netz für Corosync und redundante Links, hinter dem Entwurf mit zwei Wegen für die Mitgliedschaft
  • Proxmox VE — Deploy Hyper-Converged Ceph Cluster — die Netzerwartungen eines hyperkonvergenten Clusters
  • Linux-Kernel — IP sysctl documentation — ip_forward und seine Vorgabe 0, die Steuerung forwarding pro Schnittstelle und die Warnung, dass eine Änderung am globalen Schalter die Konfiguration pro Schnittstelle zurücksetzt