Síťařina v Kubernetes v Azure Container Service

V síťařině jsem působil mnoho let a vždycky to bylo docela složité. Virtualizace a cloud situaci díky nástupu overlay sítí a mikrosegmentaci zrovna nezjednodušují a dnes se pak musí řešit otázka síťařiny v kontejnerech běžících nad virtualizací. Azure Container Service odladila a připravila robustní řešení pro open source orchestrátor dle vaší volby - Docker Swarm, Kubernetes, DC/OS.

Dnes se společně podíváme na síťování v Kubernetes v Azure.

Koncept síťařiny v Kubernetes

IP per pod

Kubernetes přichází s konceptem podů, tedy shluků kontejnerů (ale velmi často lidé používají jediný kontejner v podu), které sdílejí IP adresu. Nicméně každý pod pak má adresu svou a s ostatními pody komunikuje napřímo a bez NAT místo sdílení IP adresy hostitele a pekla překládání portů (tak původně fungoval Mesos, interní Google Borg i Docker, ale v zásadě všichni zmínění začínají nabízet i koncept IP per kontejner).

Aby bylo možné toho dosáhnout existuje řada síťových řešení postavených na standardu CNI. Některé přidávají koncept overlay sítí (VXLAN) podobně, jako je tomu u DC/OS implementace. Zmínit můžeme Contiv, Weave, Flannel, Nuage nebo OVN. Jiné implementace využívají přímé L3 adresovatelnosti (tedy bez overlay) jako je případ Calico,  jistých nastavení Contiv apod.

Azure Container Service v tomto ohledu využívá přímou adresaci a směrování (tedy L3 řešení), takže na úrovni kontejnerů nejsou overlay sítě potřeba (samozřejmě samotný Azure na úrovni VM je používá, ale to je interní záležitost, kterou nemusíte ani znát - pro vás je to možnost vytvořit objekt VNet a v něm subnety, jak si to Azure zařídí, je vám jedno). Azure přidělí každému hostiteli (VM s Kubernetes) samostanou /24 síť:

Vlastní hostitelé mají /16 subnet, ale pro účely kontejnerů dostal každý hostitel jinou /24 síť a mezi nimi je zajištěno směrování.

Zkusme si nastartovat dva deploymenty (v našem testovacím případě s jedním podem, potažmo jedním kontejnerem) tak, aby se v nich reálně nic nedělo, ale zůstaly běžet.

kubectl run c1 --image busybox --command -- tail -f /dev/null
kubectl run c2 --image busybox --command -- tail -f /dev/null

Najdeme si jména podů.

# kubectl get pods
NAME                 READY     STATUS    RESTARTS   AGE
c1-240622296-djsx2   1/1       Running   0          <invalid>
c2-411540186-n3tbn   1/1       Running   0          <invalid>

Vevnitř kontejeru si vypíšeme adresu - všimněte si, že zapadá do /24 rozsahu svého hostitele.

# kubectl exec "c1-240622296-djsx2" -- ip a
...
3: eth0@if8: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 0a:58:0a:f4:03:05 brd ff:ff:ff:ff:ff:ff
    inet 10.244.3.5/24 scope global eth0
       valid_lft forever preferred_lft forever
...
# kubectl exec "c2-411540186-n3tbn" -- ip a
...
3: eth0@if8: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 0a:58:0a:f4:02:05 brd ff:ff:ff:ff:ff:ff
    inet 10.244.2.5/24 scope global eth0
       valid_lft forever preferred_lft forever
...

Můžeme si ověřit, že ping funguje - máme tedy přímo dosažitelnost mezi kontejnery.

# kubectl exec "c2-411540186-n3tbn" -- ping -c1 10.244.3.5
PING 10.244.3.5 (10.244.3.5): 56 data bytes
64 bytes from 10.244.3.5: seq=0 ttl=62 time=2.067 ms

--- 10.244.3.5 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 2.067/2.067/2.067 ms

Externí balancer aneb Kuberenes mluví s Azure Load Balancer

Jak je patrné z předchozího odstavce, pokud vypnete pod a pustíte ho na jiném hostiteli, nastartujte s jinou IP adresou. Pokud někdo chce na službu přistupovat, musel by se o změně IP dozvědět. Navíc co když chceme pody replikovat, tedy z výkonnostních důvodů jich provozovat několik a balancovat na ně? Kubernetes má koncept service, který našemu podu (nebo několika podům v rámci deploymentu) přiřadí neměnnou IP adresu, na kterou pak balancuje. Nicméně bude to mít jeden háček, podívejme se jaký.

Představme si, že na našem deploymentu c1 běží nějak služba a vytvořme si konstrukt service.

# kubectl get service
NAME         CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
c1           10.0.127.42   <none>        80/TCP    <invalid>
kubernetes   10.0.0.1      <none>        443/TCP   5h

Co se stalo? Kubernetes vytvořil virtuální IP aresu (CLUSTER-IP) a na portu 80 na ní poslouchá a provoz balancuje na všechny pody v deploymentu c1. Zajišťuje tedy load balancing a neměnnou IP pro naší službu.

Nicméně jak je patrné, adresa 10.0.127.42 není veřejná (nebo řekněme externí či reálná). Service je výborná pro balancing služeb využívaných uvnitř clusteru, ale nedostaneme se na ni z okolního světa (tedy od uživatelů). Koncept service je ale možné integrovat s externím load balancerem mimo cluster, tedy v infrastruktuře (typicky virtualizované IaaS), v které cluster běží. Tou je v našem případě Azure a Kubernetes dokáže žádat Azure Load Balancer o zajištění tohoto externího balancingu. Ukažme si jak to funguje.

Spustíme tři deploymenty jednoduché webové aplikace a každý ve třech replikách.

kubectl run web --image yeasy/simple-web --replicas 3
kubectl run web2 --image yeasy/simple-web --replicas 3
kubectl run web3 --image yeasy/simple-web --replicas 3

Teď tuto službu "vystrčíme" ven jako service, ale nejen interní v rámci clusteru, ale i jako zvenku dostupnou balancovanou service.

kubectl expose deployments web --port=80 --type=LoadBalancer
kubectl expose deployments web2 --port=80 --type=LoadBalancer
kubectl expose deployments web3 --port=80 --type=LoadBalancer

Nějakou dobu bude trvat, než si Kubernetes a Azure vymění potřebné informace, ale po pár minutách uvidíme na výpisu služeb něco takového:

# kubectl get service
NAME         CLUSTER-IP    EXTERNAL-IP     PORT(S)   AGE
c1           10.0.127.42   <none>          80/TCP    <invalid>
kubernetes   10.0.0.1      <none>          443/TCP   5h
web          10.0.103.19   13.95.8.111     80/TCP    <invalid>
web2         10.0.25.153   13.95.12.182    80/TCP    <invalid>
web3         10.0.15.37    52.174.188.30   80/TCP    <invalid>

Všimněte si externích IP adres. Podívejme se do Azure portálu. V zdrojích najdeme nový balancer a public IP zdroje.

IP adresy jsou front end v balanceru.

Směřují na IP adresy hostitelů.

Když se podíváme na balancovací pravidla a taky health sondy, zjistíme, že Kubernetes vybral pro každou naší službu jiný TCP port a Azure balancer automaticky nastavil tak, že z unikátní IP na portu, který jsme chtěli (v našem případě 80) balancuje na agenty na tento jiný TCP port.

 

Síťařina v Kubernetes je možná trochu komplikovaná, ale ne pokud používáte Azure Container Service. Nejen, že cluster sestavíte jednoduše a spolehlivě, ale máte perfektní integraci se sítí v Azure, takže napojit vaše uživatele na reálné balancované služby ve vašem clusteru je snadné.



Privátní napojení PaaS služeb do VNETu s Azure Private Link Networking
Kubernetes praticky: používání externí konfigurace v Azure App Configuration Service Kubernetes Kontejnery
Automatické získávání IP range PaaS služeb v Azure přes API Networking
Kubernetes praticky: vystavování aplikací s Ingress a Azure App Gateway (WAF) Kubernetes Kontejnery Networking
IPv6 v Azure Networking