Configurarea fină a rutării pentru MetalLB în modul L2

Configurarea fină a rutării pentru MetalLB în modul L2
Nu cu mult timp în urmă, m-am confruntat cu o sarcină destul de neobișnuită de configurare a rutării pentru MetalLB. Nimic neobișnuit până acum, deoarece în mod normal nu sunt necesare acțiuni suplimentare pentru MetalLB, dar în cazul nostru avem un cluster destul de mare cu o configurație de rețea destul de simplă.

În acest articol, voi descrie cum să configurați rutarea bazată pe sursă și rutarea bazată pe politici pentru rețeaua externă a clusterului dumneavoastră.

Nu voi intra în detalii despre instalarea și configurarea MetalLB, deoarece presupun că deja aveți o experiență anterioară. Propun să trecem direct la subiect, și anume la configurarea rutării. Așadar, avem patru cazuri:

Cazul 1: Când configurarea nu este necesară

Să analizăm un caz simplu.

Configurarea fină a rutării pentru MetalLB în modul L2

Configurarea suplimentară a rutării nu este necesară atunci când adresele emise de MetalLB se află în aceeași subrețea cu adresele nodurilor dumneavoastră.

De exemplu, aveți o subrețea 192.168.1.0/24, în care există un router 192.168.1.1, iar nodurile dumneavoastră primesc adrese: 192.168.1.10-30, atunci pentru MetalLB puteți să configurați intervalul 192.168.1.100-120 și să fiți sigur că acestea vor funcționa fără vreo configurare suplimentară.

De ce așa? Pentru că nodurile dumneavoastră au deja rutele configurate:

# 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

Și adresele din același interval vor fi reutilizate fără a necesita alte acțiuni suplimentare.

Cazul 2: Când este necesară o configurare suplimentară

Configurarea fină a rutării pentru MetalLB în modul L2

Trebuie să configurați rute suplimentare de fiecare dată când nodurile dumneavoastră nu au ruta configurată adrese IP sau ruta în subrețeaua pentru care MetalLB emite adrese.

Voi explica puțin mai în detaliu. De fiecare dată când MetalLB emite o adresă, aceasta poate fi comparată cu o simplă atribuție de tip:

ip addr add 10.9.8.7/32 dev lo

Observați, pe:

  • a) Adresa este atribuită cu un prefix /32 deci ruta în subrețea pentru aceasta nu va fi adăugată automat (aceasta este pur și simplu o adresă)
  • b) Adresa este atașată la orice interfață a nodului (de exemplu, loopback). Aici merită menționată o particularitate a stivei de rețea Linux. Nu contează pe ce interfață adăugați adresa, kernelul va procesa întotdeauna solicitările arp și va trimite răspunsurile arp pe oricare dintre acestea, acest comportament este considerat corect și, în plus, este destul de utilizat într-un mediu dinamic precum Kubernetes.

Acest comportament poate fi configurat, de exemplu, activând arp strict:

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

În acest caz, răspunsurile ARP vor fi trimise doar dacă interfața conține în mod explicit o adresă IP specifică. Această setare este obligatorie dacă intenționați să utilizați MetalLB și kube-proxy-ul dvs. funcționează în modul IPVS.

Cu toate acestea, MetalLB nu folosește nucleul pentru a procesa cererile ARP, ci o face singură în spațiul utilizatorului, astfel că această opțiune nu va afecta funcționarea MetalLB.

Să ne întoarcem la sarcina noastră. Dacă nu există o rută pentru adresele emise pe nodurile dvs., adăugați-o în prealabil pe toate nodurile:

ip route add 10.9.8.0/24 dev eth1

Cazul 3: Când este necesar routing-ul bazat pe sursă

Routing-ul bazat pe sursă trebuie să fie configurat atunci când primiți pachete printr-un gateway separat, diferit de cel configurat implicit, prin urmare pachetele de răspuns trebuie să părăsească de asemenea prin acest gateway.

De exemplu, aveți aceeași subrețea 192.168.1.0/24 dedicată nodurilor dvs., dar doriți să emiteți adrese externe folosind MetalLB. Să presupunem că aveți câteva adrese din subrețeaua 1.2.3.0/24 aflate în VLAN 100, și doriți să le utilizați pentru accesul la serviciile Kubernetes din exterior.

Configurarea fină a rutării pentru MetalLB în modul L2

Când accesați 1.2.3.4 veți face cereri dintr-o altă subrețea decât 1.2.3.0/24 și așteptați un răspuns. Nodul care este în prezent maestru pentru adresa MetalLB emisă 1.2.3.4, va primi pachetul de la router 1.2.3.1, dar răspunsul pentru acesta trebuie neapărat să plece prin aceeași rută, prin 1.2.3.1.

Deoarece nodul nostru are deja configurat un gateway implicit 192.168.1.1, prin urmare, răspunsul va merge implicit către acesta, nu către 1.2.3.1, prin care am primit pachetul.

Cum putem gestiona această situație?

În acest caz, este necesar să pregătiți toate nodurile astfel încât să fie capabile să gestioneze adrese externe fără configurări suplimentare. Cu alte cuvinte, pentru exemplul de mai sus, trebuie să creați în prealabil o interfață VLAN pe nod:

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

Apoi, adăugați rutele:

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

Rețineți că rutele sunt adăugate într-o tabelă de rutare separată 100 aceasta va conține doar două rute necesare pentru a trimite pachetul de răspuns prin gateway 1.2.3.1, care se află după interfața eth0.100.

Acum trebuie să adăugăm o regulă simplă:

ip rule add from 1.2.3.0/24 lookup 100

care spune în mod explicit: dacă adresa sursă a pachetului se află în 1.2.3.0/24, atunci trebuie folosit tabelul de rutare. 100. În aceasta avem deja descris traseul care îl va trimite prin 1.2.3.1

Caz 4: Când este necesară rutarea bazată pe politici

Topologia rețelei este ca în exemplul anterior, dar să presupunem că doriți de asemenea să aveți posibilitatea de a accesa adrese externe din pool-ul 1.2.3.0/24 din podurile dvs.:

Configurarea fină a rutării pentru MetalLB în modul L2

Particularitatea constă în faptul că, atunci când accesați orice adresă în 1.2.3.0/24, pachetul de răspuns ajungând pe nod și având adresa sursă în intervalul 1.2.3.0/24 va fi trimis cu docilitate în eth0.100, dar noi vrem ca Kubernetes să-l redirecționeze către primul nostru pod, care a generat inițial cererea.

Rezolvarea acestei probleme s-a dovedit a fi complicată, dar a devenit posibilă datorită ruterii bazate pe politici:

Pentru o mai bună înțelegere a procesului, voi prezenta un bloc schematic netfilter:
Configurarea fină a rutării pentru MetalLB în modul L2

Mai întâi, ca și în exemplul anterior, vom crea o tabelă suplimentară de rutare:

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

Acum vom adăuga câteva reguli în 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-mark

Aceste reguli vor marca conexiunile de intrare pe interfață eth0.100, marcând toate pachetele cu eticheta 0x100, aceeași etichetă va fi aplicată și răspunsurilor în cadrul aceleași conexiuni.

Acum putem adăuga o regulă de rutare:

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

Adică, toate pachetele cu adresa sursă 1.2.3.0/24 și eticheta 0x100 trebuie să fie rutate folosind tabela 100.

Astfel, alte pachete primite pe o altă interfață nu se încadrează în această regulă, ceea ce le va permite să fie rutate prin metode standard Kubernetes.

Există totuși o problemă: în Linux există așa-numitul filtru de cale inversă care strică totul, efectuează o simplă verificare: pentru toate pachetele de intrare, schimbă adresa sursă a pachetului cu adresa expeditorului și verifică dacă pachetul poate pleca prin aceeași interfață pe care a fost primit, dacă nu, îl filtrează.

Problema este că, în cazul nostru, acesta va funcționa incorect, dar îl putem dezactiva:

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

Rețineți, prima comandă controlează comportamentul global al rp_filter, dacă nu este dezactivat, a doua comandă nu va avea niciun efect. Cu toate acestea, celelalte interfețe vor rămâne cu rp_filter activat.

Pentru a nu restricționa complet funcționarea filtrului, putem utiliza implementarea rp_filter pentru netfilter. Folosind rpfilter ca modul iptables, putem configura reguli destul de flexibile, de exemplu:

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

activează rp_filter pe interfață eth0.100 pentru toate adresele, mai puțin 1.2.3.0/24.

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster