Hvorfor 68% af alle organisationer bruger for meget på Kubernetes
Kubernetes har fuldstændig ændret måden, vi kører applikationer i skyen. Men med al den fleksibilitet følger en ret irriterende bivirkning: ukontrollerede omkostninger. Data fra 2026 viser, at mere end 68% af organisationer overforbruger på Kubernetes med 20-40% — og de fleste aner det ikke engang.
Problemet er faktisk ikke Kubernetes selv. Det er den måde, vi konfigurerer ressourcer på.
Ingeniører har en helt naturlig tendens til at overallokere CPU og hukommelse. Ingen har lyst til at være den person, der forårsager nedetid kl. 2 om natten — det forstår jeg godt. Men den defensive overprovisionering koster altså dyrt. Undersøgelser viser, at 80-90% af alle pods har oppustede ressourceanmodninger "for en sikkerheds skyld", og selv relativt små reduktioner på 5-15% per pod kan akkumulere til 30-60% besparelser på hele klyngen gennem bedre bin-packing.
Så lad os dykke ned i det. I denne artikel gennemgår vi en komplet, praktisk guide til Kubernetes-omkostningsoptimering i 2026. Du får arbejdsklare YAML-konfigurationer, kubectl-kommandoer og en trinvis strategi, der kan reducere din Kubernetes-regning med op til 40-70% — uden at gå på kompromis med pålideligheden.
Forstå Kubernetes-omkostninger: Hvor forsvinder pengene egentlig?
Før vi kan optimere noget som helst, skal vi forstå hvad vi betaler for. Kubernetes-omkostninger kan grundlæggende inddeles i fire kategorier:
- Compute (noder): CPU og hukommelse på de virtuelle maskiner, der udgør klyngen. Det her er typisk 60-70% af den samlede regning — altså langt det største punkt.
- Storage: Persistent Volumes, snapshots og backup-storage. Ofte 10-20% af omkostningerne.
- Netværk: Udgående datatrafik (egress), load balancers og cross-zone trafik. Typisk 5-15%.
- Overhead: Control plane, monitoring-værktøjer og logging. De resterende 5-10%.
Den absolut største besparelse ligger i compute — altså i at sikre, at dine noder og pods bruger de ressourcer, de faktisk har brug for. Og det starter med right-sizing.
Strategi 1: Right-Sizing af Pods med Vertical Pod Autoscaler (VPA)
Right-sizing handler om at matche de allokerede ressourcer med det faktiske forbrug. I Kubernetes styres det af resources.requests og resources.limits i pod-specifikationen. Problemet? De fleste teams sætter værdierne én gang ved deployment og kigger aldrig på dem igen.
Vertical Pod Autoscaler (VPA) løser det ved automatisk at analysere det historiske ressourceforbrug og anbefale — eller automatisk justere — CPU- og hukommelsesanmodninger for dine pods.
Trin 1: Start med VPA i anbefalingstilstand
Den sikreste tilgang er at køre VPA i Off-tilstand, hvor den blot observerer og giver anbefalinger uden at ændre noget. Tro mig, start altid her:
# vpa-recommendation.yaml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: webapp-vpa
namespace: production
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: webapp
updatePolicy:
updateMode: "Off"
resourcePolicy:
containerPolicies:
- containerName: '*'
minAllowed:
cpu: 50m
memory: 64Mi
maxAllowed:
cpu: 2
memory: 2Gi
controlledResources: ["cpu", "memory"]
Anvend konfigurationen:
kubectl apply -f vpa-recommendation.yaml
Trin 2: Læs VPA-anbefalinger
Giv VPA et par dage til at indsamle data, og læs så anbefalingerne:
kubectl describe vpa webapp-vpa -n production
Output viser fire vigtige værdier:
Status:
Recommendation:
Container Recommendations:
Container Name: webapp
Lower Bound:
Cpu: 250m
Memory: 128Mi
Target:
Cpu: 500m
Memory: 256Mi
Upper Bound:
Cpu: 1500m
Memory: 512Mi
Uncapped Target:
Cpu: 500m
Memory: 256Mi
- Target: Den anbefalede værdi — brug denne som din nye
requests-værdi - Lower Bound: Minimumanbefaling baseret på det observerede forbrug
- Upper Bound: Maksimumanbefaling til at håndtere spidsbelastninger
- Uncapped Target: Anbefaling uden hensyntagen til
minAllowed/maxAllowed
Trin 3: Anvend anbefalinger manuelt eller skift til Auto-tilstand
Når du har kigget anbefalingerne igennem og valideret dem, kan du enten opdatere dine Deployment-manifester manuelt eller skifte VPA til Auto-tilstand:
# vpa-auto.yaml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: webapp-vpa
namespace: production
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: webapp
updatePolicy:
updateMode: "Auto"
resourcePolicy:
containerPolicies:
- containerName: '*'
minAllowed:
cpu: 100m
memory: 128Mi
maxAllowed:
cpu: 2
memory: 2Gi
Vigtigt: I Auto-tilstand genstarter VPA pods for at anvende nye ressourceværdier. Sørg for, at dine workloads rent faktisk kan håndtere rolling restarts, ellers får du en dårlig dag.
VPA Update Modes oversigt
| Tilstand | Adfærd | Anbefalet til |
|---|---|---|
Off | Kun anbefalinger — ingen automatiske ændringer | Indledende analyse, produktion |
Initial | Anvender anbefalinger kun ved oprettelse af nye pods | Stateful workloads |
Recreate | Genstarter pods med opdaterede ressourcer | Udviklings- og testmiljøer |
Auto | Anvender automatisk anbefalinger (kan genstarte pods) | Stabile, stateless workloads |
Strategi 2: Horizontal Pod Autoscaler (HPA) for trafikbaseret skalering
Mens VPA justerer ressourcer inden i en pod, justerer Horizontal Pod Autoscaler (HPA) antallet af pod-replikaer baseret på observerede metrics. HPA er perfekt til workloads med varierende trafik — API-servere, web-frontends og mikrotjenester.
HPA baseret på CPU-udnyttelse
# hpa-cpu.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: webapp-hpa
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: webapp
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 30
policies:
- type: Percent
value: 50
periodSeconds: 60
Lad os kigge på de vigtige parametre:
averageUtilization: 70: HPA skalerer op, når gennemsnitlig CPU-udnyttelse kommer over 70%scaleDown.stabilizationWindowSeconds: 300: Venter 5 minutter før nedskalering — det undgår den klassiske flapping-problematikscaleDown.policies: Nedskalerer maks 10% ad gangen per minut. Langsomt og sikkert.scaleUp.policies: Opskalerer op til 50% ad gangen — hurtig respons, når trafikken pludselig stiger
Kombiner HPA med KEDA for event-drevet skalering
KEDA (Kubernetes Event-Driven Autoscaler) udvider HPA med evnen til at skalere baseret på eksterne metrics — køer, databaser, brugerdefinerede metrics og en masse andet. Det er særligt nyttigt til asynkrone workloads:
# keda-scaledobject.yaml
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: order-processor
namespace: production
spec:
scaleTargetRef:
name: order-processor
minReplicaCount: 1
maxReplicaCount: 50
triggers:
- type: aws-sqs-queue
metadata:
queueURL: https://sqs.eu-west-1.amazonaws.com/123456789/orders
queueLength: "5"
awsRegion: "eu-west-1"
Her skalerer KEDA order-processor-deployment baseret på antallet af beskeder i en SQS-kø. Når køen er tom, skaleres ned til 1 replika. Når der er mere end 5 beskeder per replika, skaleres op. Simpelt og effektivt.
Vigtigt at huske: Undgå at bruge VPA og HPA på de samme metrics (CPU/hukommelse) samtidig — de vil konflikte med hinanden, og det bliver rodet. Brug VPA til ressource-right-sizing og HPA/KEDA til replika-skalering baseret på separate metrics.
Strategi 3: Karpenter — Intelligent node-provisionering
Mens VPA og HPA optimerer på pod-niveau, tager Karpenter sig af node-niveauet. Karpenter er en moderne erstatning for Kubernetes Cluster Autoscaler, og ærligt talt er den ret imponerende i sin tilgang til node-provisionering.
Hvor Cluster Autoscaler er begrænset til foruddefinerede nodegrupper, analyserer Karpenter ventende pods krav og vælger automatisk den optimale instanstype fra hele det tilgængelige katalog. Det reducerer typisk omkostningerne med 10-20% sammenlignet med faste nodegrupper.
Karpenter NodePool til produktion (Spot + On-Demand)
# nodepool-production.yaml
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: production
spec:
template:
metadata:
labels:
environment: production
managed-by: karpenter
spec:
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
expireAfter: 720h # 30 dage
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ["on-demand", "spot"]
- key: node.kubernetes.io/instance-type
operator: In
values:
- m6i.large
- m6i.xlarge
- m6i.2xlarge
- m6a.large
- m6a.xlarge
- m6a.2xlarge
- c6i.large
- c6i.xlarge
- r6i.large
- r6i.xlarge
- key: kubernetes.io/arch
operator: In
values: ["amd64", "arm64"]
- key: topology.kubernetes.io/zone
operator: In
values:
- eu-west-1a
- eu-west-1b
- eu-west-1c
limits:
cpu: 200
memory: 400Gi
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 60s
budgets:
- nodes: "15%"
Der er en del at gennemgå her, så lad os tage de vigtigste punkter:
capacity-type: ["on-demand", "spot"]: Karpenter kan vælge mellem on-demand og spot-instanser baseret på tilgængelighed og prisinstance-type: En bred vifte af instanstyper giver Karpenter fleksibilitet til at finde den billigste optionarch: ["amd64", "arm64"]: Graviton (ARM)-instanser er typisk 20% billigere — lad Karpenter vælgeconsolidationPolicy: WhenEmptyOrUnderutilized: Karpenter konsoliderer automatisk underudnyttede noderconsolidateAfter: 60s: Venter 60 sekunder inden konsolidering for at undgå flappingbudgets.nodes: "15%": Maks 15% af noder kan forstyrres på samme tid
Karpenter NodePool til udviklingsmiljø (kun Spot)
Til udviklings- og testmiljøer kan du tillade dig at være mere aggressiv — her bruger vi kun spot-instanser:
# nodepool-dev.yaml
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: development
spec:
template:
metadata:
labels:
environment: development
managed-by: karpenter
spec:
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
expireAfter: 168h # 7 dage
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ["spot"]
- key: node.kubernetes.io/instance-type
operator: In
values:
- m6i.large
- m6i.xlarge
- m6a.large
- m6a.xlarge
- c6i.large
- c6a.large
- r6i.large
- r6a.large
- m7i.large
- m7a.large
- c7i.large
- c7a.large
- r7i.large
- r7a.large
- m7i-flex.large
limits:
cpu: 100
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 10s
budgets:
- nodes: "30%"
Bemærk, at vi inkluderer mindst 15 instanstyper for Spot. Det er en vigtig best practice — Karpenters Spot-til-Spot-konsolidering kræver bred diversificering for at finde billigere alternativer og reducere risikoen for afbrydelser. Jo flere typer, jo bedre.
Avanceret: Vedligeholdelsesvinduer med Karpenter Budgets
I produktionsmiljøer vil du næsten altid begrænse konsolidering til bestemte tidsrum. Det her er en af de konfigurationer, jeg synes er mest undervurderet:
# nodepool-maintenance-window.yaml
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: production-scheduled
spec:
template:
spec:
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ["on-demand", "spot"]
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 30s
budgets:
# I arbejdstiden (06-02): Bloker underudnyttet disruption
- duration: 20h
nodes: "0"
reasons:
- Underutilized
schedule: "0 6 * * *"
# I arbejdstiden: Tillad tomme og driftede noder
- duration: 20h
nodes: "10%"
reasons:
- Empty
- Drifted
schedule: "0 6 * * *"
# Vedligeholdelsesvindue (02-06): Tillad al disruption
- duration: 4h
nodes: "10%"
reasons:
- Underutilized
- Empty
- Drifted
schedule: "0 2 * * *"
Konfigurationen sikrer, at Karpenter kun udfører aggressive konsolideringer i vedligeholdelsesvinduet mellem kl. 02 og 06, mens tomme noder og driftede noder stadig håndteres i arbejdstiden. Det giver ro i maven i dagtimerne.
Strategi 4: ResourceQuotas og LimitRanges — Governance på klyngeniveau
Autoscaling og right-sizing er fantastisk, men de forhindrer ikke teams i at oprette workloads med fuldstændig absurde ressourcekrav. (Og ja, det sker oftere end man tror.) ResourceQuotas og LimitRanges giver dig governance-kontroller på namespace-niveau.
ResourceQuota: Begræns det samlede forbrug per namespace
# resource-quota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-alpha-quota
namespace: team-alpha
spec:
hard:
requests.cpu: "20"
requests.memory: 40Gi
limits.cpu: "40"
limits.memory: 80Gi
pods: "100"
persistentvolumeclaims: "20"
LimitRange: Sæt standardværdier og grænser per pod
# limit-range.yaml
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: team-alpha
spec:
limits:
- default:
cpu: 500m
memory: 256Mi
defaultRequest:
cpu: 100m
memory: 128Mi
max:
cpu: 4
memory: 8Gi
min:
cpu: 50m
memory: 64Mi
type: Container
LimitRange er særligt nyttig, fordi den automatisk tildeler standardressourcer til pods, der deployes uden eksplicitte requests og limits. Uden den vil disse pods bruge ubegrænsede ressourcer, og så kan du godt glemme alt om bin-packing — det driver bare omkostningerne i vejret.
Strategi 5: Spot-instanser — Op til 90% besparelse
Spot-instanser (AWS), Spot VMs (Azure) og Preemptible VMs (GCP) tilbyder ledig kapacitet til op til 90% rabat sammenlignet med on-demand-priser. Det er en kæmpe besparelse, men de kræver, at dine workloads kan håndtere afbrydelser.
Hvornår skal du bruge Spot-instanser?
| Velegnet til Spot | Undgå Spot |
|---|---|
| CI/CD-pipelines | Stateful databaser |
| Batch-processing | Latenstunge API-servere |
| ML-træningsjobs | Singleton-tjenester |
| Udviklingsmiljøer | Real-time betalingsbehandling |
| Stateless mikrotjenester | Kubernetes control plane |
Konfigurer pods til Spot med tolerations og nodeaffinitet
# spot-tolerant-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: batch-worker
namespace: processing
spec:
replicas: 5
selector:
matchLabels:
app: batch-worker
template:
metadata:
labels:
app: batch-worker
spec:
tolerations:
- key: "karpenter.sh/capacity-type"
operator: "Equal"
value: "spot"
effect: "NoSchedule"
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 90
preference:
matchExpressions:
- key: karpenter.sh/capacity-type
operator: In
values:
- spot
terminationGracePeriodSeconds: 120
containers:
- name: worker
image: batch-worker:latest
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 1
memory: 1Gi
Kombiner det med en PodDisruptionBudget, så du er sikker på, at et minimum antal pods altid kører:
# pdb.yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: batch-worker-pdb
namespace: processing
spec:
minAvailable: 2
selector:
matchLabels:
app: batch-worker
Strategi 6: Overvågning og kontinuerlig optimering
Alle de strategier, vi har gennemgået, er kun effektive, hvis du løbende overvåger og justerer. FinOps Foundation beskriver det som en cyklisk tilgang i tre faser: Inform → Optimize → Operate. Det er ikke et engangsprojekt — det er en løbende proces.
Essentielle kubectl-kommandoer til omkostningsanalyse
Start med at få overblik over det aktuelle ressourceforbrug:
# Se nodeudnyttelse
kubectl top nodes
# Se podudnyttelse i et specifikt namespace
kubectl top pods -n production --sort-by=cpu
# Find pods uden ressourceanmodninger
kubectl get pods --all-namespaces -o json | \
jq -r '.items[] | select(.spec.containers[].resources.requests == null) | .metadata.namespace + "/" + .metadata.name'
# Find oversized pods (requests vs faktisk forbrug)
kubectl get vpa --all-namespaces -o json | \
jq -r '.items[] | .metadata.name + ": Target CPU=" + (.status.recommendation.containerRecommendations[0].target.cpu // "N/A")'
Prometheus-forespørgsler til omkostningsovervågning
Opsæt dashboards i Grafana med disse PromQL-forespørgsler — de giver dig et rigtig godt billede af, hvor pengene forsvinder:
# CPU-udnyttelsesprocent per namespace
sum(rate(container_cpu_usage_seconds_total{namespace!="kube-system"}[5m])) by (namespace)
/
sum(kube_pod_container_resource_requests{resource="cpu", namespace!="kube-system"}) by (namespace)
* 100
# Hukommelsesudnyttelse per namespace
sum(container_memory_working_set_bytes{namespace!="kube-system"}) by (namespace)
/
sum(kube_pod_container_resource_requests{resource="memory", namespace!="kube-system"}) by (namespace)
* 100
# Uallokeret kapacitet per node (spild)
sum(kube_node_status_allocatable{resource="cpu"}) by (node)
-
sum(kube_pod_container_resource_requests{resource="cpu"}) by (node)
Anbefalede værktøjer i 2026
| Værktøj | Anvendelse | Pris |
|---|---|---|
| Kubecost | Omkostningsallokering per namespace, deployment og label | Gratis tier tilgængelig |
| Prometheus + Grafana | Ressourceovervågning og dashboards | Open source |
| Karpenter | Intelligent node-provisionering med spot-optimering | Open source |
| KEDA | Event-drevet autoscaling | Open source |
| Goldilocks | VPA-anbefalinger som dashboard | Open source |
Den komplette optimeringsstrategi: En trinvis plan
Her er den rækkefølge, jeg vil anbefale for implementering af Kubernetes-omkostningsoptimering:
- Uge 1-2: Synlighed. Installer Kubecost og Prometheus/Grafana. Få overblik over, hvad der koster hvad. Identificer de største omkostningsdrivere. Du kan ikke optimere noget, du ikke kan måle.
- Uge 3-4: Right-sizing. Deploy VPA i
Off-tilstand på alle workloads. Indsaml anbefalinger i mindst 7 dage. AnvendTarget-værdier på dine Deployments. - Uge 5-6: Autoscaling. Implementer HPA på alle trafikbaserede workloads. Opsæt KEDA for kø-baserede workloads. Brug tid på at tune scale-down-parametre — det er her, flapping-problemer typisk opstår.
- Uge 7-8: Node-optimering. Migrer fra Cluster Autoscaler til Karpenter (på AWS). Aktiver Spot-instanser for ikke-kritiske workloads. Konfigurer konsolideringspolitikker.
- Uge 9-10: Governance. Implementer ResourceQuotas og LimitRanges per namespace. Opsæt showback-rapporter per team. Definer budgetter og alarmer.
- Løbende: Iteration. Ugentlig gennemgang af omkostningstendenser. Kvartalsvis revision af ressourceanbefalinger. Automatisk oprydning af forladte ressourcer.
Typiske besparelser: Hvad kan du realistisk forvente?
Baseret på branchedata fra 2026 kan du forvente følgende besparelser ved konsekvent implementering:
| Strategi | Typisk besparelse | Implementeringstid |
|---|---|---|
| Right-sizing med VPA | 20-35% | 2-3 uger |
| HPA/KEDA autoscaling | 15-25% | 2-4 uger |
| Karpenter node-optimering | 10-20% | 1-2 uger |
| Spot-instanser | 40-70% (på spot-workloads) | 1-2 uger |
| ResourceQuotas + governance | 10-15% | 1 uge |
| Samlet (kombineret) | 40-70% | 8-10 uger |
Besparelserne akkumulerer, og det er det fine ved den her tilgang: right-sizing reducerer compute-behovet, bedre autoscaling sikrer at du kun kører det nødvendige, Karpenter finder de billigste noder, og Spot giver rabat oveni. Samlet set er det en ganske betydelig forskel på den månedlige regning.
FAQ: Ofte stillede spørgsmål om Kubernetes-omkostningsoptimering
Hvad er den hurtigste måde at reducere Kubernetes-omkostninger på?
Den hurtigste enkelthandling er at right-size dine pods. Deploy VPA i anbefalingstilstand (updateMode: Off), vent 5-7 dage, og anvend derefter Target-anbefalingerne. De fleste organisationer opdager, at deres pods er overallokeret med 2-3x, og right-sizing alene kan reducere compute-omkostningerne med 20-35% på ganske få uger.
Kan jeg bruge VPA og HPA samtidig?
Ja, men med forsigtighed. Du skal undgå at lade begge autoscalere reagere på de samme metrics. Den anbefalede tilgang er at bruge VPA til at justere CPU- og hukommelsesanmodninger, mens HPA skalerer baseret på custom metrics eller eksterne metrics (f.eks. antal HTTP-anmodninger eller kølængde). KEDA er et godt alternativ til HPA, der nativt understøtter eksterne metrics.
Er Karpenter bedre end Cluster Autoscaler?
For de fleste AWS-klynger — ja, uden tvivl. Karpenter provisionerer noder hurtigere (under et minut mod flere minutter for CA), vælger automatisk optimale instanstyper uden foruddefinerede nodegrupper, og inkluderer konsolideringsfunktioner der løbende optimerer node-udnyttelse. Karpenter reducerer typisk omkostningerne med 10-20% sammenlignet med Cluster Autoscaler. Bemærk dog, at Karpenter primært er designet til AWS EKS — til Azure AKS og GCP GKE er der tilsvarende løsninger som AKS Node Autopilot og GKE Autopilot.
Hvor mange instanstyper bør jeg inkludere i en Karpenter NodePool med Spot?
Mindst 15 instanstyper. Det lyder af meget, men Karpenters Spot-til-Spot-konsolidering kræver bred diversificering for at fungere ordentligt. Jo flere instanstyper du tillader, desto bedre kan Karpenter finde billige alternativer og reducere risikoen for Spot-afbrydelser. Inkluder en blanding af instansfamilier (m6i, m6a, c6i, r6i osv.) og størrelser.
Hvad koster det at implementere disse optimeringer?
De fleste værktøjer er open source og gratis: VPA, HPA, KEDA, Karpenter, Kubecost (gratis tier), Prometheus og Grafana. Den primære omkostning er ingeniørtid — typisk 8-10 uger for en komplet implementering. Men med besparelser på 40-70% af Kubernetes-regningen betaler investeringen sig normalt tilbage inden for den første måned. Det er en ret god ROI, hvis du spørger mig.