
Niet zo lang geleden kwam ik voor een vrij ongebruikelijke taak te staan bij het configureren van routing voor MetalLB. Normaal gesproken zijn er geen extra acties voor MetalLB nodig, maar in ons geval hebben we een behoorlijk grote cluster met een vrij eenvoudige netwerkconfiguratie.
In dit artikel zal ik uitleggen hoe je source-based en policy-based routing voor het externe netwerk van je cluster kunt instellen.
Ik zal niet in detail ingaan op de installatie en configuratie van MetalLB, omdat ik ervan uitga dat je al enige ervaring hebt. Laten we meteen aan de slag gaan met de configuratie van de routing. We hebben vier cases:
Case 1: Wanneer geen configuratie nodig is
Laten we een eenvoudige case doornemen.

Extra routingconfiguratie is niet nodig wanneer de door MetalLB toegewezen adressen zich in hetzelfde subnet bevinden als de adressen van je nodes.
Bijvoorbeeld, je hebt een subnet 192.168.1.0/24, daarin is een router 192.168.1.1, en je nodes krijgen adressen: 192.168.1.10-30, dan kun je voor MetalLB het bereik instellen 192.168.1.100-120 en er zeker van zijn dat ze zonder enige extra configuratie zullen werken.
Waarom is dat zo? Omdat je nodes al routes hebben ingesteld:
# 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.10En adressen uit hetzelfde bereik zullen hun routes hergebruiken zonder enige extra moeite.
Case 2: Wanneer extra configuratie nodig is

Je moet extra routes instellen telkens wanneer je nodes geen ingesteld hebben IP-adressen of geen route naar het subnet waarvoor MetalLB adressen toewijst.
Ik zal het iets uitgebreider uitleggen. Telkens wanneer MetalLB een adres toewijst, kun je dit vergelijken met een eenvoudige toewijzing zoals:
ip addr add 10.9.8.7/32 dev loLet op:
- a) Het adres wordt toegewezen met een prefix
/32dat wil zeggen dat er automatisch geen route naar het subnet voor wordt toegevoegd (dit is gewoon een adres) - b) Het adres wordt aan elke interface van de node toegewezen (bijvoorbeeld loopback). Hier moet ik het hebben over de eigenaardigheden van de netwerkstack van Linux. Het maakt niet uit op welke interface je het adres toevoegt; de kernel zal altijd arp-verzoeken verwerken en arp-antwoorden naar elke interface sturen, dit gedrag wordt als correct beschouwd en is bovendien vrij algemeen gebruikt in een dynamische omgeving zoals Kubernetes. Dit gedrag kan worden geconfigureerd, bijvoorbeeld door strict arp in te schakelen:
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announceIn dit geval worden arp-antwoorden alleen verstuurd als de interface expliciet een specifiek IP-adres bevat. Deze instelling is verplicht als je van plan bent MetalLB te gebruiken en je kube-proxy draait in IPVS-modus.
Desondanks gebruikt MetalLB de kernel niet voor het verwerken van arp-verzoeken, maar doet dit zelf in de user-space, waardoor deze optie geen invloed heeft op de werking van MetalLB.
Laten we terugkomen op onze taak. Als er geen route is voor de uitgedeelde adressen op je knooppunten, voeg deze dan vooraf toe aan alle knooppunten:
ip route add 10.9.8.0/24 dev eth1Case 3: Wanneer source-based routing nodig is
Source-based routing moet worden ingesteld wanneer je pakketten ontvangt via een aparte gateway, niet de standaard gateway die je hebt ingesteld, en dus moeten ook de antwoordpakketten via dezezelfde gateway worden verstuurd.
Bijvoorbeeld, je hebt hetzelfde subnet 192.168.1.0/24 toegewezen aan je knooppunten, maar je wilt externe adressen via MetalLB uitgeven. Stel dat je meerdere adressen uit het subnet 1.2.3.0/24 hebt die zich in VLAN 100 bevinden, en je wilt deze gebruiken voor toegang tot Kubernetes-diensten van buitenaf.

Bij een verzoek naar 1.2.3.4 doe je aanvragen vanuit een ander subnet dan 1.2.3.0/24 en verwacht je een reactie. Het knooppunt dat momenteel de master is voor het uitgegeven MetalLB-adres 1.2.3.4, ontvangt een pakket van de router 1.2.3.1, maar de reactie moet per se via dezelfde route, door 1.2.3.1.
gaan. Aangezien ons knooppunt al een standaard gateway heeft ingesteld 192.168.1.1, gaat de reactie standaard naar hem toe en niet naar 1.2.3.1, via welke we het pakket hebben ontvangen.
Hoe gaan we met deze situatie om?
In dit geval moet je al je knooppunten zo voorbereiden dat ze in staat zijn om externe adressen te bedienen zonder extra configuratie. Dit betekent dat je voor het bovenstaande voorbeeld vooraf een VLAN-interface op het knooppunt moet maken:
ip link add link eth0 name eth0.100 type vlan id 100
ip link set eth0.100 upEn voeg vervolgens de routes toe:
ip route add 1.2.3.0/24 dev eth0.100 table 100
ip route add default via 1.2.3.1 table 100Let op dat we de routes toevoegen in een aparte routeringstabel 100 deze zal alleen de twee routes bevatten die nodig zijn om het antwoordpakket via de gateway te versturen 1.2.3.1, die zich achter de interface bevindt eth0.100.
Nu moeten we een eenvoudige regel toevoegen:
ip rule add from 1.2.3.0/24 lookup 100die expliciet zegt: als het bronadres van het pakket zich bevindt in 1.2.3.0/24, gebruik dan de routeringstabel. 100. We hebben al een route beschreven die het zal verzenden via 1.2.3.1
Geval 4: Wanneer policy-based routing nodig is
Netwerk topologie zoals in het vorige voorbeeld, maar stel dat je ook de mogelijkheid wilt hebben om externe adressen van de pool aan te spreken 1.2.3.0/24 vanuit jouw pods:

Het kenmerk is dat wanneer je een adres aanspreekt in 1.2.3.0/24, het antwoordpakket dat binnenkomt op de node en het bronadres in het bereik heeft 1.2.3.0/24 voortvarend zal worden verzonden naar eth0.100, maar we willen dat Kubernetes het omleidt naar onze eerste pod, die het oorspronkelijke verzoek heeft gegenereerd.
Deze uitdaging bleek niet eenvoudig te zijn, maar het werd mogelijk dankzij policy-based routing:
Voor een beter begrip van het proces geef ik een blokschema van netfilter:

Laten we, net als in het vorige voorbeeld, een extra routeringtabel creƫren:
ip route add 1.2.3.0/24 dev eth0.100 table 100
ip route add default via 1.2.3.1 table 100Voeg nu een paar regels toe in iptables:
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-markDeze regels zullen de inkomende verbindingen op de interface markeren eth0.100, waarbij alle pakketten worden gemarkeerd met het label 0x100, hetzelfde label zal ook worden toegepast op de antwoorden binnen dezelfde verbinding.
Nu kunnen we een routeringsregel toevoegen:
ip rule add from 1.2.3.0/24 fwmark 0x100 lookup 100Dat betekent dat alle pakketten met het bronadres 1.2.3.0/24 en het label 0x100 gemarkeerd moeten worden volgens de tabel 100.
Op deze manier zullen andere pakketten die op een andere interface zijn ontvangen, niet onder deze regel vallen, wat hen in staat stelt om met de standaardmethoden van Kubernetes te worden gerouteerd.
Er is echter nog een probleem, in Linux bestaat er een zogenaamde reverse path filter die het hele proces verstoort door een eenvoudige controle uit te voeren: voor alle binnenkomende pakketten wijzigt hij het bronadres van het pakket met het adres van de afzender en controleert hij of het pakket via dezelfde interface kan worden verzonden als de interface waarlangs het werd ontvangen, zo niet, dan wordt het gefilterd.
Het probleem is dat het in ons geval niet correct zal functioneren, maar we kunnen het uitschakelen:
echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/eth0.100/rp_filterLet op, het eerste commando controleert het globale gedrag van rp_filter; als het niet wordt uitgeschakeld, heeft het tweede commando geen effect. Desalniettemin blijven de andere interfaces met ingeschakeld rp_filter.
Om de werking van de filter niet volledig te beperken, kunnen we gebruikmaken van de implementatie van rp_filter voor netfilter. Door rpfilter als een iptables-module te gebruiken, kunnen we vrij flexibele regels instellen, bijvoorbeeld:
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 DROPrp_filter inschakelen op de interface eth0.100 voor alle adressen behalve 1.2.3.0/24.
Bron: habr.com
