
Nedávno jsem se setkal s poněkud nestandardním úkolem nastavení routování pro MetalLB. Nic by to nebylo, protože obvykle pro MetalLB není potřeba žádných dalších akcí, ale v našem případě máme dost velký klastr s poměrně jednoduchou konfigurací sítě.
V tomto článku vám ukážu, jak nastavit routování na základě zdroje a zásady pro externí síť vašeho klastru.
Nebudu se detailně zabývat instalací a nastavením MetalLB, protože předpokládám, že již máte nějaké zkušenosti. Navrhuji přejít rovnou k věci, a to k nastavení routování. Máme čtyři případy:
Případ 1: Když nastavení není potřeba
Podíváme se na jednoduchý případ.

Další nastavení routování není potřeba, když adresy vydávané MetalLB jsou ve stejné podsíti jako adresy vašich uzlů.
Například máte podsíť 192.168.1.0/24, v níž je směrovač 192.168.1.1, a vaše uzly získávají adresy: 192.168.1.10-30, pak pro MetalLB můžete nastavit rozsah 192.168.1.100-120 a být si jisti, že budou fungovat bez jakéhokoli dalšího nastavení.
Proč tomu tak je? Protože vaše uzly již mají nastavené trasy:
# 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.10A adresy ze stejného rozsahu je budou znovu používat bez jakýchkoli dalších kroků.
Případ 2: Když je potřeba další nastavení

Měli byste nastavit další trasy vždy, když vaše uzly nemají nastaveno IP adres nebo trasu do podsítě, pro kterou MetalLB vydává adresy.
Vysvětlím to podrobněji. Kdykoli MetalLB vydá adresu, dá se to přirovnat k jednoduchému přiřazení typu:
ip addr add 10.9.8.7/32 dev loVšimněte si:
- a) Adresa je přiřazena s prefixem
/32to znamená, že do ní nebude automaticky přidán žádný routovací záznam (to je prostě adresa) - b) Adresa je nastavena na jakékoli rozhraní uzlu (například na loopback). Je třeba zmínit zvláštnosti síťového zásobníku Linuxu. Nezáleží na tom, na které rozhraní adresu přidáte, jádro vždy zpracovává arp dotazy a odesílá arp odpovědi na jakékoli z nich, toto chování je považováno za správné a navíc se v dynamickém prostředí, jakým je Kubernetes, používá dost široce.
Toto chování lze nastavit, například povolením strict arp:
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announceV tomto případě budou arp-odpovědi odesílány pouze v případě, že rozhraní výslovně obsahuje konkrétní IP adresu. Toto nastavení je povinné, pokud plánujete používat MetalLB a váš kube-proxy pracuje v režimu IPVS.
MetalLB však pro zpracování arp-dotazů nepoužívá jádro, ale dělá to samostatně v uživatelském prostoru, takže tato volba nebude mít vliv na práci MetalLB.
Vraťme se k našemu úkolu. Pokud neexistuje trasa pro přidělované adresy na vašich uzlech, přidejte ji předem na všechny uzly:
ip route add 10.9.8.0/24 dev eth1Případ 3: Kdy bude potřeba routování založené na zdroji
Routování založené na zdroji budete potřebovat nastavit tehdy, když přijímáte pakety přes samostatnou bránu, která není ta, která je nastavena jako výchozí, a podle toho musí odpovědní pakety také jít přes tuto bránu.
Například máte stále tu samou podsíť 192.168.1.0/24 vyčleněnou pro vaše uzly, ale chcete přidělovat externí adresy pomocí MetalLB. Předpokládejme, že máte několik adres z podsítě 1.2.3.0/24 umístěných ve VLAN 100 a chcete je používat pro přístup ke Kubernetes službám zvenčí.

Při přístupu na 1.2.3.4 budete provádět dotazy z jiné podsítě než 1.2.3.0/24 a očekávat odpověď. Uzlu, který je v tuto chvíli mistrem pro přidělenou adresu MetalLB 1.2.3.4, obdrží paket od směrovače 1.2.3.1, ale odpověď na něj musí nutně odejít stejnou cestou, přes 1.2.3.1.
Jelikož náš uzel již má nastavený default gateway 192.168.1.1, pak odpověď půjde výchozím směrem, tedy k němu, a ne k 1.2.3.1, přes který jsme obdrželi paket.
Jak se s touto situací vyrovnat?
V tomto případě je třeba připravit všechny vaše uzly tak, aby byly schopny obsluhovat externí adresy bez dalšího nastavení. To znamená, že pro výše uvedený příklad potřebujete předem vytvořit VLAN rozhraní na uzlu:
ip link add link eth0 name eth0.100 type vlan id 100
ip link set eth0.100 upA pak přidat trasy:
ip route add 1.2.3.0/24 dev eth0.100 table 100
ip route add default via 1.2.3.1 table 100Všimněte si, že trasy přidáváme do samostatné tabulky routování 100 bude obsahovat pouze dvě trasy potřebné pro odesílání odpovědního paketu přes bránu 1.2.3.1, která se nachází za rozhraním eth0.100.
Nyní je potřeba přidat jednoduché pravidlo:
ip rule add from 1.2.3.0/24 lookup 100které výslovně říká: pokud je zdrojová adresa paketu v 1.2.3.0/24, pak je třeba použít tabulku routování 100. V ní už máme popsánu trasu, která jej odešle přes 1.2.3.1
Příklad 4: Kdy bude potřeba směrování na základě politiky
Topologie sítě jako v předchozím příkladu, ale předpokládejme, že chcete mít také možnost přistupovat k externím adresám poolu 1.2.3.0/24 z vašich podů:

Specifikum spočívá v tom, že při přístupu k jakékoli adrese v 1.2.3.0/24, odpovědní paket, dostávající se na uzel a mající adresu zdroje v rozsahu 1.2.3.0/24 bude poslušně odeslán do eth0.100, ale my chceme, aby Kubernetes přesměroval jej do našeho prvního podu, který původně vytvořil dotaz.
Vyřešení této problémy se ukázalo být obtížné, ale stalo se to možné díky směrování na základě politiky:
Pro lepší porozumění procesu uvedu blokovou schéma netfilter:

Nejprve, jako v předchozím příkladu, vytvoříme další směrovací tabulku:
ip route add 1.2.3.0/24 dev eth0.100 table 100
ip route add default via 1.2.3.1 table 100Teď přidáme několik pravidel do 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-markTato pravidla budou označovat příchozí připojení na rozhraní eth0.100, označujíc všechny pakety tagem 0x100, tímto tagem budou označeny i odpovědi v rámci jednoho připojení.
Teď můžeme přidat směrovací pravidlo:
ip rule add from 1.2.3.0/24 fwmark 0x100 lookup 100To znamená, že všechny pakety se zdrojovou adresou 1.2.3.0/24 a tagem 0x100 by měly být směrovány pomocí tabulky 100.
Tímto způsobem jiné pakety, získané na jiném rozhraní, do tohoto pravidla nepatří, což jim umožní být směrovány standardními prostředky Kubernetes.
Existuje ještě jedno, ale, v Linuxu existuje takzvaný filtr zpětné cesty, který kazí celou legraci, provádí jednoduchou kontrolu: pro všechny příchozí pakety mění adresu zdroje paketu na adresu odesílatele a kontroluje, zda může paket projít stejným rozhraním, na které byl přijat, pokud ne, pak jej filtruje.
Problém je v tom, že v našem případě bude fungovat nesprávně, ale můžeme jej vypnout:
echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/eth0.100/rp_filterVšimněte si, že první příkaz ovládá globální chování rp_filter, pokud jej nevypnete, pak druhý příkaz nebude mít žádný efekt. Nicméně ostatní rozhraní zůstanou se zapnutým rp_filter.
Abychom neomezovali činnost filtru úplně, můžeme využít implementaci rp_filter pro netfilter. Použitím rp_filter jako modulu iptables můžeme nastavit dostatečně flexibilní pravidla, například:
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 DROPpovolí rp_filter na rozhraní eth0.100 pro všechny adresy kromě 1.2.3.0/24.
Zdroj: habr.com
