FinOps voor Kubernetes: rightsizing, spotinstances en kostenreductie
68% van de organisaties die Kubernetes in productie gebruiken, geven 20-40% meer uit dan nodig is (CNCF Kostenonderzoek 2026). Niet omdat Kubernetes inefficiënt is, maar omdat genereuze en gemakkelijke bevoorrading, en het rechtvaardigen van de omvang ervan vereist operationele discipline. De resultaat en cluster met gemiddeld CPU-gebruik van 15-20% en geheugen van 30-40%: bronnen betaald maar gebruik het niet.
FinOps voor Kubernetes en de praktijk van meten, optimaliseren en besturen clusteruitgaven. In dit artikel zullen we zien hoe te gebruiken Kubecost voor de zichtbaarheid van de kosten voor naamruimten, zoals de VPA helpt bij het op orde brengen automatische verzoeken, hoe Karpenter optimaliseert de bin-packing van knooppunten met spotinstances en welk beleid er op organisatieniveau moet worden geïmplementeerd om de kosten op peil te houden onder controle in de loop van de tijd.
Wat je gaat leren
- Installeer en configureer Kubecost voor zichtbaarheid van naamruimte/teamkosten
- VPA in Uit-modus: automatische aanbevelingen voor het aanpassen van de rechten zonder onderbrekingen
- Karpenter: Consolidatie voor optimale bin-packing van knooppunten
- Ontdek instanties op AWS/GCP/Azure met Karpenter en onderbreek beheer
- ResourceQuota als tool voor teambudgettering
- Waarschuw Prometheus voor afwijkingen op het gebied van verspilling en kosten
- Hoe u een terugboekingssysteem voor teams kunt bouwen
- Benchmark: echte besparingen haalbaar met elke techniek
Waarom Kubernetes vaak overprovisioned is
Voordat u gaat optimaliseren, moet u de oorzaken van het probleem begrijpen:
- Conservatieve verzoeken: Teams stellen de verzoeken hoog "om veilig te zijn" (bijvoorbeeld 1 CPU voor een app die 0,1 gebruikt). Verzoeken bepalen het aantal benodigde knooppunten
- Limieten = verzoeken: Veel CI/CD-sjablonen stellen limieten in die gelijk zijn aan verzoeken, waardoor systematische overprovisioning ontstaat
- Lege naamruimten: Ontwikkelingsnaamruimte met "Hello World"-pods die 24/7 aan blijven
- Extra grote knopen: Grote cloudinstanties met inefficiënte bin-packing (een pod met 2 vCPU's op een knooppunt met 32 vCPU's)
- Geen zichtbaarheid voor teams: Als teams hun kosten niet zien, hebben ze geen prikkel om te optimaliseren
Kubecost: zichtbaarheid van naamruimtekosten
Kubecost Het is de meest gebruikte FinOps-tool in het Kubernetes-ecosysteem. Verzamelt statistieken van Prometheus, haalt prijzen van cloudinstanties op (AWS, GCP, Azure) en bereken de kosten die zijn toegewezen voor naamruimte, implementatie, serviceaccount en label.
Kubecost-installatie
# Installa Kubecost con Helm
helm repo add kubecost https://kubecost.github.io/cost-analyzer/
helm repo update
helm install kubecost kubecost/cost-analyzer \
--namespace kubecost \
--create-namespace \
--set kubecostToken="your-token-here" \
--set prometheus.enabled=true \
--set grafana.enabled=true \
--set global.prometheus.enabled=false \
--set global.prometheus.fqdn="http://prometheus.monitoring.svc:9090"
# Port-forward per accedere alla UI
kubectl port-forward svc/kubecost-cost-analyzer 9090:9090 -n kubecost &
# Apri: http://localhost:9090
# Alternativa open-source senza token: OpenCost
helm install opencost opencost/opencost \
--namespace opencost \
--create-namespace
Configureer terugvordering voor teams
# Kubecost usa i label Kubernetes per il cost allocation
# Configura label standard per tutti i workload:
# Nel values.yaml di ogni applicazione (Helm):
podLabels:
team: "team-alpha"
cost-center: "CC-2024-ENG"
environment: "production"
product: "checkout-service"
# Kubecost mostra automaticamente i costi aggregati per questi label.
# Es: costo totale team-alpha nel mese = CPU + Memoria + Storage + GPU + Networking
# API Kubecost per report automatici (da inviare via email settimanale):
curl "http://kubecost:9090/model/allocation?window=7d&aggregate=label:team&accumulate=true" \
| jq '.data[0] | to_entries[] | {team: .key, cost: .value.totalCost}'
VPA voor automatische rechtenaanpassing
Il Verticale Pod Autoscaler (VPA) analyseert het historische CPU-verbruik en
Pod-geheugen en berekent optimale verzoeken. In modus Off (aanbeveling
zonder automatische toepassing) is het veiligste hulpmiddel voor rightsizing: het biedt
nauwkeurige cijfers zonder risico op verstoring.
# Installa VPA
git clone https://github.com/kubernetes/autoscaler.git
cd autoscaler/vertical-pod-autoscaler
./hack/vpa-up.sh
# Oppure con Helm
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
helm install vpa fairwinds-stable/vpa \
--namespace vpa \
--create-namespace
---
# vpa-recommendation.yaml - modalita Off: solo raccomandazioni
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: api-service-vpa
namespace: team-alpha
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: api-service
updatePolicy:
updateMode: "Off" # non applica automaticamente, solo raccomanda
resourcePolicy:
containerPolicies:
- containerName: api
minAllowed:
cpu: 50m
memory: 64Mi
maxAllowed:
cpu: "4"
memory: 8Gi
# Leggi le raccomandazioni dopo 24-48 ore:
kubectl describe vpa api-service-vpa -n team-alpha
# Output:
# Container Recommendations:
# Container Name: api
# Lower Bound:
# Cpu: 120m
# Memory: 256Mi
# Target: <-- usa questi valori nelle requests
# Cpu: 250m
# Memory: 512Mi
# Upper Bound:
# Cpu: 800m
# Memory: 1500Mi
# Uncapped Target:
# Cpu: 230m
# Memory: 480Mi
Script voor analyse van de juiste grootte in bulk
# Trova tutti i Deployment con requests > 2x il consumo reale
kubectl get vpa -A -o json | jq -r '
.items[] |
.metadata.namespace + "/" + .metadata.name + ": " +
(.status.recommendation.containerRecommendations[]? |
"target CPU=" + .target.cpu + " Mem=" + .target.memory)
'
# Script bash per generare report di rightsizing
#!/bin/bash
echo "=== Rightsizing Recommendations ==="
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
echo "--- Namespace: $ns ---"
kubectl get vpa -n "$ns" -o custom-columns=\
"NAME:.metadata.name,\
TARGET-CPU:.status.recommendation.containerRecommendations[0].target.cpu,\
TARGET-MEM:.status.recommendation.containerRecommendations[0].target.memory" \
2>/dev/null
done
Karpenter: Consolidatie en Spot-instanties
Karpenter optimaliseert de kosten vanuit twee richtingen: gebruik exemplaren spotten voor de kosten per knooppunt met 60-70% verlagen, bijv consolideer de knooppunten verwijderen die onderbenut worden (bin-packing).
NodePool met Spot + Consolidatie
# karpenter-cost-optimized.yaml
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: cost-optimized
spec:
template:
spec:
nodeClassRef:
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
name: default
requirements:
# Tipi di istanza ottimali per bin-packing (diverse size)
- key: node.kubernetes.io/instance-type
operator: In
values:
- m7i.xlarge # 4 vCPU, 16GB ~$0.20/h on-demand, ~$0.05/h spot
- m7i.2xlarge # 8 vCPU, 32GB
- m7i.4xlarge # 16 vCPU, 64GB
- m7i.8xlarge # 32 vCPU, 128GB
- c7i.2xlarge # CPU-optimized per workload compute-intensive
- r7i.2xlarge # Memory-optimized per carichi con alta RAM
# Mix spot e on-demand con peso
- key: karpenter.sh/capacity-type
operator: In
values:
- spot # priorita spot (economico)
- on-demand # fallback on-demand
disruption:
consolidationPolicy: WhenUnderutilized
consolidateAfter: 1m # consolida subito i nodi sottoutilizzati
limits:
cpu: "1000" # max 1000 vCPU totali
memory: "4000Gi" # max 4TB RAM totale
---
# Configurazione spot interruption handler
# Necessario per gestire le interruzioni spot (AWS invia 2 min di preavviso)
helm install aws-node-termination-handler \
eks/aws-node-termination-handler \
--namespace kube-system \
--set enableSqsTerminationDraining=true \
--set queueURL=https://sqs.eu-west-1.amazonaws.com/123456789/NodeTerminationHandler
Besparingenanalyse met Karpenter
# Verifica quale percentuale dei nodi sono spot
kubectl get nodes -o json | jq '
[.items[] |
{type: .metadata.labels["karpenter.sh/capacity-type"],
instance: .metadata.labels["node.kubernetes.io/instance-type"]}
] |
group_by(.type) |
map({type: .[0].type, count: length})'
# Output esempio:
# [{"type": "on-demand", "count": 3}, {"type": "spot", "count": 12}]
# 80% dei nodi sono spot -> risparmio medio 65% = -$2400/mese
# Kubecost: visualizza costo spot vs on-demand storicamente
# Vai in Cost Allocation > Filter by node type
Naamruimtebudget: ResourceQuota als FinOps-tool
ResourceQuota's zijn niet alleen bedoeld voor technische isolatie; ze zijn ook een hulpmiddel van financieel bestuur. Door quota toe te kennen op basis van budgetten creëer je een systeem van prikkels die teams ertoe aanzetten te optimaliseren:
# budget-quota-team.yaml
# Calcola le quote basandoti sul budget mensile del team
# Budget: 500 EUR/mese (circa 1500 CPU-hours a 0.033 EUR/CPU-hour)
# Assumendo utilizzo medio 50%: requests max = 2000 CPU-hours / 720 ore = 2.8 vCPU mean
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-alpha-budget-quota
namespace: team-alpha
annotations:
finops/monthly-budget-eur: "500"
finops/last-reviewed: "2026-01-15"
finops/owner: "alice@company.com"
spec:
hard:
# Basato su budget EUR/mese
requests.cpu: "6" # ~500 EUR/mese a tasso medio spot
requests.memory: "12Gi" # proporzionale
requests.storage: "200Gi"
---
# Alert quando il team si avvicina al budget
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: finops-budget-alerts
namespace: monitoring
spec:
groups:
- name: finops
rules:
- alert: TeamBudgetUsageHigh
expr: |
kubecost_namespace_allocation_cpu_cost_hourly * 24 * 30 +
kubecost_namespace_allocation_memory_cost_hourly * 24 * 30 > 400
for: 1h
labels:
severity: warning
annotations:
summary: "Team {{ $labels.namespace }}: costo mensile proiettato > 400 EUR"
Besparingsstrategieën voor verschillende werklasten
| Type werkbelasting | Strategie | Verwachte besparingen |
|---|---|---|
| Web-API (staatloos) | Spot + HPA + rechten op VPA | 50-65% |
| ML-batchtaken | Spot + controlepunt + schaal naar nul | 60-70% |
| Databases (stateful) | Op aanvraag gereserveerd + rechten aanpassen | 20-30% |
| CI/CD-lopers | Spot + schaal-naar-nul (KEDA) | 70-80% |
| Essentiële diensten 24/7 | Gereserveerde instanties + rechten aanpassen | 30-40% |
CI/CD-taakoptimalisatie met KEDA + Spot
# Runners CI/CD sono idle la maggior parte del tempo:
# scala a 0 quando non ci sono job, usa spot
# KEDA ScaledJob per runner GitHub Actions
apiVersion: keda.sh/v1alpha1
kind: ScaledJob
metadata:
name: github-actions-runner
namespace: actions-runners
spec:
jobTargetRef:
template:
spec:
containers:
- name: runner
image: summerwind/actions-runner:latest
resources:
limits:
cpu: "2"
memory: "4Gi"
nodeSelector:
karpenter.sh/capacity-type: spot # usa spot per runners
tolerations:
- key: "spot"
operator: "Exists"
effect: "NoSchedule"
pollingInterval: 30
minReplicaCount: 0 # scala a 0 quando nessun job
maxReplicaCount: 20 # massimo 20 runner paralleli
triggers:
- type: github-runner
metadata:
owner: "myorg"
repos: "myrepo"
targetWorkflowQueueLength: "1"
FinOps-dashboard met Grafana
# PromQL queries per dashboard FinOps Kubernetes
# Costo orario totale del cluster
sum(
kube_pod_container_resource_requests{resource="cpu"} * 0.033 +
kube_pod_container_resource_requests{resource="memory"} / 1073741824 * 0.004
) by (namespace)
# Efficienza CPU per namespace (utilizzo reale / requested)
sum(rate(container_cpu_usage_seconds_total[5m])) by (namespace) /
sum(kube_pod_container_resource_requests{resource="cpu"}) by (namespace) * 100
# Pod con requests molto piu alte del consumo reale (spreco > 70%)
(
kube_pod_container_resource_requests{resource="cpu"} -
rate(container_cpu_usage_seconds_total[24h])
) / kube_pod_container_resource_requests{resource="cpu"} > 0.7
# Importa il dashboard Grafana Kubecost: ID 11270
FinOps best practices voor Kubernetes
Maandelijkse FinOps-checklist
- Bekijk de VPA-aanbevelingen: Analyseer VPA-aanbevelingen en pas rechten toe op de top 10 van verspillingen
- Controleer inactieve knooppunten: Nodes met CPU- en geheugengebruik < 10% gedurende 24 uur moeten worden beëindigd (Karpenter doet dit automatisch)
- Controleer de spotdekking: Het doel is 70-80% van de niet-stateful knooppunten op spotinstanties
- Terugboekingsrapporten: Verstuur maandelijks kostenrapport per team via Kubecost API → e-mail of Slack
- ResourceQuota bekijken: Verhoog de quota alleen als er zakelijke redenen voor zijn, en niet standaard
- Schalen naar nul voor ontwikkelomgevingen: Ontwikkelomgevingen moeten buiten kantooruren worden afgesloten (-65% kosten)
Conclusies en volgende stappen
FinOps voor Kubernetes is geen eenmalige optimalisatie: het is een continu proces vereist zichtbaarheid (Kubecost), intelligente aanbevelingen (VPA), efficiënte provisioning (Karpenter met commercieel) en organisatorisch bestuur (ResourceQuota als budget). Implementeren al deze technieken samen realiseren organisaties doorgaans een besparing van 35-55% op uw Kubernetes-cloudfactuur in de eerste 3-6 maanden.
De volgende stap is het integreren van FinOps Kubernetes in de ontwikkelcyclus: de ontwikkelaars ze zouden de geschatte kosten van hun inzet moeten zien voordat ze in productie gaan – een "shift-left"-benadering toegepast op de kosten.







