Feinabstimmung des Routings für MetalLB im L2-Modus

Feinabstimmung des Routings für MetalLB im L2-Modus
Vor nicht allzu langer Zeit stand ich vor der sehr ungewöhnlichen Aufgabe, das Routing für MetalLB einzurichten. Alles wäre gut, denn... Normalerweise erfordert MetalLB keine zusätzlichen Aktionen, aber in unserem Fall haben wir einen ziemlich großen Cluster mit einer sehr einfachen Netzwerkkonfiguration.

In diesem Artikel erkläre ich Ihnen, wie Sie quellenbasiertes und richtlinienbasiertes Routing für das externe Netzwerk Ihres Clusters konfigurieren.

Ich werde nicht näher auf die Installation und Konfiguration von MetalLB eingehen, da ich davon ausgehe, dass Sie bereits über einige Erfahrung verfügen. Ich schlage vor, gleich zur Sache zu kommen, nämlich das Routing einzurichten. Wir haben also vier Fälle:

Fall 1: Wenn keine Konfiguration erforderlich ist

Schauen wir uns einen einfachen Fall an.

Feinabstimmung des Routings für MetalLB im L2-Modus

Eine zusätzliche Routing-Konfiguration ist nicht erforderlich, wenn die von MetalLB ausgegebenen Adressen im selben Subnetz liegen wie die Adressen Ihrer Knoten.

Sie haben beispielsweise ein Subnetz 192.168.1.0/24, es hat einen Router 192.168.1.1, und Ihre Knoten erhalten Adressen: 192.168.1.10-30, dann können Sie für MetalLB den Bereich anpassen 192.168.1.100-120 und stellen Sie sicher, dass sie ohne zusätzliche Konfiguration funktionieren.

Warum so? Da für Ihre Knoten bereits Routen konfiguriert sind:

# 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 Aktionen wiederverwenden.

Fall 2: Wenn zusätzliche Anpassungen erforderlich sind

Feinabstimmung des Routings für MetalLB im L2-Modus

Sie sollten zusätzliche Routen konfigurieren, wenn Ihre Knoten keine konfigurierte IP-Adresse oder Route zu dem Subnetz haben, für das MetalLB Adressen ausgibt.

Ich werde es etwas genauer erklären. Immer wenn MetalLB eine Adresse ausgibt, kann dies mit einer einfachen Zuweisung wie der folgenden verglichen werden:

ip addr add 10.9.8.7/32 dev lo

Beachten:

  • a) Die Adresse wird mit einem Präfix vergeben /32 das heißt, eine Route wird nicht automatisch zum Subnetz hinzugefügt (es ist nur eine Adresse)
  • b) Die Adresse wird an eine beliebige Knotenschnittstelle (z. B. Loopback) angehängt. Erwähnenswert sind hier die Features des Linux-Netzwerkstacks. Unabhängig davon, zu welcher Schnittstelle Sie die Adresse hinzufügen, verarbeitet der Kernel immer ARP-Anfragen und sendet ARP-Antworten an jede von ihnen. Dieses Verhalten gilt als korrekt und wird darüber hinaus in einer so dynamischen Umgebung wie Kubernetes recht häufig verwendet.

Dieses Verhalten kann angepasst werden, indem beispielsweise „strict arp“ aktiviert wird:

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 die Schnittstelle explizit eine bestimmte IP-Adresse enthält. Diese Einstellung ist erforderlich, wenn Sie MetalLB verwenden möchten und Ihr Kube-Proxy im IPVS-Modus ausgeführt wird.

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

Kehren wir zu unserer Aufgabe zurück. Wenn die Route für die ausgegebenen Adressen auf Ihren Knoten nicht vorhanden ist, fügen Sie sie vorab allen Knoten hinzu:

ip route add 10.9.8.0/24 dev eth1

Fall 3: Wenn Sie quellenbasiertes Routing benötigen

Sie müssen das quellenbasierte Routing konfigurieren, wenn Sie Pakete über ein separates Gateway empfangen, nicht über das standardmäßig konfigurierte. Daher sollten Antwortpakete auch über dasselbe Gateway laufen.

Beispielsweise haben Sie dasselbe Subnetz 192.168.1.0/24 dediziert für Ihre Knoten, Sie möchten jedoch externe Adressen mithilfe von MetalLB vergeben. Nehmen wir an, Sie haben mehrere Adressen aus einem Subnetz 1.2.3.0/24 sich im VLAN 100 befinden und Sie diese für den externen Zugriff auf Kubernetes-Dienste verwenden möchten.

Feinabstimmung des Routings für MetalLB im L2-Modus

Bei der Kontaktaufnahme 1.2.3.4 Sie werden Anfragen aus einem anderen Subnetz stellen als 1.2.3.0/24 und warte auf eine Antwort. Der Knoten, der derzeit der Master für die von MetalLB ausgegebene Adresse ist 1.2.3.4, empfängt das Paket vom Router 1.2.3.1, aber die Antwort für ihn muss notwendigerweise den gleichen Weg gehen, nämlich durch 1.2.3.1.

Da unser Knoten bereits über ein konfiguriertes Standard-Gateway verfügt 192.168.1.1, dann geht die Antwort standardmäßig an ihn und nicht an 1.2.3.1, über die wir das Paket erhalten haben.

Wie kann man mit dieser Situation umgehen?

In diesem Fall müssen Sie alle Ihre Knoten so vorbereiten, dass sie ohne zusätzliche Konfiguration bereit sind, externe Adressen zu bedienen. Das heißt, für das obige Beispiel müssen Sie im Voraus eine VLAN-Schnittstelle 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

Bitte beachten Sie, dass wir Routen zu einer separaten Routing-Tabelle hinzufügen 100 Es enthält nur zwei Routen, die zum Senden eines Antwortpakets über das Gateway erforderlich sind 1.2.3.1, befindet sich hinter der Schnittstelle eth0.100.

Jetzt müssen wir eine einfache Regel hinzufügen:

ip rule add from 1.2.3.0/24 lookup 100

was ausdrücklich besagt: wenn die Quelladresse des Pakets in ist 1.2.3.0/24, dann müssen Sie die Routing-Tabelle verwenden 100. Darin haben wir bereits die Route beschrieben, die ihn passieren wird 1.2.3.1

Fall 4: Wenn Sie richtlinienbasiertes Routing benötigen

Die Netzwerktopologie ist dieselbe wie im vorherigen Beispiel, aber nehmen wir an, Sie möchten auch auf externe Pooladressen zugreifen können 1.2.3.0/24 aus deinen Pods:

Feinabstimmung des Routings für MetalLB im L2-Modus

Die Besonderheit besteht darin, dass beim Zugriff auf eine beliebige Adresse in 1.2.3.0/24, das Antwortpaket erreicht den Knoten und hat eine Quelladresse im Bereich 1.2.3.0/24 wird gehorsam an geschickt eth0.100, aber wir möchten, dass Kubernetes es zu unserem ersten Pod umleitet, der die ursprüngliche Anfrage generiert hat.

Die Lösung dieses Problems erwies sich als schwierig, wurde aber dank richtlinienbasiertem Routing möglich:

Zum besseren Verständnis des Prozesses finden Sie hier ein Netfilter-Blockdiagramm:
Feinabstimmung des Routings für MetalLB im L2-Modus

Erstellen wir zunächst wie im vorherigen Beispiel eine zusätzliche Routing-Tabelle:

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

Fügen wir nun ein paar Regeln zu 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 markieren eingehende Verbindungen zur Schnittstelle eth0.100, markiert alle Pakete mit dem Tag 0x100, werden Antworten innerhalb derselben Verbindung ebenfalls mit demselben Tag markiert.

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 einer Quelladresse 1.2.3.0/24 und markieren 0x100 müssen über eine Tabelle geroutet werden 100.

Daher unterliegen andere Pakete, die auf einer anderen Schnittstelle empfangen werden, nicht dieser Regel, sodass sie mit Standard-Kubernetes-Tools weitergeleitet werden können.

Hinzu kommt noch etwas, in Linux gibt es einen sogenannten Reverse-Path-Filter, der das Ganze verdirbt; er führt eine einfache Prüfung durch: Bei allen eingehenden Paketen tauscht er die Quelladresse des Pakets mit der Absenderadresse aus und prüft, ob Das Paket kann über dieselbe Schnittstelle verlassen, über die es empfangen wurde. Andernfalls wird es herausgefiltert.

Das Problem ist, dass es in unserem Fall nicht richtig funktioniert, aber wir können es 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 von rp_filter steuert; wenn er nicht deaktiviert ist, hat der zweite Befehl keine Wirkung. Die übrigen Schnittstellen bleiben jedoch bei aktiviertem rp_filter bestehen.

Um den Betrieb des Filters nicht vollständig einzuschränken, können wir die rp_filter-Implementierung für netfilter verwenden. Mit rpfilter als iptables-Modul können Sie recht flexible Regeln konfigurieren, 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

Aktivieren Sie rp_filter auf der Schnittstelle eth0.100 für alle Adressen außer 1.2.3.0/24.

Source: habr.com

Kommentar hinzufügen