2024-07-17

Inleiding tot Kubernetes Resources

Wanneer je Kubernetes begint te gebruiken, is een van de eerste dingen waarmee je in aanraking komt de instellingen voor geheugen en CPU-gebruik. Het wordt sterk aanbevolen om voor elke container in je pods deze instellingen correct in te stellen. Dit is cruciaal voor het optimaliseren van de prestaties en betrouwbaarheid van je applicaties. Bovendien kan Kubernetes betere beslissingen nemen, en zo efficienter machines gaan gebruiken, zodat je een optimale omgeving krijgt.

Containers, Pods en Nodes

Wanneer je een applicatie hebt gebouwd, wordt deze verpakt als een image (een container image of docker image). Deze image wordt gebruikt om een container te starten, die op zijn beurt deel uitmaakt van een pod.

Eenvoudig gesteld kan je Kubernetes zien als een systeem dat applicaties uitvoert op een aantal machines (nodes in Kubernetes-speak). Kubernetes heeft zicht op de totale CPU en geheugen van elke machine. Wat Kubernetes echter niet weet, zijn de specifieke behoeften van je applicatie. Zonder deze informatie wordt het toekennen van applicaties aan machines meer een berekende gok dan een weldoordachte keuze. En dat willen we uiteraard vermijden...

CPU en Geheugen

We richten ons eerst op de twee basis-resources: CPU en geheugen. Weet echter dat er meer resources zijn, zoals opslag en GPU's, die elk hun eigen complexiteit en gebruik hebben. In latere blogposts zullen we dieper ingaan op bijvoorbeeld opslag en GPU-gebruik.

Resources Bekijken

Je kunt de beschikbare resources van elke machine in je Kubernetes-cluster opvragen met het volgende commando:

kubectl get nodes -o json | jq '.items[].status.capacity’

Dit geeft output zoals:

{
  "cpu": "4",
  "ephemeral-storage": "20414Mi",
  "hugepages-1Gi": "0",
  "hugepages-2Mi": "0",
  "memory": "7981416Ki",
  "pods": "58"
}

Hier zien we de beschikbaarheid van ongeveer 8 GB werkgeheugen en 4 CPUs. Mocht je de tool jq niet hebben, doe dan even een kubectl describe nodes en ga op zoek naar "Capacity" onder "Status".

Eenheden

Wanneer je CPU en geheugen instelt voor je containers in Kubernetes, is het belangrijk om de eenheden correct te begrijpen en gebruiken.

CPU

CPU resources in Kubernetes worden uitgedrukt in "cpu"/"core" of "millicpu"/"millicore" (m). Eén CPU-eenheid in Kubernetes komt overeen met één virtuele CPU (vCPU, een "core") of één fysieke CPU-kern op de onderliggende node. De exacte rekenkracht die hiermee gepaard gaat is afhankelijk van de hardware.

Enkele voorbeelden:

  • cpu: 1: Dit staat gelijk aan 1 CPU. Als je een waarde van 1 of 1000m opgeeft, betekent dit dat je container één volledige CPU-kern krijgt toegewezen.
  • cpu: 500m: Dit staat gelijk aan 0.5 CPU. Met 500m geef je je container de helft van de capaciteit van een enkele CPU-core.
  • cpu: 2.5: Dit staat gelijk aan de rekenkracht van 2.5 CPU.

Het gebruik van millicpu maakt het mogelijk om CPU resources nauwkeurig toe te wijzen. Lager dan 1 millicpu (of millicore) kan je niet toewijzen. Waarden als "0.5m" of "0.0005" zijn dus niet geldig. De kleinste toekenning is dus "1m", of 0.001.

Geheugen (memory)

Werkgeheugen, of memory, of "RAM" wordt uitgedrukt in bytes, maar je kunt ook grotere eenheden zoals kilobytes, megabytes, en gigabytes gebruiken. Hierdoor kun je geheugen nauwkeurig toewijzen aan je containers, afhankelijk van de behoefte van je applicatie.

De eenheden die gebruikt worden zijn de SI eenheden. Daarom spreken we niet van "megabytes" en "gigabytes" maar wel van "mebibytes" en "gibibytes". Want, 5 GB is eigenlijk gelijk aan 5000 MB, maar 5 Gi is echter 5368.7 MB.

Enkele voorbeelden:

  • memory: 128Mi: Dit staat voor 128 mebibytes. De 'Mi' suffix staat voor mebibytes, waarbij 1 Mi gelijk is aan 2^20 bytes of 1,048,576 bytes.
  • memory: 1Gi: Dit staat voor 1 gibibyte. De 'Gi' suffix staat voor gibibytes, waarbij 1 Gi gelijk is aan 2^30 bytes of 1,073,741,824 bytes.
"Once upon a time, computer professionals noticed that 2^10 was very nearly equal to 1000 and started using the SI prefix "kilo" to mean 1024. That worked well enough for a decade or two because everybody who talked kilobytes knew that the term implied 1024 bytes. But, almost overnight a much more numerous "everybody" bought computers, and the trade computer professionals needed to talk to physicists and engineers and even to ordinary people, most of whom know that a kilometer is 1000 meters and a kilogram is 1000 grams."

Meer over het waarom van de verschillende eenheden kan je vinden op de SI site van NIST bij "Historical context".

Pro-tip. Iedereen is er al eens tegen gelopen, maar denk eraan dat je ook best niet de eenheid van "cpu" gaat gebruiken bij geheugen. Stel dat je `memory: 128m` definieert als waarde, dan spreken we van 0.128 bytes, wat bitter weinig is... Misschien (vermoedelijk) bedoelde je `128Mi`.

Een Voorbeeld van Resource Instellingen

Hier is een voorbeeld van een eenvoudige pod:

apiVersion: v1
kind: Pod
metadata:
  name: voorbeeld-pod
spec:
  containers:
  - name: voorbeeld-container
    image: voorbeeld-image
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

In dit voorbeeld zien we de twee belangrijke onderdelen van het "resources" blok bij de container: "requests" en "limits". We focussen eerst op de "requests".

Requests: De Basisvereisten

Wanneer je een "request" instelt, vraag je Kubernetes om je applicatie te plaatsen op een machine waar minimaal die hoeveelheid CPU en geheugen beschikbaar is. Kubernetes bekijkt voor elke machine de reeds toegekende pods en berekent hoeveel CPU en geheugen nog beschikbaar is. Je applicatie zal alleen toegewezen worden aan een machine met voldoende capaciteit. Dit is de taak van de "scheduler" binnen Kubernetes.

"The scheduler ensures that, for each resource type, the sum of the resource requests of the scheduled containers is less than the capacity of the node."

Limits: De Maximale Grenzen

Zodra de applicatie gestart is, komen de "limits" in actie. Er wordt een harde limiet ingesteld op de opgegeven waarden. Als de applicatie probeert om deze limieten te overschrijden, wordt dit niet toegestaan. Dit is essentieel om te voorkomen dat een enkele applicatie te veel resources gebruikt en andere applicaties op dezelfde machine beïnvloedt.

En wat als je niet alles defnieert?

Wanneer je een limit opgeeft, maar geen request, dan gaat Kubernetes de limits ook gebruiken als request. Wanneer je request opgeeft, maar geen limit, dan wordt de request gebruikt bij het kiezen van een machine, en worden er geen limieten gezet op het gebruik van CPU en geheugen eens je applicatie draait.

Conclusie

Het correct instellen van CPU en geheugen voor je containers is van groot belang voor de prestaties en betrouwbaarheid van je Kubernetes-cluster. Door het instellen van zowel "requests" als "limits" zorg je ervoor dat je applicaties efficiënt worden geplaatst en dat ze binnen veilige grenzen blijven werken. Dit is nog maar het begin, in andere blogposts zullen we dieper ingaan op de details.

Onze laatste blogposts