Feinabstimmung der Routing-Konfiguration für MetalLB im L2-Modus

Feinabstimmung der Routing-Konfiguration für MetalLB im L2-Modus
Vor nicht allzu langer Zeit stand ich vor einer ziemlich ungewöhnlichen Herausforderung bei der Konfiguration des Routings für MetalLB. Das wäre normalerweise kein Problem, da für MetalLB in der Regel keine zusätzlichen Maßnahmen erforderlich sind, aber in unserem Fall gibt es einen relativ großen Cluster mit einer recht einfachen Netzwerkkonfiguration.

In diesem Artikel werde ich erläutern, wie man source-basiertes und policy-basiertes Routing für das externe Netzwerk Ihres Clusters einrichtet.

Ich werde nicht ausführlich auf die Installation und Konfiguration von MetalLB eingehen, da ich davon ausgehe, dass Sie bereits über einige Erfahrungen verfügen. Lassen Sie uns einfach zur Sache kommen, nämlich zur Einrichtung des Routings. Wir haben also vier Fälle:

Fall 1: Wenn keine Konfiguration erforderlich ist

Lassen Sie uns einen einfachen Fall durchgehen.

Feinabstimmung der Routing-Konfiguration für MetalLB im L2-Modus

Zusätzliche Routingkonfiguration ist nicht erforderlich, wenn die von MetalLB vergebenen Adressen im gleichen Subnetz liegen wie die Adressen Ihrer Knoten.

Angenommen, Sie haben ein Subnetz 192.168.1.0/24, in dem ein Router existiert 192.168.1.1, und Ihre Knoten erhalten Adressen: 192.168.1.10-30, dann können Sie für MetalLB den Bereich 192.168.1.100-120 einrichten und sicher sein, dass sie ohne zusätzliche Konfiguration funktionieren werden.

Warum ist das so? Weil Ihre Knoten bereits konfigurierte Routen haben:

# ip route
default via 192.168.1.1 dev eth0 onlink 
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.10

Und Adressen aus demselben Bereich werden sie ohne zusätzliche Maßnahmen wiederverwenden.

Fall 2: Wenn zusätzliche Konfiguration erforderlich ist

Feinabstimmung der Routing-Konfiguration für MetalLB im L2-Modus

Sie sollten zusätzliche Routen einrichten, wenn Ihre Knoten keine konfigurierten IP-Adressen oder Routen zum Subnetz haben, für das MetalLB Adressen vergibt.

Ich werde das etwas ausführlicher erklären. Jedes Mal, wenn MetalLB eine Adresse vergibt, kann man dies mit einer einfachen Zuweisung vergleichen:

ip addr add 10.9.8.7/32 dev lo

Bitte beachten Sie:

  • a) Die Adresse wird mit einem Präfix zugewiesen, /32 das heißt, eine Route zum Subnetz wird automatisch nicht hinzugefügt (es ist einfach nur eine Adresse).
  • b) Die Adresse wird auf jedes Interface des Knotens angewendet (zum Beispiel Loopback). Hier sollte man die Besonderheit des Linux-Netzwerkstacks erwähnen. Es ist egal, auf welches Interface Sie die Adresse hinzufügen, der Kernel wird immer ARP-Anfragen verarbeiten und ARP-Antworten an eines von ihnen senden, dieses Verhalten wird als korrekt angesehen und ist zudem in einer dynamischen Umgebung wie Kubernetes sehr verbreitet.

Dieses Verhalten kann konfiguriert werden, indem man zum Beispiel strict arp aktiviert:

echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce

In diesem Fall werden ARP-Antworten nur gesendet, wenn das Interface ausdrücklich eine bestimmte IP-Adresse enthält. Diese Einstellung ist erforderlich, wenn Sie MetalLB nutzen möchten und Ihr kube-proxy im IPVS-Modus läuft.

MetalLB verwendet jedoch nicht den Kernel zur Verarbeitung von ARP-Anfragen, sondern erledigt dies selbst im User-Space. Daher hat diese Option keinen Einfluss auf die Funktionsweise von MetalLB.

Kommen wir zu unserer Aufgabe zurück. Wenn es keine Route für die ausgegebenen Adressen auf Ihren Knoten gibt, fügen Sie diese vorher auf allen Knoten hinzu:

ip route add 10.9.8.0/24 dev eth1

Fall 3: Wenn Source-based Routing benötigt wird

Source-based Routing müssen Sie einrichten, wenn Sie Pakete über ein separates Gateway empfangen, das nicht das ist, das bei Ihnen standardmäßig eingerichtet ist. Dementsprechend sollten auch die Antwortpakete über dieses Gateway gesendet werden.

Zum Beispiel haben Sie dasselbe Subnetz 192.168.1.0/24 für Ihre Knoten reserviert, aber Sie möchten externe Adressen über MetalLB bereitstellen. Angenommen, Sie haben mehrere Adressen aus dem Subnetz 1.2.3.0/24 in VLAN 100 und möchten diese nutzen, um auf Kubernetes-Dienste von außen zuzugreifen.

Feinabstimmung der Routing-Konfiguration für MetalLB im L2-Modus

Bei Anfragen an 1.2.3.4 werden Sie Anfragen aus einem anderen Subnetz stellen als 1.2.3.0/24 und auf eine Antwort warten. Der Knoten, der derzeit der Master für die ausgegebene MetalLB-Adresse ist, 1.2.3.4erhält das Paket vom Router 1.2.3.1, aber die Antwort muss über denselben Weg gehen, über 1.2.3.1.

Da unser Knoten bereits ein standardmäßiges Gateway konfiguriert hat, wird die Antwort standardmäßig dorthin gesendet, nicht über 192.168.1.1, durch das wir das Paket erhalten haben. 1.2.3.1Wie gehen wir mit dieser Situation um?

In diesem Fall müssen Sie alle Ihre Knoten so vorbereiten, dass sie externe Adressen ohne zusätzliche Konfiguration bedienen können. Das heißt, für das obige Beispiel müssen Sie vorher ein VLAN-Interface auf dem Knoten erstellen:

ip link add link eth0 name eth0.100 type vlan id 100 ip link set eth0.100 up

Und dann Routen hinzufügen:

ip route add 1.2.3.0/24 dev eth0.100 table 100 ip route add default via 1.2.3.1 table 100

Beachten Sie, dass wir die Routen in eine separate Routing-Tabelle hinzufügen.

Diese wird nur zwei Routen enthalten, die notwendig sind, um das Antwortpaket über das Gateway zu senden, 100 das sich hinter dem Interface 1.2.3.1eth0.100 Jetzt müssen wir eine einfache Regel hinzufügen:.

ip rule add from 1.2.3.0/24 lookup 100

die ausdrücklich sagt: Wenn die Quelladresse des Pakets in

liegt, verwenden Sie die Routing-Tabelle. 1.2.3.0/24, dann muss die Routingtabelle verwendet werden 100. In diesem Dokument haben wir bereits die Route beschrieben, die ihn durch 1.2.3.1

Fall 4: Wenn policy-basiertes Routing benötigt wird

Die Netzwerktopologie ist wie im vorherigen Beispiel, aber nehmen wir an, Sie möchten auch die Möglichkeit haben, auf externe Adressen des Pools zuzugreifen 1.2.3.0/24 von Ihren Pods:

Feinabstimmung der Routing-Konfiguration für MetalLB im L2-Modus

Das Besondere ist, dass beim Zugriff auf jede Adresse in 1.2.3.0/24, das Antwortpaket auf den Knoten gelangt und die Quelladresse im Bereich 1.2.3.0/24 wird brav an Jetzt müssen wir eine einfache Regel hinzufügen:, aber wir wollen, dass Kubernetes es an unseren ersten Pod weiterleitet, der die ursprüngliche Anfrage generiert hat.

Diese Problematik zu lösen, erwies sich als nicht einfach, aber es wurde durch policy-basiertes Routing möglich:

Um den Prozess besser zu verstehen, präsentiere ich das Blockschema von netfilter:
Feinabstimmung der Routing-Konfiguration für MetalLB im L2-Modus

Zunächst, wie im vorherigen Beispiel, erstellen wir eine zusätzliche Routing-Tabelle:

Beachten Sie, dass wir die Routen in eine separate Routing-Tabelle hinzufügen.

Jetzt fügen wir einige Regeln in iptables hinzu:

iptables -t mangle -A PREROUTING -i eth0.100 -j CONNMARK --set-mark 0x100
iptables -t mangle -A PREROUTING  -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -m mark ! --mark 0 -j RETURN
iptables -t mangle -A POSTROUTING -j CONNMARK --save-mark

Diese Regeln werden eingehende Verbindungen an der Schnittstelle markieren, Jetzt müssen wir eine einfache Regel hinzufügen:, indem sie alle Pakete mit dem Tag 0x100markieren; auch die Antworten im Rahmen derselben Verbindung werden mit diesem Tag versehen.

Jetzt können wir eine Routing-Regel hinzufügen:

ip rule add from 1.2.3.0/24 fwmark 0x100 lookup 100

Das heißt, alle Pakete mit der Quelladresse 1.2.3.0/24 und dem Tag 0x100 müssen unter Verwendung der Tabelle geroutet werden, 100.

so dass andere Pakete, die an einer anderen Schnittstelle empfangen werden, nicht unter diese Regel fallen, was es ihnen ermöglicht, mit den Standardmitteln von Kubernetes geroutet zu werden.

Es gibt jedoch ein weiteres Problem: In Linux gibt es den sogenannten Reverse Path Filter, der die gesamte Situation kompliziert und eine einfache Überprüfung durchführt: Für alle eingehenden Pakete ändert er die Quelladresse des Pakets auf die des Absenders und prüft, ob das Paket über dieselbe Schnittstelle, über die es empfangen wurde, gesendet werden kann. Wenn nicht, wird es herausgefiltert.

Das Problem dabei ist, dass er in unserem Fall nicht korrekt funktioniert, aber wir können ihn deaktivieren:

echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/eth0.100/rp_filter

Bitte beachten Sie, dass der erste Befehl das globale Verhalten des rp_filter steuert. Wenn er nicht deaktiviert wird, hat der zweite Befehl keine Wirkung. Dennoch bleiben die anderen Schnittstellen mit aktiviertem rp_filter.

Um die Funktion des Filters nicht vollständig einzuschränken, können wir die Implementierung von rp_filter für netfilter nutzen. Mit rpfilter als iptables-Modul können wir flexiblere Regeln festlegen, zum Beispiel:

iptables -t raw -A PREROUTING -i eth0.100 -d 1.2.3.0/24 -j RETURN
iptables -t raw -A PREROUTING -i eth0.100 -m rpfilter --invert -j DROP

rp_filter auf der Schnittstelle aktivieren Jetzt müssen wir eine einfache Regel hinzufügen: für alle Adressen außer 1.2.3.0/24.

Quelle: habr.com

60GB SSD 8Gb DDR4