- Authors

- Name
- Phillip Pham
- @ddppham
Apache Airflow auf Kubernetes: ETL-Kosten mit dem KubernetesExecutor halbieren
TL;DR
- Der KubernetesExecutor startet pro Airflow-Task einen eigenen Pod und beendet ihn danach -- keine idle Worker mehr
- Gegenueber statischen VMs spart dynamische Worker-Allokation typischerweise 40-60% Infrastrukturkosten
- Das offizielle Airflow Helm Chart macht das Setup reproduzierbar und produktionsreif in wenigen Stunden
- Resource Requests und Limits pro Task-Pod sind der wichtigste Hebel fuer Kostenoptimierung
- Git-Sync fuer DAGs plus CI/CD ergibt einen sauberen Deployment-Workflow ohne manuelle Eingriffe
Das Problem: Statische ETL-Infrastruktur ist teuer
Viele Teams betreiben ihre Airflow-Worker auf dedizierten VMs oder festen Kubernetes-Deployments mit einer statischen Replica-Anzahl. Das fuehrt zu einem bekannten Muster: Die Infrastruktur ist fuer Spitzenlasten dimensioniert, laeuft aber 80% der Zeit mit 20% Auslastung.
Ein typisches Setup mit drei VMs (Scheduler, Webserver, Worker-Pool) kostet bei einem Cloud-Provider schnell 600-900 Euro pro Monat. Davon entfallen rund zwei Drittel auf die Worker, die nur waehrend der tatsaechlichen DAG-Ausfuehrung Arbeit verrichten.
Der KubernetesExecutor loest genau dieses Problem. Statt einen permanenten Worker-Pool vorzuhalten, wird fuer jede einzelne Task ein eigener Pod gestartet. Sobald die Task abgeschlossen ist, wird der Pod wieder entfernt. Die Abrechnung erfolgt damit nur fuer tatsaechlich genutzte Compute-Zeit.
Architektur: Wie der KubernetesExecutor funktioniert
Beim KubernetesExecutor kommuniziert der Airflow Scheduler direkt mit der Kubernetes API. Fuer jede Task, die zur Ausfuehrung ansteht, erstellt der Scheduler einen Pod mit dem passenden Container-Image und den definierten Resource Requests.
Die Architektur besteht aus vier Kernkomponenten:
- Scheduler -- laeuft als Deployment mit 1-2 Replicas, ueberwacht DAGs und erstellt Task-Pods
- Webserver -- stellt die Airflow-UI bereit, ebenfalls als Deployment
- Metadata-DB -- PostgreSQL als StatefulSet oder Managed Service
- Task-Pods -- werden on-demand vom Scheduler erstellt und nach Abschluss geloescht
Der entscheidende Unterschied zum CeleryExecutor: Es gibt keinen permanenten Worker-Pool und keinen Message Broker (Redis/RabbitMQ). Das vereinfacht die Architektur und reduziert die Betriebskosten weiter.
Setup: Airflow mit Helm deployen
Das offizielle Apache Airflow Helm Chart ist der schnellste Weg zu einem produktionsreifen Setup. Hier eine minimale values.yaml fuer den KubernetesExecutor:
# values-airflow.yaml
executor: KubernetesExecutor
webserver:
replicas: 1
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: 500m
memory: 1Gi
scheduler:
replicas: 1
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: "1"
memory: 2Gi
# Worker-Ressourcen gelten als Default fuer Task-Pods
workers:
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: "1"
memory: 1Gi
# DAGs via Git-Sync statt PersistentVolume
dags:
gitSync:
enabled: true
repo: "git@github.com:your-org/airflow-dags.git"
branch: main
subPath: "dags"
# Metadaten-DB
postgresql:
enabled: true
persistence:
size: 10Gi
# Kein Redis noetig beim KubernetesExecutor
redis:
enabled: false
Installation mit Helm:
helm repo add apache-airflow https://airflow.apache.org
helm repo update
kubectl create namespace airflow
helm install airflow apache-airflow/airflow \
--namespace airflow \
--values values-airflow.yaml \
--version 1.13.1 \
--timeout 10m
Nach wenigen Minuten laeuft der Airflow-Stack. Der Webserver ist ueber einen Kubernetes Service erreichbar, und der Scheduler beginnt sofort, DAGs aus dem konfigurierten Git-Repository zu laden.
Task-Level Resource Tuning
Der groesste Kostenhebel liegt im Tuning der Resource Requests und Limits pro Task. Statt einen globalen Default zu verwenden, koennen individuelle Tasks ihre eigenen Ressourcen definieren. Das verhindert, dass ein leichtgewichtiger API-Call genauso viel Compute reserviert wie ein schweres Datenbank-Export.
In einem DAG sieht das so aus:
from airflow import DAG
from airflow.providers.cncf.kubernetes.operators.pod import KubernetesPodOperator
from kubernetes.client import models as k8s
from datetime import datetime
with DAG(
dag_id="etl_pipeline",
start_date=datetime(2026, 1, 1),
schedule_interval="@daily",
catchup=False,
) as dag:
# Leichtgewichtiger Task: API-Call, wenig Ressourcen
extract = KubernetesPodOperator(
task_id="extract_api_data",
image="your-registry/etl-extract:latest",
namespace="airflow",
container_resources=k8s.V1ResourceRequirements(
requests={"cpu": "100m", "memory": "128Mi"},
limits={"cpu": "250m", "memory": "256Mi"},
),
)
# Schwerer Task: Daten-Transformation mit Pandas
transform = KubernetesPodOperator(
task_id="transform_data",
image="your-registry/etl-transform:latest",
namespace="airflow",
container_resources=k8s.V1ResourceRequirements(
requests={"cpu": "500m", "memory": "1Gi"},
limits={"cpu": "2", "memory": "4Gi"},
),
)
# Mittlerer Task: Ergebnisse in Data Warehouse laden
load = KubernetesPodOperator(
task_id="load_to_warehouse",
image="your-registry/etl-load:latest",
namespace="airflow",
container_resources=k8s.V1ResourceRequirements(
requests={"cpu": "200m", "memory": "256Mi"},
limits={"cpu": "500m", "memory": "512Mi"},
),
)
extract >> transform >> load
Durch diese Differenzierung nutzt der Extract-Task nur ein Zehntel der Ressourcen des Transform-Tasks. Bei einem DAG mit 20+ Tasks summiert sich das schnell zu erheblichen Einsparungen.
Kostenvergleich: Statisch vs. KubernetesExecutor
Die folgende Tabelle zeigt einen realistischen Vergleich fuer ein mittelstaendisches Unternehmen mit ca. 15 DAGs und insgesamt 80 Tasks pro Tag.
| Kostenfaktor | Statische VMs (3x) | KubernetesExecutor |
|---|---|---|
| Scheduler + Webserver | 200 EUR/Monat | 150 EUR/Monat |
| Worker-Compute | 450 EUR/Monat (24/7) | 120-180 EUR/Monat (on-demand) |
| Message Broker (Redis) | 50 EUR/Monat | entfaellt |
| Metadata-DB (Managed) | 80 EUR/Monat | 80 EUR/Monat |
| Ops-Aufwand (Stunden/Monat) | 15h | 5h |
| Gesamt Infrastruktur | 780 EUR/Monat | 350-410 EUR/Monat |
Die Ersparnis liegt bei rund 50%. Der groesste Posten ist der Worker-Compute, weil die Task-Pods nur waehrend der tatsaechlichen Ausfuehrung existieren. Bei den meisten ETL-Workloads bedeutet das: 2-4 Stunden aktive Compute-Zeit statt 24 Stunden Bereitschaft.
Monitoring: Resource-Verbrauch sichtbar machen
Ohne Monitoring ist Kostenoptimierung Blindflug. Zwei Dinge sind wichtig: die Airflow-eigenen Metriken und die Kubernetes-Ressourcennutzung der Task-Pods.
Airflow exportiert StatsD-Metriken, die Prometheus ueber einen StatsD-Exporter scrapen kann. Die wichtigsten Metriken fuer Kostenoptimierung:
scheduler.tasks.running-- Anzahl gleichzeitig laufender Task-Podsdag_processing.total_parse_time-- Parse-Zeit, die den Scheduler belastetti.finish.<dag_id>.<task_id>.success-- Task-Laufzeiten pro Task
Auf der Kubernetes-Seite sind kubectl top pods -n airflow und ein Grafana-Dashboard mit CPU/Memory-Auslastung pro Pod die Basis. Wer es detaillierter braucht, kann sich unseren Artikel zu Kubernetes Monitoring und Kosten ansehen.
Ein haeufiger Fehler: Resource Requests zu hoch setzen. Wenn ein Task 200Mi Memory braucht, aber 2Gi reserviert, blockiert er Cluster-Kapazitaet fuer andere Workloads. Das fuehrt zu unnoetigem Node-Autoscaling und damit hoeheren Kosten. Die Faustregel: Requests auf den 95. Perzentil der tatsaechlichen Nutzung setzen, Limits 50-100% darueber.
DAG-Deployment mit Git-Sync
Der Git-Sync-Sidecar im Helm Chart ist die sauberste Loesung fuer DAG-Deployment. Er pollt ein Git-Repository in konfigurierbaren Intervallen und synchronisiert die DAG-Dateien in das Airflow-Verzeichnis.
Der Workflow:
- Entwickler pusht DAG-Aenderung in einen Feature-Branch
- CI-Pipeline fuehrt
airflow dags testund Linting aus - Nach Merge in
mainpickt der Git-Sync die Aenderung automatisch auf - Scheduler erkennt den neuen DAG beim naechsten Parse-Zyklus
Das eliminiert manuelle Deployments und macht DAG-Aenderungen nachvollziehbar. In Kombination mit GitOps-Workflows entsteht eine durchgaengige Deployment-Pipeline.
Haeufige Fehler und wie man sie vermeidet
Pod-Startup-Latenz unterschaetzen. Jeder Task-Pod muss gestartet werden, was 10-30 Sekunden dauert. Bei Tasks, die selbst nur 5 Sekunden laufen, dominiert der Startup-Overhead. Loesung: Kurzlaufende Tasks zusammenfassen oder den CeleryKubernetesExecutor fuer gemischte Workloads verwenden.
Keine Pod-Templates nutzen. Ohne Pod-Templates erben alle Tasks die gleichen Defaults. Mit pod_template_file oder pod_override in der Task-Definition lassen sich individuelle Tolerations, Node Selectors und Volumes konfigurieren. Das ist relevant, wenn bestimmte Tasks auf Spot-Nodes laufen sollen.
Image-Pull-Zeiten ignorieren. Grosse Container-Images (2GB+) verursachen lange Pull-Zeiten, besonders wenn der Node das Image noch nicht gecacht hat. Loesung: Schlanke Base-Images verwenden, Multi-Stage-Builds, und eine private Registry im selben Netzwerk betreiben.
Kein Namespace-Isolation. Airflow-Task-Pods sollten in einem dedizierten Namespace laufen, mit ResourceQuotas und LimitRanges. Das verhindert, dass ein fehlerhafter DAG den gesamten Cluster in die Knie zwingt. Mehr dazu unter Namespace-Management.
Wann der KubernetesExecutor nicht passt
Der KubernetesExecutor ist nicht fuer jeden Anwendungsfall optimal. Bei sehr kurzen Tasks (unter 10 Sekunden) oder extrem hoher Task-Frequenz (tausende Tasks pro Minute) wird der Pod-Startup-Overhead zum Bottleneck.
In solchen Faellen ist der CeleryKubernetesExecutor die bessere Wahl. Er kombiniert einen Celery-Worker-Pool fuer schnelle Standardtasks mit der Moeglichkeit, rechenintensive Tasks als Kubernetes-Pods auszulagern. Der Trade-off: hoehere Komplexitaet (Redis/RabbitMQ noetig) und ein permanenter Worker-Pool, der Grundkosten verursacht.
| Kriterium | KubernetesExecutor | CeleryKubernetesExecutor |
|---|---|---|
| Task-Startup-Latenz | 10-30 Sekunden | unter 1 Sekunde (Celery) |
| Idle-Kosten | keine | Worker-Pool laeuft dauerhaft |
| Infrastruktur-Komplexitaet | niedrig | mittel (Redis/RabbitMQ) |
| Bester Einsatz | Batch-ETL, ML-Pipelines | Mixed Workloads, hohe Frequenz |
| Skalierung | pro Task | Worker-Pool + pro Task |
Security-Basics fuer Airflow auf Kubernetes
ETL-Pipelines verarbeiten haeufig sensible Daten. Ein paar nicht-verhandelbare Security-Massnahmen:
- Secrets nicht in DAG-Code. Airflow Connections und Variables nutzen, oder besser: einen externen Secret Store wie HashiCorp Vault mit dem Airflow Secrets Backend.
- Network Policies. Task-Pods sollten nur auf die Datenquellen zugreifen koennen, die sie tatsaechlich brauchen. Default-Deny plus explizite Whitelists.
- RBAC im Cluster. Der Airflow ServiceAccount sollte nur Pods im eigenen Namespace erstellen und loeschen duerfen -- nicht clusterweite Rechte haben.
- Image Scanning. Alle Task-Images vor dem Push in die Registry mit Trivy oder Grype scannen. Das laesst sich in die CI/CD-Pipeline integrieren.
Wer tiefer einsteigen will, findet in unserem Artikel zu Kubernetes Security Hardening weitere Best Practices.
Fazit und naechste Schritte
Der KubernetesExecutor ist der effizienteste Weg, Apache Airflow fuer Batch-ETL-Workloads zu betreiben. Die dynamische Pod-Allokation eliminiert Idle-Kosten, und das Helm Chart macht das initiale Setup unkompliziert. Der Schluessel zur tatsaechlichen Kostenreduktion liegt im konsequenten Resource Tuning pro Task und im Monitoring der realen Auslastung.
Fuer den Einstieg empfehle ich:
- Ein Staging-Cluster mit dem Airflow Helm Chart aufsetzen
- Zwei bis drei bestehende DAGs migrieren und die Resource-Nutzung messen
- Basierend auf den Messwerten Requests und Limits optimieren
- Nach 2-4 Wochen die Kosten mit dem bisherigen Setup vergleichen
Wenn Sie Unterstuetzung bei der Migration oder beim Aufbau einer kosteneffizienten Airflow-Plattform auf Kubernetes benoetigen, koennen Sie sich gerne bei uns melden.
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
Airflow auf Kubernetes: Data Pipelines optimieren
Apache Airflow auf Kubernetes beschleunigt Data Pipelines um das Dreifache bei 78 Prozent weniger Compute-Kosten dank Auto-Scaling und dynamischer Worker.
Cluster Autoscaler: Kubernetes-Nodes optimal skalieren
Cluster Autoscaler optimieren mit Expander-Strategien, Scale-Down-Tuning und Priority-Konfiguration für kosteneffiziente Node-Skalierung.
Kubernetes Cloud-Kosten senken: FinOps und Right-Sizing
Kubernetes Cloud-Kosten um 45% senken: Right-Sizing, Spot Instances, Autoscaling und FinOps-Prozesse mit Kubecost für nachhaltige Einsparungen.
Kubernetes E-Commerce: Black Friday Autoscaling richtig
Kubernetes für Black Friday konfigurieren: HPA mit Custom Metrics, Scheduled Scaling vor Peak-Events und Kostenoptimierung in der Nebensaison.
Kubernetes Monitoring-Kosten um 60% senken
Kubernetes-Monitoring-Kosten mit Prometheus statt Datadog um 60% senken durch Retention-Optimierung, Downsampling und Alert-Fatigue-Reduktion.