Veröffentlicht am

Kubernetes Kosten pro Namespace mit OpenCost berechnen

Teilen:
Authors

Kubernetes Kosten pro Namespace mit OpenCost berechnen

TL;DR

OpenCost ist das Open-Source-Standardtool fuer Kubernetes Cost Allocation. Es berechnet Kosten pro Namespace, Label, Pod oder Controller basierend auf tatsaechlichem Ressourcenverbrauch. Installation per Helm in 5 Minuten, Grafana-Dashboard in 10 Minuten. CNCF Sandbox-Projekt.


"Was kostet unser Kubernetes-Cluster?" -- einfach zu beantworten. "Was kostet Team A im Vergleich zu Team B?" -- schon schwieriger. "Wer verursacht den 40%-Anstieg seit letztem Monat?" -- ohne Tooling unmoeglich. OpenCost loest genau dieses Problem.

Was OpenCost berechnet

OpenCost kombiniert zwei Datenquellen:

  1. Cloud-Provider-Preise: Node-Kosten (VM-Typ, Region, Spot/On-Demand), Persistent-Volume-Kosten, LoadBalancer-Kosten
  2. Kubernetes-Metriken: CPU- und Memory-Verbrauch pro Pod, via Prometheus/Metrics-Server

Daraus berechnet es stuendliche Kosten pro:

  • Namespace
  • Deployment / StatefulSet / DaemonSet
  • Pod
  • Label (beliebige Labels)
  • Cluster (bei Multi-Cluster)

Installation

Voraussetzungen

  • Kubernetes 1.25+
  • Prometheus (kube-prometheus-stack empfohlen)
  • Helm 3

OpenCost deployen

# Helm-Repo hinzufuegen
helm repo add opencost https://opencost.github.io/opencost-helm-chart
helm repo update

# OpenCost installieren
helm install opencost opencost/opencost \
  --namespace opencost --create-namespace \
  --set opencost.prometheus.internal.serviceName=prometheus-kube-prometheus-prometheus \
  --set opencost.prometheus.internal.namespaceName=monitoring \
  --set opencost.ui.enabled=true

# Pods pruefen
kubectl -n opencost get pods
# NAME                       READY   STATUS    RESTARTS   AGE
# opencost-5f4b8c7d9-k2l8m  2/2     Running   0          45s

Fuer Hetzner, Netcup oder andere Anbieter ohne native Cloud-Integration: Custom Pricing konfigurieren.

# Custom Pricing fuer Hetzner/On-Prem
cat <<EOF > custom-pricing.json
{
  "provider": "custom",
  "description": "Hetzner Cloud Pricing",
  "CPU": "0.0080",
  "RAM": "0.0040",
  "GPU": "0.95",
  "storage": "0.00005479",
  "spotCPU": "0.0040",
  "spotRAM": "0.0020",
  "zoneNetworkEgress": "0.00",
  "regionNetworkEgress": "0.00",
  "internetNetworkEgress": "0.01"
}
EOF

kubectl -n opencost create configmap custom-pricing \
  --from-file=default.json=custom-pricing.json

# Helm-Upgrade mit Custom Pricing
helm upgrade opencost opencost/opencost \
  --namespace opencost \
  --set opencost.customPricing.enabled=true \
  --set opencost.customPricing.configmapName=custom-pricing \
  --set opencost.prometheus.internal.serviceName=prometheus-kube-prometheus-prometheus \
  --set opencost.prometheus.internal.namespaceName=monitoring

Kosten abfragen

OpenCost API

# Port-Forward
kubectl -n opencost port-forward svc/opencost 9003:9003 &

# Kosten pro Namespace (letzte 24h)
curl -s "http://localhost:9003/allocation/compute?window=24h&aggregate=namespace" | jq '.data[0]' | jq 'to_entries[] | {namespace: .key, totalCost: .value.totalCost}'

# Beispiel-Ausgabe:
# {"namespace": "production", "totalCost": 12.45}
# {"namespace": "staging", "totalCost": 4.82}
# {"namespace": "monitoring", "totalCost": 3.21}
# {"namespace": "kube-system", "totalCost": 2.15}

# Kosten pro Label (z.B. team)
curl -s "http://localhost:9003/allocation/compute?window=7d&aggregate=label:team" | jq '.data[0]'

# Kosten pro Deployment im Namespace "production"
curl -s "http://localhost:9003/allocation/compute?window=24h&aggregate=controller&filter=namespace:production" | jq '.data[0]'

OpenCost UI

kubectl -n opencost port-forward svc/opencost 9090:9090
# Browser: http://localhost:9090

Die UI zeigt Kosten nach Namespace, Controller und Pod. Fuer tiefere Analysen und Dashboards lohnt sich die Grafana-Integration.

Grafana-Dashboard

Datenquelle: Prometheus

OpenCost exportiert Metriken nach Prometheus. Die wichtigsten:

# CPU-Kosten pro Namespace (stuendlich)
opencost_allocation_cpu_cost_total

# Memory-Kosten pro Namespace (stuendlich)
opencost_allocation_memory_cost_total

# PV-Kosten
opencost_allocation_pv_cost_total

# Gesamtkosten
opencost_allocation_total_cost_total

Dashboard erstellen

# Dashboard als ConfigMap fuer Grafana Sidecar
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  name: opencost-dashboard
  namespace: monitoring
  labels:
    grafana_dashboard: "1"
data:
  opencost-namespace.json: |
    {
      "dashboard": {
        "title": "Kubernetes Kosten pro Namespace",
        "panels": [
          {
            "title": "Monatliche Kosten pro Namespace",
            "type": "barchart",
            "targets": [
              {
                "expr": "sum(opencost_allocation_total_cost_total) by (namespace) * 730",
                "legendFormat": "{{namespace}}"
              }
            ]
          },
          {
            "title": "CPU-Kosten vs Memory-Kosten",
            "type": "timeseries",
            "targets": [
              {
                "expr": "sum(rate(opencost_allocation_cpu_cost_total[1h])) by (namespace)",
                "legendFormat": "CPU: {{namespace}}"
              },
              {
                "expr": "sum(rate(opencost_allocation_memory_cost_total[1h])) by (namespace)",
                "legendFormat": "Memory: {{namespace}}"
              }
            ]
          },
          {
            "title": "Top 10 teuerste Pods",
            "type": "table",
            "targets": [
              {
                "expr": "topk(10, sum(opencost_allocation_total_cost_total) by (pod, namespace)) * 730",
                "format": "table"
              }
            ]
          }
        ]
      }
    }
EOF

PromQL-Abfragen fuer Kosten-Reports

# Monatliche Gesamtkosten pro Namespace (hochgerechnet)
sum(opencost_allocation_total_cost_total) by (namespace) * 730

# Kostentrend: Woche-ueber-Woche pro Namespace
sum(increase(opencost_allocation_total_cost_total[7d])) by (namespace)

# Idle-Kosten (bezahlte aber ungenutzte Ressourcen)
sum(opencost_allocation_cpu_cost_total{container="__idle__"}) by (node) * 730

# Effizienz pro Namespace (genutzt vs. angefordert)
sum(opencost_allocation_cpu_cost_total{container!="__idle__"}) by (namespace)
/
sum(opencost_allocation_cpu_cost_total) by (namespace)

Cost Allocation Reports

Chargeback per Team

Voraussetzung: Jeder Namespace oder Pod hat ein Team-Label.

# Namespace mit Team-Label
apiVersion: v1
kind: Namespace
metadata:
  name: payment-service
  labels:
    team: backend
    cost-center: "4711"
    environment: production
# Monatliche Kosten pro Team
curl -s "http://localhost:9003/allocation/compute?window=30d&aggregate=label:team" \
  | jq '.data[0] | to_entries[] | {team: .key, cpu: .value.cpuCost, memory: .value.ramCost, total: .value.totalCost}'

# Ausgabe:
# {"team": "backend", "cpu": 45.20, "memory": 32.10, "total": 77.30}
# {"team": "data", "cpu": 120.50, "memory": 89.30, "total": 209.80}
# {"team": "platform", "cpu": 18.90, "memory": 15.40, "total": 34.30}

Automatischer Report per CronJob

apiVersion: batch/v1
kind: CronJob
metadata:
  name: cost-report
  namespace: opencost
spec:
  schedule: "0 8 1 * *"  # Jeden 1. des Monats um 8:00
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: reporter
            image: curlimages/curl:8.5.0
            command:
            - /bin/sh
            - -c
            - |
              REPORT=$(curl -s "http://opencost.opencost:9003/allocation/compute?window=30d&aggregate=namespace")
              # An Slack, E-Mail oder S3 senden
              curl -X POST -H 'Content-Type: application/json' \
                -d "{\"text\": \"Monatlicher Kubernetes-Kostenbericht: $REPORT\"}" \
                "$SLACK_WEBHOOK_URL"
            env:
            - name: SLACK_WEBHOOK_URL
              valueFrom:
                secretKeyRef:
                  name: slack-webhook
                  key: url
          restartPolicy: OnFailure

Idle Costs: Was niemand nutzt

OpenCost berechnet auch Idle Costs -- Ressourcen die bezahlt aber nicht genutzt werden. Das ist oft der groesste Hebel fuer Kostensenkung.

# Idle-Kosten abfragen
curl -s "http://localhost:9003/allocation/compute?window=7d&aggregate=namespace&includeIdle=true" \
  | jq '.data[0]["__idle__"]'

# Typisches Ergebnis:
# {
#   "cpuCost": 45.20,     <- bezahlte CPU die niemand nutzt
#   "ramCost": 32.80,     <- bezahlter RAM der leer steht
#   "totalCost": 78.00    <- pro Woche verschwendet
# }

Idle Costs entstehen durch:

  • Ueberdimensionierte Requests: Pods fordern 2 CPU an, nutzen 0,3
  • Zu viele Replicas: 5 Replicas fuer Traffic der 2 braucht
  • Fehlende Autoscaler: Cluster ist fuer Peak dimensioniert, Peak kommt selten
  • Vergessene Workloads: Staging-Deployments die seit Monaten laufen

OpenCost vs Kubecost vs Cloud-Provider-Tools

FeatureOpenCostKubecost FreeKubecost EnterpriseAWS Cost Explorer
Namespace-KostenJaJaJaNein (nur EC2)
Pod-Level-KostenJaJaJaNein
Custom PricingJaNeinJaNein
Multi-ClusterLimitiertNeinJaJa (nur AWS)
Savings-EmpfehlungenNeinJaJaJa
AlertingVia PrometheusEingebautEingebautCloudWatch
LizenzApache 2.0FreemiumKommerziellAWS-gebunden

OpenCost ist die Basis fuer Kubecost. Wer mehr als Kosten-Visibility braucht (Savings-Empfehlungen, Budgets, Governance), schaut sich Kubecost an. Fuer reine Cost Allocation reicht OpenCost.

Praxis-Tipps

Labels konsequent setzen

Ohne Labels keine sinnvolle Zuordnung. Mindestens:

metadata:
  labels:
    team: backend          # Wer zahlt
    cost-center: "4711"    # Controlling-ID
    environment: production  # Dev/Staging/Prod
    app: payment-api       # Was laeuft

Erzwingt Labels per OPA/Gatekeeper oder Kyverno:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-cost-labels
spec:
  validationFailureAction: Enforce
  rules:
  - name: check-labels
    match:
      any:
      - resources:
          kinds: ["Namespace"]
    validate:
      message: "Namespaces muessen ein 'team' und 'cost-center' Label haben."
      pattern:
        metadata:
          labels:
            team: "?*"
            cost-center: "?*"

Requests vs. tatsaechlicher Verbrauch

OpenCost kann auf Basis von Requests oder tatsaechlichem Verbrauch rechnen. Beides hat Berechtigung:

  • Requests-basiert (Chargeback): "Ihr habt 4 CPU reserviert, das kostet X" -- fair, weil reservierte Ressourcen andere blockieren
  • Usage-basiert (Showback): "Ihr habt 1,2 CPU tatsaechlich genutzt" -- zeigt Optimierungspotential
# Requests-basierte Kosten
curl -s "http://localhost:9003/allocation/compute?window=24h&aggregate=namespace"

# Usage-basierte Kosten (idle wird verteilt)
curl -s "http://localhost:9003/allocation/compute?window=24h&aggregate=namespace&shareIdle=weighted"

FAQ

Wie genau sind die Kosten-Berechnungen?

Bei Cloud-Providern mit nativer Integration (AWS, GCP, Azure): 95%+ Genauigkeit. Bei Custom Pricing (Hetzner, On-Prem): so genau wie eure Preiskonfiguration. Netzwerk-Egress und Shared Services (DNS, Ingress) werden gleichmaessig verteilt.

Funktioniert OpenCost auf On-Premise-Clustern?

Ja, mit Custom Pricing. Tragt eure tatsaechlichen Server-Kosten ein (Abschreibung pro Stunde, Strom, Hosting). Die Genauigkeit haengt von eurer Kostenrechnung ab.

Wie viel Overhead erzeugt OpenCost?

Minimal: ca. 100 MB RAM und 0,1 CPU-Cores. OpenCost liest nur Prometheus-Metriken und Cloud-Pricing-APIs. Es instrumentiert keine Pods.

Kann ich Kosten fuer einzelne Microservices berechnen?

Ja, ueber Labels. Setzt ein app-Label auf alle Pods eines Microservice und aggregiert per aggregate=label:app. Funktioniert auch namespace-uebergreifend.

Wie setze ich Budgets pro Namespace?

OpenCost selbst hat kein Budget-Feature. Nutzt Prometheus-Alerting: Wenn sum(opencost_allocation_total_cost_total{namespace="production"}) * 730 > 500, feuert ein Alert. Kubecost hat Budgets als eingebautes Feature.


Wollt ihr Kubernetes-Kosten transparent machen und Teams verantwortlich einbinden? Ich helfe bei der Einrichtung von OpenCost, Custom Pricing und FinOps-Prozessen -- vom ersten Dashboard bis zum monatlichen Chargeback-Report.


Weiterführende Artikel:

Kubernetes-Beratung gesucht?

Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.

📖 Verwandte Artikel

Weitere interessante Beiträge zu ähnlichen Themen

kubernetesopencost+1 weitere

OpenCost FinOps: Kubernetes-Kosten pro Team aufschlüsseln

Meistern Sie mit OpenCost 2026 die präzise Kostenallokation und Showback in Kubernetes für FinOps im Mittelstand. Dieser Guide zeigt DevOps-Teams, wie sie Cloud-Kosten transparent machen, Budgets überwachen und die Kubernetes Kostenoptimierung sowie Effizienz signifikant steigern – ideal als leistungsstarke Kubecost-Alternative.

Weiterlesen →