Kubernetes Cost Optimization: Jak ušetřit 40–60 % na cloud infrastruktuře v roce 2026¶
Kubernetes se stal standardem pro provoz enterprise aplikací. S tím ale přichází i výzva, kterou mnoho týmů podceňuje: náklady na cloud infrastrukturu rostou rychleji než produktivita. Průzkum CNCF 2026 ukazuje, že průměrná organizace přeplácí za Kubernetes infrastrukturu 35–50 % — a to pouze kvůli špatně nastaveným resource requests, nepoužívanému compute a absenci FinOps kultury.
Tento článek je praktický průvodce, jak tyto ztráty eliminovat.
Kde peníze mizí — anatomie Kubernetes waste¶
Over-provisioning resource requests¶
Největší zdroj plýtvání. Vývojáři konzervativně nastavují requests a limits, protože nikdo nechce, aby jim aplikace OOMkilloval. Výsledek: průměrné využití CPU v clusteru bývá 15–25 %, paměti 40–60 %.
# Typický "safe" setting od vývojáře
resources:
requests:
cpu: "500m" # Reálně aplikace používá 50m
memory: "512Mi" # Reálně 120Mi
limits:
cpu: "2000m"
memory: "2Gi"
Tento pod zabírá billing slot pro 500m CPU a 512Mi RAM — i když 90 % toho nikdy nevyužije.
Idle namespaces a zombie workloady¶
Development a staging prostředí běží 24/7, přestože jsou aktivní 8 hodin denně. Zapomenuté jobs, completed CronJobs s historií, staré ReplicaSets — to vše platíte.
Neoptimální instance typy¶
Spuštění memory-intensive workloadu na compute-optimized instanci (nebo naopak) — zaplatíte za kapacitu, kterou nemůžete využít.
Resource Optimization — konkrétní kroky¶
1. Goldilocks — automatický návrh resource requests¶
Goldilocks analyzuje skutečné využití přes VPA (Vertical Pod Autoscaler) a doporučuje správné hodnoty.
# Instalace
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
helm install goldilocks fairwinds-stable/goldilocks \
--namespace goldilocks \
--create-namespace
# Označit namespace pro analýzu
kubectl label namespace production goldilocks.fairwinds.com/enabled=true
# Goldilocks dashboard
kubectl -n goldilocks port-forward svc/goldilocks-dashboard 8080:80
Dashboard ukáže pro každý deployment doporučené requests/limits na základě skutečného P50/P99 využití za posledních N dní.
2. VPA (Vertical Pod Autoscaler) v recommendation mode¶
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: api-service-vpa
namespace: production
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: api-service
updatePolicy:
updateMode: "Off" # Jen doporučení, neaplikuje automaticky
resourcePolicy:
containerPolicies:
- containerName: api
minAllowed:
cpu: 50m
memory: 64Mi
maxAllowed:
cpu: 2000m
memory: 4Gi
controlledResources: ["cpu", "memory"]
# Zobrazit doporučení
kubectl describe vpa api-service-vpa -n production
# Hledejte: "Target" hodnoty pro cpu a memory
3. HPA s custom metrikami¶
Horizontal Pod Autoscaler na základě custom business metrik (ne jen CPU):
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-service-hpa
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api-service
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "100"
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # 5 min před scale-down
policies:
- type: Percent
value: 25
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
4. KEDA pro event-driven autoscaling¶
Pro workloady řízené frontami (Kafka, SQS, Redis):
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: worker-scaledobject
namespace: production
spec:
scaleTargetRef:
name: queue-worker
minReplicaCount: 0 # Scale to zero!
maxReplicaCount: 50
triggers:
- type: aws-sqs-queue
metadata:
queueURL: https://sqs.eu-west-1.amazonaws.com/123456789/my-queue
queueLength: "10" # 1 replica per 10 messages
awsRegion: eu-west-1
Scale-to-zero je klíčový — worker bez zpráv = 0 podů = 0 nákladů.
Node Optimization¶
Spot/Preemptible instances s Karpenter¶
Karpenter je moderní node autoscaler od AWS, který umí inteligentně mixovat spot a on-demand instance:
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
name: default
spec:
template:
spec:
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ["spot", "on-demand"]
- key: kubernetes.io/arch
operator: In
values: ["amd64", "arm64"] # ARM = levnější
- key: karpenter.k8s.aws/instance-category
operator: In
values: ["c", "m", "r"]
nodeClassRef:
name: default
disruption:
consolidationPolicy: WhenUnderutilized
consolidateAfter: 30s
limits:
cpu: 1000
memory: 4000Gi
Karpenter konsoliduje uzly automaticky — pokud 3 workloady sedí na 3 nodech, přepakuje je na 1 node a zbývající 2 vypne.
Pravidelné čištění idle nodů¶
#!/bin/bash
# Skript pro identifikaci nevyužitých nodů
kubectl get nodes -o json | jq -r '
.items[] |
select(.status.conditions[] | select(.type=="Ready" and .status=="True")) |
{
name: .metadata.name,
cpu_capacity: .status.capacity.cpu,
mem_capacity: .status.capacity.memory,
age: .metadata.creationTimestamp
}
' | jq -r '.name + " | CPU: " + .cpu_capacity + " | Age: " + .age'
# Zkontrolovat skutečné využití přes metrics-server
kubectl top nodes --sort-by=cpu | awk '$3+0 < 20 {print "LOW CPU:", $0}'
Namespace a Environment Cleanup¶
Automatické mazání development prostředí¶
#!/usr/bin/env python3
"""Auto-cleanup idle development namespaces"""
import subprocess
import json
from datetime import datetime, timezone, timedelta
def get_namespace_last_activity(namespace: str) -> datetime:
"""Zjistí poslední aktivitu v namespace podle events"""
result = subprocess.run(
["kubectl", "get", "events", "-n", namespace,
"--sort-by=.lastTimestamp", "-o", "json"],
capture_output=True, text=True
)
events = json.loads(result.stdout)
if not events["items"]:
return datetime.min.replace(tzinfo=timezone.utc)
last_event = events["items"][-1]
timestamp = last_event["lastTimestamp"]
return datetime.fromisoformat(timestamp.replace("Z", "+00:00"))
def cleanup_idle_namespaces(max_idle_hours: int = 48):
"""Smaže namespaces s prefixem 'dev-' které jsou idle více než N hodin"""
result = subprocess.run(
["kubectl", "get", "namespaces", "-o", "json"],
capture_output=True, text=True
)
namespaces = json.loads(result.stdout)
now = datetime.now(timezone.utc)
cutoff = now - timedelta(hours=max_idle_hours)
for ns in namespaces["items"]:
name = ns["metadata"]["name"]
if not name.startswith("dev-"):
continue
last_activity = get_namespace_last_activity(name)
if last_activity < cutoff:
idle_hours = (now - last_activity).total_seconds() / 3600
print(f"Deleting idle namespace {name} (idle {idle_hours:.0f}h)")
subprocess.run(["kubectl", "delete", "namespace", name])
if __name__ == "__main__":
cleanup_idle_namespaces(max_idle_hours=48)
CronJob pro noční scale-down¶
# Scale staging na 0 replik přes noc
apiVersion: batch/v1
kind: CronJob
metadata:
name: staging-scale-down
namespace: staging
spec:
schedule: "0 20 * * 1-5" # Pondělí-Pátek 20:00
jobTemplate:
spec:
template:
spec:
serviceAccountName: scaler-sa
containers:
- name: kubectl
image: bitnami/kubectl:latest
command:
- /bin/sh
- -c
- |
kubectl scale deployment --all --replicas=0 -n staging
kubectl scale statefulset --all --replicas=0 -n staging
restartPolicy: OnFailure
---
apiVersion: batch/v1
kind: CronJob
metadata:
name: staging-scale-up
namespace: staging
spec:
schedule: "0 8 * * 1-5" # Pondělí-Pátek 8:00
jobTemplate:
spec:
template:
spec:
serviceAccountName: scaler-sa
containers:
- name: kubectl
image: bitnami/kubectl:latest
command:
- /bin/sh
- -c
- |
kubectl scale deployment --all --replicas=2 -n staging
restartPolicy: OnFailure
FinOps — Kubecost a cost visibility¶
Kubecost pro granulární cost tracking¶
# Instalace Kubecost
helm repo add kubecost https://kubecost.github.io/cost-analyzer/
helm install kubecost kubecost/cost-analyzer \
--namespace kubecost \
--create-namespace \
--set kubecostToken="your-token" \
--set prometheus.server.persistentVolume.size=50Gi
Kubecost umožňuje vidět náklady per namespace, deployment, label nebo team — klíčové pro chargeback model.
Cost allocation labels¶
# Každý workload musí mít cost labels
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-service
labels:
app: api-service
team: backend # Tým
cost-center: "CC-1042" # Nákladové středisko
environment: production
product: core-platform
# Kubecost query per team
curl "http://kubecost/model/allocation?window=30d&aggregate=label:team&idle=true" | \
jq '.data[0] | to_entries | sort_by(-.value.totalCost) |
.[] | "\(.key): $\(.value.totalCost | round)"'
Výsledky — reálné čísla¶
Po implementaci těchto opatření v typickém enterprise clusteru:
| Optimalizace | Typická úspora |
|---|---|
| Right-sizing requests (Goldilocks) | 20–30 % |
| Spot instances (70 % workloadů) | 60–70 % na compute |
| Scale-to-zero pro dev/staging | 40–60 % na nonprod |
| Karpenter konsolidace | 10–20 % |
| Cleanup idle resources | 5–15 % |
| Celkem | 40–60 % celkových nákladů |
Implementační plán¶
Týden 1–2: Viditelnost - Nasadit Kubecost nebo OpenCost - Přidat cost allocation labels na všechny workloady - Audit resource utilization přes Goldilocks
Týden 3–4: Quick wins - Right-size top 20 nejvíce over-provisioned deploymentů - Zapnout scale-to-zero pro dev/staging přes noc - Vyčistit zombie workloady
Měsíc 2: Automatizace - Karpenter nebo Cluster Autoscaler s spot pool - HPA/KEDA pro klíčové services - Automatický namespace cleanup
Měsíc 3+: FinOps kultura - Chargeback reporty per team - Cost budgets a alerting - Kvartální review s development týmy
Závěr¶
Kubernetes cost optimization není jednorázová akce — je to kontinuální proces. Začněte viditelností (Kubecost), pokračujte right-sizingem (Goldilocks + VPA), a automatizujte škálování (HPA, KEDA, Karpenter). Výsledkem je infrastruktura, která roste s vašimi potřebami, ne navzdory nim.
CORE SYSTEMS pomáhá enterprise organizacím implementovat FinOps kulturu a Kubernetes cost governance. Kontaktujte nás pro audit vaší infrastruktury.
Brauchen Sie Hilfe bei der Implementierung?
Unsere Experten helfen Ihnen bei Design, Implementierung und Betrieb. Von der Architektur bis zur Produktion.
Kontaktieren Sie uns