Kubernetes ResourceQuota en LimitRange: namespace-limieten afdwingen

ResourceQuota begrenst het totale resourceverbruik over een hele namespace. LimitRange beperkt individuele pods en containers en injecteert defaults wanneer ze ontbreken. Krijg de volgorde van admission verkeerd, en het eerste symptoom is een pod die wordt geweigerd met must specify limits.memory. Deze gids loopt door het veilig toepassen van beide objecten, het oplossen van die foutmelding, en sluit af met een referentie van elk spec-veld.

Inhoudsopgave

Waarom namespaces resource-limieten nodig hebben

Een Kubernetes-namespace is een label, geen hek. Zonder expliciete limieten kan elke pod in elke namespace zoveel CPU en geheugen claimen als het cluster vrij heeft, alle beschikbare IP's opeisen, etcd vullen met ConfigMaps, of een node in MemoryPressure duwen waardoor onverwante workloads worden geëvicteerd. ResourceQuota en LimitRange zijn de twee admission-controls die een namespace omtoveren van een label tot een echte resource-grens.

Allebei zijn admission controllers, allebei zijn standaard ingeschakeld op elk standaard-conform cluster (de plugins LimitRanger en ResourceQuota staan in de default-plugins-lijst sinds Kubernetes 1.36), en allebei doen ze niets totdat je daadwerkelijk de bijbehorende objecten in een namespace aanmaakt. De aanwezigheid van de admission plugin is de motor; een ResourceQuota- of LimitRange-object is de brandstof.

Dit artikel behandelt allebei: hoe je ze veilig toepast, de foutmelding die elk team de eerste keer raakt bij een quota-uitrol, en een complete referentie voor elk spec-veld.

ResourceQuota vs. LimitRange: wat elk afdwingt

Deze twee objecten lijken oppervlakkig op elkaar (beide zijn namespace-scoped, beide begrenzen resourceverbruik) maar ze handhaven verschillende dingen op verschillende momenten in de admission-pipeline.

Aspect ResourceQuota LimitRange
Bereik Totalen over alle pods in de namespace Per pod of per container
Wat het doet Begrenst totale CPU, geheugen, storage en object counts Zet default requests/limits en bodems en plafonds per container
Wanneer het werkt Validateert bij admission; wijst verzoeken af die het plafond zouden overschrijden Muteert bij admission (injecteert defaults), valideert tegen min/max
Admission plugin ResourceQuota (validating) LimitRanger (mutating + validating)
Foutgedrag Pod-creatie geweigerd met HTTP 403 Forbidden Pod-creatie geweigerd als buiten min/max-grenzen
Typische units requests.cpu: "10", pods: "100" default.cpu: 500m, max.memory: 8Gi
Stopt een hebberige pod Nee, alleen het totaal Ja, via max
Stopt de hele tenant Ja, via hard-totalen Nee, alleen individuele pods

Je wilt bijna altijd allebei. ResourceQuota voorkomt dat een tenant collectief het cluster opslokt. LimitRange voorkomt dat een container in die tenant in een enkele pod het hele quotum opmaakt, en biedt defaults zodat developers niet bij elke workload requests en limits hoeven mee te geven.

Pas een LimitRange toe voor de ResourceQuota

De volgorde doet ertoe. Zodra een ResourceQuota cpu of memory tracked, weigert de admission controller elke nieuwe pod die de bijbehorende requests of limits niet specificeert. LimitRange-defaults worden geïnjecteerd voor die check, dus door de LimitRange als eerste neer te zetten voorkom je dat bestaande workloads breken zodra de quota erbij komt.

# limitrange.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: team-payments
spec:
  limits:
  - type: Container
    default:                # geïnjecteerd als limits wanneer de container ze weglaat
      cpu: 500m
      memory: 512Mi
    defaultRequest:         # geïnjecteerd als requests wanneer de container ze weglaat
      cpu: 100m
      memory: 128Mi
    max:                    # plafond per container
      cpu: "4"
      memory: 8Gi
    min:                    # bodem per container
      cpu: 50m
      memory: 64Mi
    maxLimitRequestRatio:   # begrens de verhouding limit/request
      cpu: "10"             # limit mag maximaal 10x de request zijn
kubectl apply -f limitrange.yaml

Twee operationele opmerkingen. Houd één LimitRange per namespace aan. Meerdere LimitRange-objecten geven niet-deterministische default-injectie omdat de admission plugin er doorheen loopt en per resource de laatste match wint. Als default en defaultRequest identiek zijn, krijgt elke pod die resource-specs weglaat Guaranteed QoS, wat invloed heeft op eviction-prioriteit. Voor Burstable QoS als default (de gebruikelijkere keuze voor generieke workloads), zet defaultRequest lager dan default. De mechanica van QoS-klassen staat in Kubernetes resource requests en limits.

Een ResourceQuota voor compute, storage en object counts

Zodra de LimitRange staat, pas je de ResourceQuota toe. Een complete productie-stijl quota dekt vier families: compute (cpu, memory), storage (PVC-aantal en totale grootte), object counts (pods, services, secrets), en optioneel object counts voor willekeurige API-resources via de generieke count/<resource>.<group>-syntax.

# resourcequota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-payments-quota
  namespace: team-payments
spec:
  hard:
    # Compute
    requests.cpu: "10"
    requests.memory: 20Gi
    limits.cpu: "20"
    limits.memory: 40Gi
    # Object counts (ingebouwde shortcuts)
    pods: "100"
    services: "10"
    services.loadbalancers: "2"
    secrets: "30"
    configmaps: "30"
    persistentvolumeclaims: "5"
    # Storage
    requests.storage: 100Gi
    fast-ssd.storageclass.storage.k8s.io/requests.storage: 50Gi
    fast-ssd.storageclass.storage.k8s.io/persistentvolumeclaims: "3"
    # Generieke count/* voor elke API-resource
    count/deployments.apps: "20"
    count/jobs.batch: "10"
    count/ingresses.networking.k8s.io: "5"
kubectl apply -f resourcequota.yaml

De count/<resource>.<group>-syntax is beschikbaar sinds Kubernetes 1.9 en werkt voor elke API-resource, inclusief third-party CRD's (je kunt count/argocd-applications.argoproj.io quoten als Argo CD geïnstalleerd staat). Het is de juiste keuze wanneer je een resource-type wilt begrenzen dat de ingebouwde shortcuts niet dekken.

Quota voor extended resources (meestal GPU's) is toegevoegd in Kubernetes 1.10 en gebruikt de vorm requests.nvidia.com/gpu: "4". Voor extended resources is alleen het requests.-prefix toegestaan; overcommit via limits niet.

De "must specify limits.memory"-fout: oorzaak en oplossing

Dit is de foutmelding die elk team de eerste keer ziet bij een ResourceQuota:

Error from server (Forbidden): error when creating "deployment.yaml":
pods is forbidden: failed quota: team-payments-quota:
must specify limits.memory,requests.memory

Wat het betekent. De namespace heeft een ResourceQuota die requests.memory of limits.memory tracked. De pod die de deployment probeert aan te maken specificeert die velden niet, en er staat geen LimitRange in de namespace om defaults te injecteren. De admission controller weigert een pod waarvan hij het geheugenverbruik niet kan toerekenen aan de quota.

Drie oplossingen, op volgorde van voorkeur.

1. Voeg een LimitRange toe die defaults injecteert. Dit is voor de meeste teams de juiste oplossing. De LimitRange uit de vorige sectie definieert default en defaultRequest, die de admission plugin injecteert in elke pod die ze weglaat. Pods die zonder resource-specs zijn geschreven, worden zo automatisch geldig tegen de quota. Een LimitRange toepassen herstelt al gefaalde pods niet met terugwerkende kracht; je moet de deployment opnieuw uitrollen nadat de LimitRange staat.

2. Voeg expliciete requests en limits toe in de pod-spec. Pas het deployment-manifest aan:

resources:
  requests:
    cpu: 100m
    memory: 128Mi
  limits:
    cpu: 500m
    memory: 512Mi

Dit is de aanpak wanneer je elk resourceprofiel hard in het manifest wilt hebben, zonder impliciete defaults uit een LimitRange. Het levert de meest reviewbare manifests op, maar elke developer in de namespace moet weten dat dit moet.

3. Haal limits.memory uit de quota. Wil je alleen totalen voor requests begrenzen (geen limits), verwijder dan limits.cpu en limits.memory uit de ResourceQuota-spec. De admission plugin verplicht alleen velden die de quota daadwerkelijk tracked. Dit past bij namespaces waar limits met opzet sterk variëren en je geen vast plafond op cumulatieve limits wilt.

Je weet dat het werkt wanneer kubectl apply -f deployment.yaml succesvol terugkomt en kubectl get pods -n team-payments de nieuwe pods running laat zien.

Een subtiel gedrag verrast veel teams. Het aanmaken van een Deployment die de quota overschrijdt laat het Deployment-object zelf gewoon slagen. De Deployment wordt aangemaakt. Alleen de Pod-creatie daarbinnen faalt. kubectl get deployment toont een gezond ogende resource met nul ready replicas; kubectl describe deployment <naam> of kubectl get events -n <namespace> --field-selector reason=FailedCreate onthult de 403-fout. Check altijd events wanneer een deployment er gezond uitziet maar nooit ready pods produceert.

Huidig quotagebruik bekijken met kubectl describe

kubectl describe resourcequota is het werkpaard voor quota-debugging. Het laat het huidige verbruik zien tegen elke getrackte dimensie:

kubectl describe resourcequota team-payments-quota -n team-payments

Verwachte output:

Name:                                      team-payments-quota
Namespace:                                 team-payments
Resource                                   Used   Hard
--------                                   ----   ----
configmaps                                 8      30
count/deployments.apps                     5      20
count/ingresses.networking.k8s.io          1      5
count/jobs.batch                           0      10
limits.cpu                                 4500m  20
limits.memory                              9Gi    40Gi
persistentvolumeclaims                     2      5
pods                                       12     100
requests.cpu                               2100m  10
requests.memory                            4Gi    20Gi
requests.storage                           20Gi   100Gi
secrets                                    14     30
services                                   3      10
services.loadbalancers                     1      2

Twee dingen om af te lezen. De Used-kolom is wat operationeel telt. Alles boven 80% van Hard is een vroege indicator dat de volgende deployment gaat falen. Daarnaast: quota is niet retroactief. Als pods al draaiden voordat de quota werd toegepast, verschijnt hun verbruik direct onder Used, maar ze worden niet geëvicteerd om ruimte te maken.

Voor monitoring op schaal: installeer kube-state-metrics en alarmeer op de ratio kube_resourcequota{type="used"} / kube_resourcequota{type="hard"} boven 0,85. De Prometheus-monitoring-gids behandelt de installatie van kube-state-metrics in detail.

Quota-templates: productie vs staging

Twee quota-templates die ik in version control bewaar en per tenant aanpas. Het zijn startpunten, geen absolute waarden; observeer een sprint of twee en stel bij.

Productie-tenant (klein tot middelgroot serviceteam)

apiVersion: v1
kind: ResourceQuota
metadata:
  name: production-quota
  namespace: team-payments
spec:
  hard:
    requests.cpu: "20"
    requests.memory: 40Gi
    limits.cpu: "40"
    limits.memory: 80Gi
    pods: "200"
    persistentvolumeclaims: "10"
    requests.storage: 200Gi
    services: "20"
    services.loadbalancers: "3"
    secrets: "50"
    configmaps: "50"
    count/deployments.apps: "30"

De compute-headroom staat ongeveer 30% boven het verwachte steady-state-verbruik om ruimte te laten voor rolling updates zonder dat de quota uitgeput raakt. Service- en LoadBalancer-aantallen zijn strak om onbedoelde kosten te voorkomen (elke LoadBalancer mapt naar een cloud load balancer met eigen maandkosten).

Staging-tenant (kleiner, wegwerp-vriendelijk)

apiVersion: v1
kind: ResourceQuota
metadata:
  name: staging-quota
  namespace: team-payments-staging
spec:
  hard:
    requests.cpu: "5"
    requests.memory: 10Gi
    limits.cpu: "10"
    limits.memory: 20Gi
    pods: "50"
    persistentvolumeclaims: "5"
    requests.storage: 50Gi
    services: "10"
    services.loadbalancers: "0"   # geen cloud load balancers in staging
    secrets: "30"

Staging schroeft compute aan, weigert LoadBalancers volledig (gebruik port-forward of een Ingress voor staging-toegang) en gaat uit van vluchtige workloads. De lagere pod-cap dwingt developers ook om hun oude staging-namespaces op te ruimen, wat precies de bedoeling is.

Een multi-tenant cluster wil meestal beide templates parametriseerbaar via een Helm-chart of Kustomize-overlay zodat het onboarden van een tenant één PR is.

Hoe HPA met ResourceQuota interacteert

HPA omzeilt de quota niet. De Horizontal Pod Autoscaler schaalt door het spec.replicas-veld van een Deployment of ander workload-controller-object aan te passen. De controller probeert dan nieuwe pods aan te maken, en die pod-creatie loopt door dezelfde admission-pipeline als elke andere pod. Als de nieuwe replicas het verbruik boven de quota zouden duwen, faalt de pod-creatie met HTTP 403 en stopt HPA effectief met opschalen, ook al zegt de metric dat hij omhoog moet.

Het zichtbare symptoom: HPA meldt desiredReplicas: 12 in kubectl describe hpa <naam>, maar kubectl get deployment <naam> toont READY 8/12. Events op de deployment of replicaset laten FailedCreate met een quota-fout zien.

Drie aanpakken:

  1. Stel de quota in op HPA's max replicas. Als HPA tot 20 replicas van 500m CPU kan opschalen, moet de quota minimaal 10 CPU bovenop andere workloads accommoderen. Dit is de juiste aanpak voor namespaces waar HPA het belangrijkste schaalmechanisme is.
  2. Zet HPA's maxReplicas zodat het binnen de quota past. Begrens de autoscaler zodat hij de quota nooit probeert te overschrijden. De trade-off: verkeer boven wat de cap kan bedienen wordt gedropt of in een queue gezet.
  3. Ontkoppel staging- en productie-quota's. Hou strakke quota's op staging waar bursten niet nodig is, en ruime quota's op productie waar HPA zijn werk moet kunnen doen. De prod- en staging-templates hierboven implementeren dit impliciet.

Wat je ook kiest, zet de alert op used/hard > 0,85 uit de vorige sectie op. HPA-gedreven quota-uitputting is op Deployment-niveau stil totdat je events leest.

ResourceQuota-scopes

Een ResourceQuota tracked standaard elke pod in de namespace. Met scopes kun je aparte quota's maken die alleen specifieke subsets pods tellen, wat de juiste tool is wanneer je verschillende plafonds wilt voor batch-jobs versus services, of voor pods met hoge versus lage prioriteit.

Er zijn zes scopes beschikbaar, met verschillende stabiliteitsniveaus:

Scope Wat het matched Stabiliteit
BestEffort Pods zonder requests of limits op enige container Core (altijd beschikbaar)
NotBestEffort Pods met minstens één request of limit gezet Core
Terminating Pods met .spec.activeDeadlineSeconds >= 0 (meestal Jobs) Core
NotTerminating Pods met .spec.activeDeadlineSeconds niet gezet (services) Core
PriorityClass Pods die een specifieke PriorityClass referencen Stabiel sinds Kubernetes 1.17
CrossNamespacePodAffinity Pods die cross-namespace pod-affinity-termen gebruiken Stabiel sinds Kubernetes 1.24

Scope-voorbeelden:

# Begrens batch-jobs (Terminating) zonder service-quota's te raken
apiVersion: v1
kind: ResourceQuota
metadata:
  name: batch-jobs-quota
  namespace: team-payments
spec:
  hard:
    requests.cpu: "5"
    requests.memory: 10Gi
    pods: "20"
  scopes:
  - Terminating
# Reserveer capaciteit voor alleen high-priority pods
apiVersion: v1
kind: ResourceQuota
metadata:
  name: high-priority-quota
  namespace: team-payments
spec:
  hard:
    requests.cpu: "10"
    requests.memory: 20Gi
  scopeSelector:
    matchExpressions:
    - operator: In
      scopeName: PriorityClass
      values:
      - high-priority
# Blokkeer cross-namespace pod-affinity in een tenant-namespace
apiVersion: v1
kind: ResourceQuota
metadata:
  name: deny-cross-ns-affinity
  namespace: team-payments
spec:
  hard:
    pods: "0"
  scopeSelector:
    matchExpressions:
    - operator: Exists
      scopeName: CrossNamespacePodAffinity

Het laatste voorbeeld is een bewust deny-patroon: pods: "0" op de scope CrossNamespacePodAffinity zetten weigert elke pod die een cross-namespace affinity-term probeert te gebruiken, en dat is de aanbevolen manier om te voorkomen dat tenants failure domains blokkeren voor andere tenants.

Scopes kunnen worden gecombineerd. Een quota die alleen op niet-best-effort, niet-terminerende, high-priority pods slaat is een geldige constructie, al wordt alles boven twee scopes lastig om over na te denken.

Wat ResourceQuota en LimitRange niet doen

Deze sectie staat hier omdat elk veelvoorkomend misverstand over deze objecten een outage in de wachtrij is.

Ze zijn niet hetzelfde. Een ResourceQuota zonder LimitRange werkt wel, maar breekt elke pod die resource-specs weglaat. Een LimitRange zonder ResourceQuota injecteert defaults maar begrenst totaalverbruik niet. Ze hebben een ander doel en zijn ontworpen om samen gebruikt te worden.

Geen LimitRange betekent niet dat pods zonder limits prima zijn. Zodra een ResourceQuota cpu of memory tracked, falen pods zonder die velden bij admission. De foutmelding must specify limits.memory is het zichtbare gevolg. LimitRange is de tool die pods zonder expliciete specs alsnog geldig maakt; het is niet optioneel zodra er een ResourceQuota staat.

ResourceQuota beschermt nodes niet tegen overcommit. Het rekent requests en limits af bij admission, maar dwingt op runtime niets af. Een namespace met limits.memory: 100Gi quota op een cluster met in totaal 50Gi geheugen accepteert pods tot 100Gi limiet. Als die pods allemaal tegelijk geheugen gaan gebruiken, is het geheugen op voordat de kubelet kan ingrijpen. Bescherming op nodeniveau komt van eviction-thresholds en de reserved-memory-config van de kubelet, niet van quota's.

CPU-throttling gebeurt op limits, niet op requests. requests.cpu in ResourceQuota is een scheduling-tijd accounting-veld. Daadwerkelijke CPU-throttling, wanneer een container zijn allocatie overschrijdt, wordt door de Linux-kernel afgedwongen op basis van de limits.cpu per container. Een container met requests.cpu: 100m zonder limit burst vrijuit. De quota voorkomt dat niet; alleen de limit per container doet dat.

LimitRange max is geen quota. Het begrenst individuele containers (geen container in deze namespace mag meer dan 4 CPU's vragen) maar zegt niets over de som binnen de namespace. Een namespace met max.cpu: 4 en geen quota kan duizend pods elk met 4 CPU draaien.

Quota is niet retroactief. Bestaande pods worden niet geëvicteerd wanneer een quota wordt toegepast die ze zouden overschrijden. Hun verbruik staat direct onder Used, maar ze blijven draaien. Alleen nieuwe pod-creatie loopt door de quotacheck. Wil je een striktere quota op bestaande workloads afdwingen, restart dan hun controllers (kubectl rollout restart deployment <naam>) en laat de nieuwe pods erin passen of falen.

Referentie: elk ResourceQuota-veld

Deze sectie catalogiseert elk veld dat een ResourceQuota-object kan dragen. Het schema dekt API-versie v1, stabiel sinds Kubernetes 1.0; nieuwe resource-types en scopes worden binnen het bestaande schema toegevoegd, niet via breaking API-changes.

spec.hard

Een map van benoemde resources naar quantities. Elke resource die de quota tracked, staat hier.

Compute-resources:

Veld Beschrijving
requests.cpu (of cpu) Som van requests.cpu over alle niet-terminale pods mag dit niet overschrijden.
requests.memory (of memory) Som van requests.memory over alle niet-terminale pods mag dit niet overschrijden.
limits.cpu Som van limits.cpu over alle niet-terminale pods.
limits.memory Som van limits.memory over alle niet-terminale pods.
hugepages-<size> Som van huge-page-requests van de gegeven grootte (bijvoorbeeld hugepages-2Mi).
requests.ephemeral-storage Som van ephemeral-storage-requests over alle pods.
limits.ephemeral-storage Som van ephemeral-storage-limits over alle pods.
requests.<extended-resource> Som van requests voor een extended resource (bijvoorbeeld requests.nvidia.com/gpu). Beschikbaar sinds Kubernetes 1.10.

Storage-resources:

Veld Beschrijving
requests.storage Som van spec.resources.requests.storage over alle PVC's in de namespace.
persistentvolumeclaims Totaal aantal PVC's dat in de namespace mag bestaan.
<storage-class>.storageclass.storage.k8s.io/requests.storage Som van requests.storage voor PVC's die een specifieke StorageClass referencen.
<storage-class>.storageclass.storage.k8s.io/persistentvolumeclaims Aantal toegestane PVC's voor een specifieke StorageClass.

Object counts (ingebouwde shortcuts):

Veld Beschrijving
pods Totaal niet-terminale pods.
services Totaal Services.
services.loadbalancers Services van type LoadBalancer.
services.nodeports Services van type NodePort.
secrets Totaal Secrets.
configmaps Totaal ConfigMaps.
persistentvolumeclaims Totaal PVC's (staat ook onder storage).
replicationcontrollers Totaal ReplicationControllers.
resourcequotas Totaal ResourceQuotas (zelden getrackt).

Object counts (generieke syntax, beschikbaar sinds Kubernetes 1.9):

Veld Beschrijving
count/<resource>.<group> Totaal objecten van het gegeven type. Werkt voor core API-resources (count/pods), built-in groepen (count/deployments.apps, count/jobs.batch, count/ingresses.networking.k8s.io) en CRD's (count/argocd-applications.argoproj.io).

spec.scopes

Een optionele lijst van scope-namen. De quota telt alleen objecten die op alle opgegeven scopes matchen. Geldige waarden:

Scope Beschrijving Stabiliteit
BestEffort Pods zonder requests of limits op enige container. Core
NotBestEffort Pods met minstens één request of limit gezet. Core
Terminating Pods met spec.activeDeadlineSeconds >= 0. Core
NotTerminating Pods met spec.activeDeadlineSeconds niet gezet. Core
PriorityClass Pods die een PriorityClass referencen (gebruik met scopeSelector). Stabiel sinds 1.17
CrossNamespacePodAffinity Pods met cross-namespace pod-affinity-termen. Stabiel sinds 1.24

BestEffort en NotBestEffort sluiten elkaar uit, net als Terminating en NotTerminating. Onverenigbare scopes combineren levert een quota op die niets matched.

spec.scopeSelector

Een uitdrukkingsrijker alternatief voor spec.scopes. Verplicht bij scopen op PriorityClass.

scopeSelector:
  matchExpressions:
  - operator: In | NotIn | Exists | DoesNotExist
    scopeName: PriorityClass | CrossNamespacePodAffinity | <ander>
    values:
    - <waarde>

operator moet In of NotIn zijn als values niet leeg is, en Exists of DoesNotExist als values leeg is.

status.hard en status.used

Read-only velden die de ResourceQuota-controller invult. hard spiegelt spec.hard; used rapporteert het huidige verbruik per getrackte resource. Dit is wat kubectl describe resourcequota afleest.

Referentie: elk LimitRange-veld

LimitRange is ook een stabiele v1-API. Elke entry in spec.limits is één constraint-blok.

spec.limits[].type

Het type object waarop de constraint slaat. Drie waarden worden ondersteund:

Type Wat het begrenst
Container Individuele containers (de meest voorkomende). Accepteert default, defaultRequest, min, max, maxLimitRequestRatio.
Pod Totaal over alle containers in een pod. Accepteert min, max, maxLimitRequestRatio. Accepteert default of defaultRequest niet.
PersistentVolumeClaim Storage gevraagd door PVC's in de namespace. Accepteert min en max voor de storage-resource.

spec.limits[].default

Een map van resource-namen naar quantities. Wordt geïnjecteerd als limits in elke container die ze niet specificeert. Werkt alleen bij type: Container.

default:
  cpu: 500m
  memory: 512Mi

spec.limits[].defaultRequest

Zelfde vorm als default, maar geïnjecteerd als requests. Werkt alleen bij type: Container.

defaultRequest:
  cpu: 100m
  memory: 128Mi

Als defaultRequest gelijk is aan default, is de resulterende pod Guaranteed QoS. Wil je standaard Burstable QoS-pods, zet defaultRequest lager dan default.

spec.limits[].min

Bodem per resource. Een container of PVC die er minder dan vraagt wordt geweigerd bij admission met een duidelijke foutmelding die de resource benoemt.

min:
  cpu: 50m
  memory: 64Mi
  storage: 1Gi   # alleen bij type: PersistentVolumeClaim

spec.limits[].max

Plafond per resource. Een container of PVC die er meer dan vraagt wordt geweigerd.

max:
  cpu: "4"
  memory: 8Gi
  storage: 100Gi   # alleen bij type: PersistentVolumeClaim

spec.limits[].maxLimitRequestRatio

Een plafond op de verhouding limit / request voor een gegeven resource, uitgedrukt als quantity. Een waarde van "4" betekent dat de limit van een container maximaal 4x de request mag zijn.

maxLimitRequestRatio:
  cpu: "10"
  memory: "4"

Dit is het veld dat voorkomt dat een developer requests.cpu: 100m zet met limits.cpu: 8000m, waardoor één container alsnog naar 8 cores kan bursten op een node waar hij gescheduled werd op basis van slechts 100m. In multi-tenant clusters is een ratio-cap van 4 tot 10 een verdedigbare default.

Hoe LimitRange met admission werkt

De LimitRanger admission plugin draait in twee fases. Eerst muteert hij pod-specs door default- en defaultRequest-waarden te injecteren voor containers die ze weglaten. Daarna valideert hij de resulterende pod tegen min, max en maxLimitRequestRatio. De mutatie gebeurt voordat de validatie van ResourceQuota loopt, en daarom werken LimitRange en ResourceQuota samen: de LimitRange vult de gaten op voordat de quota op missende velden checkt.

Meerdere LimitRange-objecten in een namespace zijn technisch toegestaan, maar leveren niet-deterministische injectie omdat de plugin er doorheen loopt en per resource de laatste match wint. Hou het bij één LimitRange per namespace.

Voor het bredere namespace-isolatie-patroon dat ResourceQuota en LimitRange combineert met NetworkPolicy, RBAC en Pod Security Standards, zie de multi-tenancy-walkthrough.

Terugkerende server- of deploymentproblemen?

Ik help teams productie betrouwbaar maken met CI/CD, Kubernetes en cloud—zodat fixes blijven en deploys geen stress meer zijn.

Bekijk DevOps consultancy

Doorzoek deze site

Begin met typen om te zoeken, of blader door de kennisbank en blog.