DevOps

Kako koristiti Affinity i Antiaffinity za raspodelu Podova u Kubernetesu

affinity i antaffinity

Kubernetes (K8s) planer često koristi jednostavna pravila zasnovana na dostupnosti resursa kako bi smestio podove na nodove (čvorove).
To je sasvim u redu za mnoge slučajeve i upotrebu uopšte. Međutim, ponekad možda možemo da idemo korak dalje od jednostavnog planiranja zasnovanog na resursima.

Na primer, šta ako želimo da rasporedimo podove na određene nodove?
Ili, recimo želimo da izbegnemo postavljanje određenih podova na iste nodove?

Znam, zvuči zamršeno.
Tu dolaze do izražaja dva koncepta u Kubernetesu – Affinity i AntiAffinty ( npr. afinitet i anti-afinitet) .
Ova dva koncepta su naredne tehnike planiranja u Kubernetesu koje nam mogu pomoći da kreiramo fleksibline takozvane politike planiranja.

Uopšteno govoreći, Affinity omogućava planeru Kubernetes-a da postavi pod na grupu nodova ili pod u odnosu na postavljanje drugih podova.
Da bismo kontrolisali postavljanje poda na grupu nodova, korisnik mora koristiti pravila afiniteta nodova.
Za razliku od toga, pravila afiniteta poda ili anti-afiniteta poda omogućavaju kontrolu postavljanja poda u odnosu na druge podove.

Dakle, da vidimo prvo detaljno šta su Affinity i AntiAffinity u Kubernetesu.

U Kubernetesu, Affinity i Antiaffinity su koncepti koji se koriste za upravljanje rasporedom aplikacija i resursa u klasteru.

  • Affinity se odnosi na preferenciju koju jedna aplikacija ili resurs ima prema drugoj aplikaciji ili resursu u smislu njihove lokacije u klasteru.
  • Na primer, ako imate dva mikroservisa koji često komuniciraju međusobno, možda ćete želeti da ih držite na istom fizičkom ili virtualnom serveru kako bi se smanjilo vreme prenosa podataka i povećala brzina odziva.
  • Affinity se takođe može koristiti za balansiranje opterećenja između čvorova u klasteru, ili za postavljanje aplikacija na određenim vrstama hardvera ili resursa.

S druge strane, Antiaffinity se odnosi na želju da se dva resursa drže razdvojeno i ne smeju biti smešteni zajedno na istom fizičkom ili virtualnom serveru.

  • Ovo se može koristiti, na primer, ako su dve aplikacije kritične za poslovanje i postoji rizik od istovremene greške ili prekida rada ako su smeštene zajedno na istom serveru.
  • Antiaffinity se takođe može koristiti za sprečavanje dva ista servisa ili aplikacije da se izvršavaju na istom čvoru u klasteru.

U Kubernetesu, Affinity i Antiaffinity se primenjuju pomoću etiketa (labels) i selektora (selectors), kojima se označavaju nodovi i resursi u klasteru.
Ovo omogućava Kubernetesu da upravlja rasporedom aplikacija i resursa na različitim nodovima u klasteru, u skladu sa definisanim Affinity i Antiaffinity pravilima.

Affinity i Antiaffinity su, dakle, ključni koncepti za upravljanje Kubernetes klasterom i omogućavaju bolju skalabilnost, performanse i otpornost na greške.

U ovom članku, kako biste brzo krenuli sa afinitetom Kubernetes-a, detaljno ćemo razmotriti napredne metode planiranja, duboko uroniti u različite vrste K8s afiniteta i pružiti demo afiniteta čvora kako biste mogli praktično da se bavite naprednim planiranjem Kubernetes-a.

Napredne tehnike planiranja podova u Kubernetes-u

Pre nego što se upustimo u Kubernetes afinitet, vratimo se korak unazad i pregledajmo različite prilagođene tehnike planiranja podova koje su nam dostupne.
U tabeli ispod možete videti pregled različitih naprednih metoda planiranja, uključujući Afinitet nodova i Anti-Afinitet poda.

KonceptOpis i značenje
Taints i TolerationsDozvoljavanje nodu da kontroliše koje će se podovi izvršavati na njemu i koje će biti odbijeni
NodeSelectorDodeljivanje Poda određenom nodu pomoću oznaka (Labels).
Node AffinitySlično NodeSelector-u, ali izražajnije i fleksibilnije kao što je dodavanje “Required” i “Preferred” pravila
Pod Affinity i Anti-AffinityZajedničko lociranje modula ili postavljanje modula dalje jedan od drugog na osnovu pravila o Affinity i Anti-Affinity

Sada ćemo da pogledamo bliže o čemu se radi ovde.

K8s Taints i Tolerations

Sa Taints-ima, nodovi imaju kontrolu nad postavljanjem podova.
Taints omogućavaju nodovima da definišu koji podovi mogu da se postave na njih, a koji su podovi odbijeni od njih.

Na primer, pretpostavimo da imamo node sa posebnom hardverskom opremom i želimo da planer (scheduler) raspoređuje samo podove koji zahtevaju tu posebnu hardversku opremu.
Možemo koristiti Toleracije za Taintove nodova da bismo ispunili ovaj zahtev.
Podovi koji zahtevaju posebnu hardversku opremu moraju definisati toleranciju za Taints na tim nodovima. Sa Tolerancijama, nodovi će omogućiti pokretanje podova na njima.

K8s NodeSelector

NodeSelector je najjednostavniji način za raspoređivanje podova na nodovima.
Radi tako što se definiše oznake za node, a zatim se veže pod za taj node odgovaranjem oznake u specifikaciji poda.
Ovo je jednostavan pristup koji funkcioniše u nekim slučajevima. Međutim, nije dovoljno fleksibilan za kompleksno planiranje podova.

Node Affinity

Pravila afiniteta noda koriste oznake na nodovima i selektore oznaka u fajlu specifikacije poda.
Nodovi nemaju kontrolu nad postavljanjem.
Ako planer postavi pod koristeći pravilo afiniteta noda i pravilo kasnije više nije važeće (npr. zbog promene oznaka), pod će i dalje raditi na tom nodu.
Postoji mnogo korisnih slučajeva za afinitet nodova, uključujući postavljanje poda na grupu nodova sa specifičnim CPU/GPU i postavljanje podova na nodove u određenoj dostupnoj zoni.

Primer zakazivanja Kubernetes poda korišćenjem afiniteta noda.

Postoje dva tipa pravila za Node afinitet :

  • Obavezno “Required”
  • Poželjno  “Preffered”

Dakle, Afinitet noda može biti obavezan ili poželjan.
Za postavljanje poda, pravilo afiniteta noda koje je obavezno, mora biti zadovoljeno, dok sa pravilom afiniteta koje je poželjno, planer će pokušati da pravilo primeni, ali ne garantuje primenu.

Pod Afinitet i Anti-Afinitet – omogućavaju kreiranje pravila koja kontrolišu gde će biti postavljeni podovi u odnosu na druge podove.

Korisnik mora označiti nodove i koristiti selektore oznaka u specifikaciji poda.

Pod Afinitet i Anti-Afinitet omogućavaju podu da specifikuje afinitet (ili anti-afinitet) prema skupu podova.

Kao i kod afiniteta noda, node nema kontrolu nad postavljanjem poda.
Pravila afiniteta funkcionišu na osnovu oznaka.

Pomoću pravila afiniteta, planer može postaviti pod na isti node kao i drugi podovi, ako se oznaka na novom podu podudara sa oznakom na drugom podu.

Primer raspoređivanja Kubernetes poda uz upotrebu Pod Affinity-a.

  • Anti-Afinitet pravilo govori planeru da ne raspoređuje novi pod na isti node ako oznaka na novom podu odgovara oznaci na drugom podu.
  • Takođe, omogućava vam da držite podove udaljene jedan od drugog.
  • Uvođenje Anti-affinity je korisno u slučajevima kao što su izbegavanje postavljanja poda koji će uticati na performanse postojećeg poda na istom nodu.

 

Affinity i Antiaffinity u Kubernetesu

Primer raspoređivanja Kubernetes podova korišćenjem Anti-Affinity pravila.

Kao i pravila Node Affinity-ja, pravila Pod Affinity-ja takođe imaju “Obavezni” i “Preferirani” režim rada.

U “Obaveznim” pravilima, pravilo mora biti ispunjeno da bi scheduler postavio pod.
U “Preferiranom” režimu, raspoređivanje zasnovano na pravilu nije garantovano.

Primer Node Affinity-a

Sada kada razumete Kubernetes afinitete, pređimo na naš demo Node Affinity-a.

U ovom primeru, proći ćemo korak po korak kroz instrukcije:

  • Hajde da objasnimo kako Node Affinity pravila funkcionišu označavanjem nekih nodova u klasteru
  • Zatim ćemo da napravimo deployment sa Node Affinity pravilom u pod specifikaciji
  • Na kraju ćemo da vidimo da su pod-ovi postavljeni na nodove sa datim oznakama.

Prvo da vidimo listu nodova u klasteru:

$ kubectl get nodes
NAME                STATUS   ROLES               AGE  VERSION
k8s-node-master-1   Ready    controlplane,etcd   3d   v1.15.12
k8s-node-master-2   Ready    controlplane,etcd   3d   v1.15.12
k8s-node-master-3   Ready    controlplane,etcd   3d   v1.15.12
k8s-node-worker-1   Ready    worker              3d   v1.15.12
k8s-node-worker-2   Ready    worker              3d   v1.15.12
k8s-node-worker-3   Ready    worker              3d   v1.15.12
k8s-node-worker-4   Ready    worker              3d   v1.15.12

Označite dva noda za Node Affinity primer tako da se podovi mogu postaviti na označene nodove prema pravilima privrženosti nodovima:

$ kubectl label node k8s-node-worker-3 app=frontend node/k8s-node-worker-3 labeled
                    
$ kubectl label node k8s-node-worker-4 app=frontend node/k8s-node-worker-4 labeled   

Zatim kreirajte namespace test za ovaj demo:

$ kubectl create ns test
namespace/test created  

Zatim kreirajte sledeći deployment fajl sa nodeАffinity u specifikaciji pod-a:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: node-affinity
  namespace: test
spec:
  replicas: 4
  selector:
    matchLabels:
      run: nginx
  template:
    metadata:
      labels:
        run: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: Always
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: app
                operator: In
                values:
                - frontend

Sada kreirajte deployment koristeći YAML datoteku:

$ kubectl create -f deployment-node-affinity.yml
deployment.apps/node-affinity created

Sledeći korak je da se proveri da li je deployment uspešno kreiran. Ovde vidimo komanu za deploy u namespace-u test.

$ kubectl get deploy -n test
 NAME            READY   UP-TO-DATE   AVAILABLE   AGE
 node-affinity   4/4     4            4           10s 

Zatim tražimo da vidimo sve podove izlistane.

$ kubectl get pods -n test
  NAME                             READY   STATUS    RESTARTS   AGE
  node-affinity-8fd8f3f23f-dng7b   1/1     Running   0          30s
  node-affinity-8fd8f3f23f-frsxz   1/1     Running   0          30s
  node-affinity-8fd8f3f23f-nn6jl   1/1     Running   0          30s
  node-affinity-8fd8f3f23f-wpc66   1/1     Running   0          30s   

Dalje, da bismo proverili da li je pravilo afiniteta za nodove funkcionisalo, otvaramo listu podova na nodovima i proveravamo da li su podovi smešteni na nodovima sa oznakom app=frontend, tj. worker3, worker4 u ovom slučaju:

$ kubectl get pod -o=custom-columns=NODE:.spec.nodeName,NAME:.metadata.name -n test
  NODE                NAME
  k8s-node-worker-4   node-affinity-8fd8f3f23f-dng7b
  k8s-node-worker-4   node-affinity-8fd8f3f23f-frsxz
  k8s-node-worker-3   node-affinity-8fd8f3f23f-nn6jl
  k8s-node-worker-3   node-affinity-8fd8f3f23f-wpc66   

Na kraju, očistite resurse demo primera:

$ kubectl delete ns test --cascade
  namespace "test" deleted 

Pod Affinity i Anti-Affinity

Sada ćemo da pretpostavimo da imamo Redis keš za web aplikacije i potrebno je pokrenuti tri replike Redis-a, ali je potrebno da se svaka replika pokreće na drugom čvoru.

Koristi se anti-affinity pravilo u ovom slučaju.

Deployment Redis-a sa pravilom pod anti-affinity, tako da svaka replika završi na drugom čvoru:

cat redis.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-cache
  namespace: test
spec:
  selector:
    matchLabels:
      app: store
  replicas: 3
  template:
    metadata:
      labels:
        app: store
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - store
            topologyKey: "kubernetes.io/hostname"
      containers:
      - name: redis-server
        image: redis:3.2-alpine

Kreirajte deployment koristeći yaml fajl iznad:

kubectl create -f redis.yaml deployment.apps/redis-cache created

Proverite da li je deployment pokrenut.

$ kubectl -n test get deploy

NAME          READY   UP-TO-DATE   AVAILABLE   AGE
redis-cache   3/3     3            3           11s  

Proverite da li svaki pod radi na različitom čvoru:

$ kubectl get pod -o=custom-columns=NODE:.spec.nodeName,NAME:.metadata.name -n test

 NODE               NAME
k8s-node-worker-3   redis-cache-58786cc745-yzxtr
k8s-node-worker-1   redis-cache-58786cc745-bmkpc
k8s-node-worker-2   redis-cache-58786cc745-lehut

Dakle, ovde vidimo da se svaki pod pokreće na drugom nodu.

Idemo dalje, sada pretpostavimo da imamo pokrenut veb server i da moramo da se uverimo da se svaki modul veb servera nalazi zajedno sa svakim Redis keš modulom, ali u isto vreme, moramo da se uverimo da dva modula veb servera ne rade na istom nodu, da bi se ovo desilo koristimo pod affinity i pod anti-affinity kao što je prikazano u nastavku.

Kreirajte datoteku za implementaciju sa pravilima pod affinity i pod anti-affinity:

cat web-server.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-server
  namespace: test
spec:
  selector:
    matchLabels:
      app: web-store
  replicas: 3
  template:
    metadata:
      labels:
        app: web-store
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - web-store
            topologyKey: "kubernetes.io/hostname"
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - store
            topologyKey: "kubernetes.io/hostname"
      containers:
      - name: web-app
        image: nginx:1.12-alpine

Ovde pravimo deployment.

$ kubectl create -f web-server.yaml 
  deployment.apps/web-server created 

Izlistajte podove zajedno sa nodovima i proverite da li su postavljeni prema pravilima:

$ kubectl get pod -o=custom-columns=NODE:.spec.nodeName,NAME:.metadata.name -n test

NODE                NAME
k8s-node-worker-3   redis-cache-58786cc745-yzxtr
k8s-node-worker-1   redis-cache-58786cc745-bmkpc
k8s-node-worker-2   redis-cache-58786cc745-lehut
k8s-node-worker-1   web-server-84b9456f9b-dhd9x
k8s-node-worker-3   web-server-84b9456f9b-lf6xs
k8s-node-worker-2   web-server-84b9456f9b-zbjq2 

Dakle, ovde vidimo da se svaki web pod nalazi u istom nodu kao i jedan Redis pod, i da nijedna dva web noda ne rade na istoj mašini, što je postignuto upotrebom pravila za pod Affinity i Anti-Affinity.

Zaključak

Kocenpti afinitet i anti-afinitet pružaju fleksibilne načine za zakazivanje pods-ova na nodovima ili postavljanje pod-ova u odnosu na druge pod-ove.
Možete koristiti pravila afiniteta za optimizaciju raspoređivanja pod-ova na radnim nodovima za performanse, toleranciju na greške ili druge složene zahteve raspoređivanja.

Primeri koji su navedeni mogu da se urade na Kubernetes klasteru na Linode Cloud-u, koji je svakako najjeftiniji i najbrže se podiže.
Ukoliko ste zaintersovani za ovo testiranje možete otvoriti nalog ovde i uraditi probu.

Nemojte zaboraviti da na kraju testiranja ugasite i obrišete komplet nodove sa mašine.

Srećna plovidba.

Napišite komentar