Forceer pods naar bepaalde node(s)

In een Kubernetes Cluster kan het voorkomen dat je bepaalde pods op een vastgestelde worker-node (of groep worker-nodes) wilt installeren. Dit kan zijn omdat deze workers sneller zijn dan andere workers of omdat je de worker nodes in een externe load-balancer als endpoint hebt gedefinieerd. Hoe dan ook, we gaan het forceren want standaard kiest de cluster zelf de worker-node en dat willen we dus niet.

De meest simpele manier om pods aan een bepaalde node te koppelen is om in de manifest file aan te geven welke nodeName er gebruikt dient te worden, bijvoorbeeld:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeName: node2
  containers:
  - name: nginx
    image: nginx 

Nu kan het natuurlijk zijn dat je een aantal gelijksoortige worker-nodes wilt gaan gebruiken en dan werkt de optie nodeName uiteraard niet. Een oplossing is hiervoor beschikbaar door ‘labels‘ te gebruiken.

Allereerst gaan we de workers, die we willen gebruiken als bestemming voor de pods, een label geven. (ookal is dat in mijn geval maar één worker-node per uniek label, maar het gaat om het idee)

$ kubectl get nodes
NAME     STATUS   ROLES    AGE   VERSION
master   Ready    master   59d   v1.16.2
node1    Ready    worker   59d   v1.16.2
node2    Ready    worker   59d   v1.16.2 

$ kubectl label node node1 kleur=geel
$ kubectl label node node2 kleur=groen

$ kc get nodes --show-labels | grep worker
node1    Ready    worker   59d   v1.16.2   ...,kleur=geel,...
node2    Ready    worker   59d   v1.16.2   ...,kleur=groen,...

Zoals je ziet hebben de worker nodes in mijn cluster beiden een kleur gekregen, node1 is geel en node2 is groen. We maken nu een manifest file met daarin een nodeSelector:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx
  nodeSelector:
    kleur: groen 

Als we deze manifest deployen naar de cluster zal de pod aangemaakt worden in de worker-node met het label kleur=groen, in dit geval is dat node2.

$ kubectl get pods -o wide
NAME    READY   STATUS    RESTARTS   AGE     IP          NODE    
nginx   1/1     Running   0          5m40s   10.44.0.2   node2

Pod Affinity en Anti-Affinity

Niet specifiek bedoeld voor deployments maar wel handig is het gebruik van affinity en anti-affinity. Voor het gebruik hiervan zijn twee opties beschikbaar:

  • requiredDuringSchedulingIgnoredDuringExecution – hiermee wordt aangegeven dat de pod niet scheduled kan worden totdat de node aan de affinity voorwaarden voldoet
  • preferredDuringSchedulingIgnoredDuringExecution – hiermee wordt aangegeven dat een pod zal proberen op een node te komen die aan de voorwaardes van de affinity voldoet, lukt dat niet dan kan een andere node gebruikt worden.

Een voorbeeld van een podAntiAffinity waarbij wordt voorkomen dat alle pods met label ‘app=simple-nginx’ op dezelfde node terecht komen:

spec:
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - simple-nginx
        topologyKey: "kubernetes.io/hostname"
  container:

Dit komt dus in de spec: van de container te staan. (zorg wel voor genoeg ‘vrije’ nodes om te voorkomen dat pods in status ‘Pending’ blijven staan!)