Kubernetes - ServiceTopology

Merhaba,

Kubernetes üzerinde iki ana objenin genel topoloji ve trafik yönetimimizi nasıl değiştireceğine bir göz atacağız.Kubernetes’in 1.17.x minor versionlarından birini incelerken karşıma EndpointSlice objesi çıktı.

Normalde her bir pod icin Endpoint objeleri yaratılmakta ve servis objeleri tarafından takip(track) edilmektedir. Buradaki bütün bu yönlendirmeleri için gereken routing kuralları kube-proxy tarafından generate edilmektedir.

Kubernetes 1.17 ile beraber EndpointSlice objeleri her bir Endpoint için bize basitçe Endpoint objelerinin topoljideki yerini node ismi gibi birçok bilgiyi sağlamaktaydı.

Örnek bir EndpointSlice objesine bir bakalım;


addressType: IPv4
apiVersion: discovery.k8s.io/v1beta1
endpoints:
- addresses:
- 10.42.252.197
conditions:
ready: true
targetRef:
kind: Pod
name: backend-api-684f76dc76-ld6j5
namespace: default
topology:
kubernetes.io/hostname: 18.202.26.110
- addresses:
- 10.42.54.133
conditions:
ready: true
targetRef:
kind: Pod
name: backend-api-684f76dc76-lhk8w
namespace: default
topology:
kubernetes.io/hostname: 34.249.47.196

TopologyKey tanımı ile bizim cluster içerisindeki endpointlerimizi istediğimiz gibi sıralayabiliriz.

Buradaki anlatımı şimdilik bir kenara alalım Kubernetes servis tanımlarının ve genel networking yapısının nasil işlediğine bir bakalım.

KubeProxy ve Kubernetes Trafik Yonetimi

Her bir konteynır IP adresi kube-proxy tarafindan varsayılan olarak routing tablolari icerisinde virtual-interface baglaminda iptable kurallarina eklenir.

Herhangi bir node üzerinde iptables-save çıktısında anda size bu generate edilmiş DNAT, SNAT kurallarının tamamını görebilirsiniz.

kubeproxy basic application flow

Buradaki bütün durumu K8s Api içerisindeki Endpoint ve Service objlerinden gelmektedir.Bu yüzden kube-proxy sahibi olduğu ServiceAccount objesinde endpoints ve service objelerine WATCH yetkisi verilmektedir.

Her bir pod ayni zamanda birbirleri arasinda farklı nodelarda olsalar dahi iletişim kurabilecek şekilde tasarlanmıştır örnek vermek gerekirse;

10.42.54.128/26 via 172.31.11.157 dev tunl0 proto bird onlink
10.42.160.192/26 via 172.31.3.146 dev tunl0 proto bird onlink
10.42.174.192/26 via 172.31.6.198 dev tunl0 proto bird onlink

Baska CIDR bloklara ait bir poda ulaşmak istenirse direkt olarak ait oldukları node’a yönlendireleceği yönünde iptable kuralları ile ile beraber routing tablosunda da bu iletişimini bulabilirsiniz.

Ancak;

ve okun yonunu Y eksenin kaydıralım. Görüldüğü üzere aşağıdaki aslında farklı bir node uzerine konumlanmış poda giden gercek bir yol. Farklı bir node a gitmek demek fiziksel networ üzerinde bir yere dokunmak anlamına gelmektedir.

Bu durumda basit olan bir yesil ok yaklasim olarak fiziksel networku bizim icin soyutlamaktadir.

Fiziksel network uzerine cikmak bir ekstra network hop, latency ve maliyeti beraberinde getirmektedir. Özellikle latency kabul edilebilir bir seviyede olduktan sonra compute-zone’u yataya esnekmekte zaten bir mani yoktur.

Ancak dikine büyümesi gereken bir mimaride Kubernetes maalesef ilk bakışta yetersiz kalabiliyor bunu cozebilmek icinde sizin trafiğinizi belli topoloji keylere gore yonetebilmek adina ServiceTopoloy adinda bir feature ile karsimiza cikmaktadir.

ServiceTopology

Kubernetes iptable kurallariyle baslangicta yonettigi trafik ile bunu baslangic ta yonetmeniz zor cunku routing bicimi RANDOM olarak tanimlanmis durumda.

Simdi gelin nasil trafik routing islemini topology keylere gore yonetebiliriz ona bir goz atalim.

Service Object:

apiVersion: v1
kind: Service
metadata:
name: swansea-city-api
spec:
selector:
run: swansea-city-api
ports:
- protocol: TCP
port: 80
targetPort: 5000

Normal bir servis objesine bu tanimlamaya yaptigimiz zaman K8S bizim icin iptable chainler yaratacak.

Her bir podun targetPortuna yapilan ornek yonlendirme bu sekildedir ve her node bu kurallari kendi icerisinde barindirmaktadir.

-A KUBE-SEP-J5INMQGMDOEPBX6T -p tcp -m tcp -j DNAT --to-destination 10.42.54.133:5000-A KUBE-SEP-K4E4PJN2BTDAZ5MF -s 10.42.174.197/32 -j KUBE-MARK-MASQ-A KUBE-SEP-K4E4PJN2BTDAZ5MF -p tcp -m tcp -j DNAT --to-destination 10.42.174.197:5000

Ilgili iptable kurallarinda kubectl get po -o wide icerisinde POD iplerini goreceksiniz.

Burada yukaridaki ihtiyaciniza gore ozellestirme yapmak istediginizde ilgili podlarla ilgili iptable kurallarini sileceksiniz ki override olabilir ya da serviceTopologyKey’leri kullanacaksiniz.

apiVersion: v1
kind: Service
metadata:
name: swansea-city-api
spec:
selector:
run: swansea-city-api
ports:
- protocol: TCP
port: 80
targetPort: 5000
topologyKeys:
- "kubernetes.io/hostname"

Artik service objelerine ve endpointSlice’daki `kubernetes.io/hostname` taglerine bakarak podun bulunmus oldugu node ile ayni hostname’e sahip podlara servisi yonlendir demektesiniz.

Buradaki donup iptable kurallarina bakacak olursaniz.Podlar sadece kendi nodelarindaki `run: swansea-city-api` labellarindaki podlara trafik yonlendirmesi yapmaktadirlar ve iptable kurallarinda bazi kurallarin silindigini gorebilrisiniz .

node-2 uzerinden alinmis IPTABLE kurallari

node-2 node uzerinde topology key enable edilmeden once aldigim IPTABLE kurallari solda sag kisimda ise enable ettikten sonra vermis oldugum kurallarin karsilastirilmasi.

Nodelarda benim topology keyimde olmayan butun podlarin DNAT kurallarinin gittgini goruyorum

swansea-city-api-684f76dc76-2qxm7 10.42.252.198   node-2
swansea-city-api-684f76dc76-j5nmb 10.42.174.198 node-3
swansea-city-api-684f76dc76-ld6j5 10.42.252.197 node-2
swansea-city-api-684f76dc76-lhk8w 10.42.54.133 node-3
swansea-city-api-684f76dc76-mw87c 10.42.174.197 node-4

Komut ciktisida podlarin IP’lerinin node-2'den ayrildigini gostermektedir.

ServiceTopoloy Alpha, EndpointSlice ise beta konumdadir.Bu ozellikleri apiserver, controller-manager, kube-proxy ve kubelet’te FeatureGates uzerinden aktif etmeniz gerekmektedir.

Sonuc:

Bu ozellikte isinize yarayacagini umdugum bir ozellik umarim faydali olmusumdur.

--feature-gates="ServiceTopology=true,EndpointSlice=true"

Kaynakca

PythonRubyLinux(❤)