- Authors

- Name
- Phillip Pham
- @ddppham
TL;DR
- Argo Workflows ist ein Container-nativer Workflow-Engine fuer Kubernetes, der komplexe DAG- und Step-basierte Pipelines als YAML definiert
- ML-Pipelines (Data Prep, Training, Evaluation, Deploy) lassen sich als DAG mit parallelen und abhaengigen Schritten modellieren
- CI/CD-Pipelines profitieren von nativer Kubernetes-Integration: Jeder Schritt laeuft als eigener Pod mit eigenem Image
- Artifacts (S3/MinIO), Parameter-Passing und WorkflowTemplates ermoeglichen wiederverwendbare, modulare Pipeline-Bausteine
- Das integrierte UI und Prometheus-Metriken geben Echtzeit-Einblick in laufende und abgeschlossene Workflows
Argo Workflows: ML-Pipelines und CI/CD auf Kubernetes orchestrieren
Argo Workflows ist ein Open-Source Workflow-Engine, der direkt auf Kubernetes laeuft. Im Gegensatz zu klassischen CI/CD-Tools wie Jenkins oder GitLab CI fuehrt Argo Workflows jeden Schritt als eigenen Kubernetes-Pod aus. Das bedeutet: volle Isolation, beliebige Container-Images pro Schritt, native Kubernetes-Ressourcenverwaltung und keine separaten Worker-Nodes.
Ob ML-Training-Pipeline, CI/CD-Workflow oder Datenverarbeitung -- Argo Workflows definiert alles als Kubernetes Custom Resource in YAML.
Kernkonzepte verstehen
Bevor wir in die Praxis einsteigen, muessen vier Konzepte klar sein:
Workflow -- Die ausfuehrbare Einheit. Vergleichbar mit einem Job, aber mit mehreren Schritten und Abhaengigkeiten.
Template -- Ein einzelner Schritt innerhalb eines Workflows. Es gibt verschiedene Template-Typen: Container (fuehrt einen Container aus), Script (fuehrt Inline-Code aus), DAG (definiert Abhaengigkeitsgraph), Steps (definiert sequentielle/parallele Schritte).
DAG (Directed Acyclic Graph) -- Definiert Abhaengigkeiten zwischen Templates. Task B startet erst, wenn Task A erfolgreich war. Tasks ohne Abhaengigkeit laufen parallel.
Steps -- Eine alternative Ausfuehrungsstrategie: Schritte laufen sequentiell ab, wobei innerhalb eines Schritts mehrere Tasks parallel laufen koennen.
Workflow
|
+-- Template: DAG
| +-- Task A (Container)
| +-- Task B (abhaengig von A)
| +-- Task C (abhaengig von A)
| +-- Task D (abhaengig von B + C)
|
+-- Template: Steps
+-- Step 1: [Task X]
+-- Step 2: [Task Y, Task Z] (parallel)
+-- Step 3: [Task W]
Installation via Helm
Die Installation von Argo Workflows auf einem bestehenden Kubernetes-Cluster dauert weniger als 5 Minuten.
# Namespace erstellen
kubectl create namespace argo
# Helm Repository hinzufuegen
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
# Argo Workflows installieren
helm install argo-workflows argo/argo-workflows \
--namespace argo \
--set server.serviceType=ClusterIP \
--set server.extraArgs="{--auth-mode=server}" \
--set controller.workflowNamespaces="{argo,default}" \
--set controller.metricsConfig.enabled=true
# Warten bis alle Pods bereit sind
kubectl wait --for=condition=Ready pods --all -n argo --timeout=300s
Argo CLI installieren
# macOS
brew install argo
# Linux
curl -sLO https://github.com/argoproj/argo-workflows/releases/latest/download/argo-linux-amd64.gz
gunzip argo-linux-amd64.gz
chmod +x argo-linux-amd64
sudo mv argo-linux-amd64 /usr/local/bin/argo
# Version pruefen
argo version
UI-Zugriff
# Port-Forward zum Argo Server
kubectl -n argo port-forward svc/argo-workflows-server 2746:2746
# Browser: https://localhost:2746
Einfacher Workflow: Steps-basiert
Ein minimaler Workflow mit sequentiellen Schritten:
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: hello-steps-
namespace: argo
spec:
entrypoint: main
templates:
- name: main
steps:
- - name: schritt-1
template: echo
arguments:
parameters:
- name: message
value: "Schritt 1: Vorbereitung"
- - name: schritt-2a
template: echo
arguments:
parameters:
- name: message
value: "Schritt 2a: parallel A"
- name: schritt-2b
template: echo
arguments:
parameters:
- name: message
value: "Schritt 2b: parallel B"
- - name: schritt-3
template: echo
arguments:
parameters:
- name: message
value: "Schritt 3: Abschluss"
- name: echo
inputs:
parameters:
- name: message
container:
image: alpine:3.19
command: [sh, -c]
args: ["echo '{{inputs.parameters.message}}' && sleep 2"]
# Workflow starten
argo submit hello-steps.yaml --watch
# Status pruefen
argo list -n argo
# Logs anzeigen
argo logs -n argo hello-steps-xxxxx
In diesem Beispiel laeuft Schritt 1 zuerst, dann Schritt 2a und 2b parallel, und abschliessend Schritt 3.
DAG Workflow: Parallele Ausfuehrung mit Abhaengigkeiten
Der DAG-Modus ist maechtig, weil Abhaengigkeiten explizit modelliert werden. Tasks ohne Abhaengigkeit starten automatisch parallel.
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: dag-pipeline-
namespace: argo
spec:
entrypoint: pipeline
templates:
- name: pipeline
dag:
tasks:
- name: checkout
template: git-clone
- name: lint
template: run-lint
dependencies: [checkout]
- name: unit-tests
template: run-tests
dependencies: [checkout]
- name: security-scan
template: run-scan
dependencies: [checkout]
- name: build
template: build-image
dependencies: [lint, unit-tests, security-scan]
- name: deploy
template: deploy-app
dependencies: [build]
- name: git-clone
container:
image: alpine/git:2.43.0
command: [sh, -c]
args: ["echo 'Cloning repository...' && sleep 3"]
- name: run-lint
container:
image: golangci/golangci-lint:v1.56
command: [sh, -c]
args: ["echo 'Running linter...' && sleep 5"]
- name: run-tests
container:
image: golang:1.22
command: [sh, -c]
args: ["echo 'Running tests...' && sleep 8"]
- name: run-scan
container:
image: aquasec/trivy:latest
command: [sh, -c]
args: ["echo 'Security scanning...' && sleep 4"]
- name: build-image
container:
image: gcr.io/kaniko-project/executor:latest
command: [sh, -c]
args: ["echo 'Building container image...' && sleep 10"]
- name: deploy-app
container:
image: bitnami/kubectl:latest
command: [sh, -c]
args: ["echo 'Deploying application...' && sleep 3"]
Die drei Tasks lint, unit-tests und security-scan laufen parallel, sobald checkout abgeschlossen ist. build startet erst, wenn alle drei erfolgreich waren.
ML Training Pipeline
Eine realistische ML-Pipeline mit Datenaufbereitung, Training, Evaluation und bedingtem Deployment:
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: ml-training-
namespace: argo
spec:
entrypoint: ml-pipeline
arguments:
parameters:
- name: model-name
value: "text-classifier"
- name: epochs
value: "50"
- name: accuracy-threshold
value: "0.85"
templates:
- name: ml-pipeline
dag:
tasks:
- name: data-prep
template: prepare-data
- name: validate-data
template: data-validation
dependencies: [data-prep]
- name: train-model
template: training
dependencies: [validate-data]
arguments:
parameters:
- name: epochs
value: "{{workflow.parameters.epochs}}"
- name: evaluate
template: evaluation
dependencies: [train-model]
- name: deploy-model
template: model-deploy
dependencies: [evaluate]
when: "{{tasks.evaluate.outputs.parameters.accuracy}} >= {{workflow.parameters.accuracy-threshold}}"
- name: prepare-data
container:
image: registry.internal/ml-data-prep:2.1.0
command: [python, -c]
args:
- |
import json
print("Daten aus S3 laden...")
print("Feature Engineering ausfuehren...")
print("Train/Test Split: 80/20")
with open("/tmp/data-stats.json", "w") as f:
json.dump({"samples": 50000, "features": 128}, f)
resources:
requests:
cpu: "1"
memory: 4Gi
outputs:
artifacts:
- name: training-data
path: /tmp/training-data
s3:
bucket: ml-artifacts
key: "{{workflow.name}}/training-data.tar.gz"
- name: data-validation
container:
image: registry.internal/ml-data-validation:1.3.0
command: [python, -c]
args:
- |
print("Schema-Validierung...")
print("Verteilungs-Check...")
print("Keine Anomalien gefunden")
resources:
requests:
cpu: 500m
memory: 2Gi
- name: training
inputs:
parameters:
- name: epochs
container:
image: registry.internal/ml-trainer:3.0.0
command: [python, -c]
args:
- |
epochs = {{inputs.parameters.epochs}}
print(f"Training mit {epochs} Epochen gestartet...")
print("Modell gespeichert unter /tmp/model/")
with open("/tmp/accuracy.txt", "w") as f:
f.write("0.92")
resources:
requests:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: "1"
limits:
cpu: "8"
memory: 32Gi
nvidia.com/gpu: "1"
outputs:
parameters:
- name: accuracy
valueFrom:
path: /tmp/accuracy.txt
artifacts:
- name: model
path: /tmp/model
s3:
bucket: ml-artifacts
key: "{{workflow.name}}/model.tar.gz"
- name: evaluation
container:
image: registry.internal/ml-evaluator:1.5.0
command: [python, -c]
args:
- |
accuracy = 0.92
print(f"Test-Accuracy: {accuracy}")
print("Confusion Matrix berechnet")
with open("/tmp/accuracy.txt", "w") as f:
f.write(str(accuracy))
resources:
requests:
cpu: "2"
memory: 8Gi
outputs:
parameters:
- name: accuracy
valueFrom:
path: /tmp/accuracy.txt
- name: model-deploy
container:
image: registry.internal/ml-deployer:1.2.0
command: [sh, -c]
args:
- |
echo "Modell auf Inference-Endpoint deployen..."
echo "Health-Check bestanden"
echo "Deployment erfolgreich"
resources:
requests:
cpu: 500m
memory: 1Gi
Entscheidend ist die when-Bedingung beim Deploy-Schritt: Das Modell wird nur deployed, wenn die Accuracy den Threshold ueberschreitet. So verhindern Sie, dass schlechte Modelle in Produktion landen.
CI/CD Pipeline mit Argo Workflows
Eine vollstaendige CI/CD-Pipeline mit Build, Test, Security-Scan und Deployment:
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: cicd-
namespace: argo
spec:
entrypoint: cicd-pipeline
arguments:
parameters:
- name: git-repo
value: "https://github.com/myorg/myapp.git"
- name: git-branch
value: "main"
- name: image-registry
value: "registry.internal/myapp"
serviceAccountName: argo-workflow-sa
volumes:
- name: docker-config
secret:
secretName: registry-credentials
- name: workspace
emptyDir: {}
templates:
- name: cicd-pipeline
dag:
tasks:
- name: clone
template: git-clone
- name: test
template: run-tests
dependencies: [clone]
- name: build
template: build-push
dependencies: [test]
- name: scan
template: security-scan
dependencies: [build]
- name: deploy-staging
template: deploy
dependencies: [scan]
arguments:
parameters:
- name: environment
value: "staging"
- name: integration-tests
template: run-integration
dependencies: [deploy-staging]
- name: deploy-production
template: deploy
dependencies: [integration-tests]
arguments:
parameters:
- name: environment
value: "production"
- name: git-clone
container:
image: alpine/git:2.43.0
command: [sh, -c]
args:
- |
git clone --branch {{workflow.parameters.git-branch}} \
{{workflow.parameters.git-repo}} /workspace/src
volumeMounts:
- name: workspace
mountPath: /workspace
- name: run-tests
container:
image: golang:1.22
command: [sh, -c]
args:
- |
cd /workspace/src
go test ./... -v -coverprofile=coverage.out
go tool cover -func=coverage.out
volumeMounts:
- name: workspace
mountPath: /workspace
- name: build-push
container:
image: gcr.io/kaniko-project/executor:latest
args:
- "--dockerfile=/workspace/src/Dockerfile"
- "--context=/workspace/src"
- "--destination={{workflow.parameters.image-registry}}:{{workflow.name}}"
- "--cache=true"
volumeMounts:
- name: workspace
mountPath: /workspace
- name: docker-config
mountPath: /kaniko/.docker/
- name: security-scan
container:
image: aquasec/trivy:latest
command: [sh, -c]
args:
- |
trivy image --severity HIGH,CRITICAL \
--exit-code 1 \
{{workflow.parameters.image-registry}}:{{workflow.name}}
- name: run-integration
container:
image: registry.internal/integration-tests:latest
command: [sh, -c]
args:
- |
echo "Integrationstests gegen Staging laufen..."
sleep 10
echo "Alle Tests bestanden"
- name: deploy
inputs:
parameters:
- name: environment
container:
image: bitnami/kubectl:latest
command: [sh, -c]
args:
- |
echo "Deploying to {{inputs.parameters.environment}}..."
kubectl set image deployment/myapp \
myapp={{workflow.parameters.image-registry}}:{{workflow.name}} \
-n {{inputs.parameters.environment}}
kubectl rollout status deployment/myapp \
-n {{inputs.parameters.environment}} --timeout=300s
Artifacts: S3 und MinIO
Argo Workflows nutzt Artifacts, um Daten zwischen Schritten zu teilen. Die haeufigste Backend-Konfiguration ist S3 oder MinIO.
Artifact Repository konfigurieren
apiVersion: v1
kind: ConfigMap
metadata:
name: artifact-repositories
namespace: argo
annotations:
workflows.argoproj.io/default-artifact-repository: default-artifact-repo
data:
default-artifact-repo: |
s3:
bucket: argo-artifacts
endpoint: minio.argo.svc.cluster.local:9000
insecure: true
accessKeySecret:
name: minio-credentials
key: accesskey
secretKeySecret:
name: minio-credentials
key: secretkey
MinIO schnell installieren
helm install minio oci://registry-1.docker.io/bitnamicharts/minio \
--namespace argo \
--set auth.rootUser=admin \
--set auth.rootPassword=minio-secret-key \
--set defaultBuckets=argo-artifacts
# Credentials als Secret
kubectl create secret generic minio-credentials \
--namespace argo \
--from-literal=accesskey=admin \
--from-literal=secretkey=minio-secret-key
WorkflowTemplates: Wiederverwendbare Bausteine
WorkflowTemplates sind cluster-weit oder namespace-weit verfuegbare Template-Bibliotheken. Einmal definiert, koennen sie in beliebig vielen Workflows referenziert werden.
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: docker-build-template
namespace: argo
spec:
templates:
- name: kaniko-build
inputs:
parameters:
- name: dockerfile
default: "Dockerfile"
- name: context
- name: image
- name: tag
artifacts:
- name: source
path: /workspace
container:
image: gcr.io/kaniko-project/executor:latest
args:
- "--dockerfile=/workspace/{{inputs.parameters.dockerfile}}"
- "--context=/workspace/{{inputs.parameters.context}}"
- "--destination={{inputs.parameters.image}}:{{inputs.parameters.tag}}"
- "--cache=true"
- "--snapshot-mode=redo"
volumeMounts:
- name: docker-config
mountPath: /kaniko/.docker/
Referenzierung in einem Workflow:
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: build-app-
spec:
entrypoint: main
templates:
- name: main
dag:
tasks:
- name: build
templateRef:
name: docker-build-template
template: kaniko-build
arguments:
parameters:
- name: context
value: "."
- name: image
value: "registry.internal/myapp"
- name: tag
value: "v1.0.0"
Argo Workflows vs. Apache Airflow
Beide Tools orchestrieren Workflows, aber die Architektur ist grundverschieden.
| Kriterium | Argo Workflows | Apache Airflow |
|---|---|---|
| Ausfuehrungsumgebung | Kubernetes-nativ (jeder Task = Pod) | Python-Prozesse auf Worker-Nodes |
| Definition | YAML (Kubernetes CRDs) | Python-Code (DAG-Dateien) |
| Container-Isolation | Vollstaendig (jeder Schritt eigenes Image) | Begrenzt (KubernetesExecutor noetig) |
| Skalierung | Kubernetes-nativ (Pod-Scheduling) | Celery/Kubernetes Executor |
| UI | Integriert (Workflow-Visualisierung) | Umfangreiches Web-UI mit Scheduling |
| Scheduling | CronWorkflows | Integrierter Scheduler (Kernfeature) |
| Datenabhaengigkeiten | Artifacts (S3/GCS/MinIO) | XCom, Datasets |
| Staerke | CI/CD, ML-Pipelines, Batch-Jobs | Daten-Pipelines, ETL, Scheduling |
| Community | CNCF Graduated Project | Apache Top-Level Project |
Wann Argo Workflows: Sie brauchen Container-Isolation pro Schritt, betreiben bereits Kubernetes, oder Ihre Pipelines bestehen aus heterogenen Tools mit unterschiedlichen Runtimes.
Wann Airflow: Sie haben primaer Daten-Pipelines, brauchen komplexes Scheduling (Backfills, SLA-Monitoring, Sensor-Tasks), oder Ihr Team denkt in Python.
Mehr zu Airflow auf Kubernetes finden Sie unter Airflow auf Kubernetes betreiben.
Monitoring: UI und Prometheus
Argo Workflows UI
Das integrierte UI zeigt laufende und abgeschlossene Workflows mit DAG-Visualisierung, Logs pro Schritt und Artifact-Download.
# Zugriff via Port-Forward
kubectl -n argo port-forward svc/argo-workflows-server 2746:2746
Prometheus-Metriken
Argo Workflows exponiert Metriken am Controller:
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: argo-workflows
namespace: argo
spec:
selector:
matchLabels:
app.kubernetes.io/name: argo-workflows-controller
endpoints:
- port: metrics
interval: 30s
path: /metrics
Wichtige Metriken fuer Dashboards:
# Laufende Workflows
argo_workflows_count{status="Running"}
# Workflow-Dauer (Histogram)
argo_workflows_operation_duration_seconds_bucket
# Fehlerrate
argo_workflows_count{status="Error"}
# Pod-Ausfuehrungszeit
argo_workflows_pods_count
Alerting-Beispiel
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: argo-workflows-alerts
namespace: argo
spec:
groups:
- name: argo-workflows
rules:
- alert: ArgoWorkflowFailed
expr: increase(argo_workflows_count{status="Error"}[5m]) > 0
for: 1m
labels:
severity: warning
annotations:
summary: "Argo Workflow fehlgeschlagen"
description: "Mindestens ein Workflow ist in den letzten 5 Minuten fehlgeschlagen."
- alert: ArgoWorkflowStuck
expr: argo_workflows_count{status="Running"} > 0 and changes(argo_workflows_count{status="Running"}[30m]) == 0
for: 30m
labels:
severity: critical
annotations:
summary: "Argo Workflow haengt"
description: "Ein Workflow laeuft seit 30+ Minuten ohne Fortschritt."
CronWorkflows: Zeitgesteuerte Ausfuehrung
Fuer regelmaessige Workflows (naechtliches ML-Retraining, taegliche Datenverarbeitung) gibt es CronWorkflows:
apiVersion: argoproj.io/v1alpha1
kind: CronWorkflow
metadata:
name: nightly-ml-retrain
namespace: argo
spec:
schedule: "0 2 * * *"
timezone: "Europe/Berlin"
concurrencyPolicy: "Forbid"
successfulJobsHistoryLimit: 5
failedJobsHistoryLimit: 3
workflowSpec:
entrypoint: ml-pipeline
templates:
- name: ml-pipeline
dag:
tasks:
- name: fetch-data
template: data-fetch
- name: retrain
template: train
dependencies: [fetch-data]
- name: validate
template: validate-model
dependencies: [retrain]
- name: data-fetch
container:
image: registry.internal/data-fetcher:latest
command: [python, fetch_latest_data.py]
- name: train
container:
image: registry.internal/ml-trainer:latest
command: [python, train.py]
resources:
requests:
nvidia.com/gpu: "1"
- name: validate-model
container:
image: registry.internal/ml-validator:latest
command: [python, validate.py]
Zusammenfassung
| Aufgabe | Befehl / Ressource |
|---|---|
| Workflow starten | argo submit workflow.yaml --watch |
| Status pruefen | argo list -n argo |
| Logs anzeigen | argo logs -n argo WORKFLOW_NAME |
| Workflow stoppen | argo stop -n argo WORKFLOW_NAME |
| Workflow loeschen | argo delete -n argo WORKFLOW_NAME |
| Template erstellen | kubectl apply -f workflowtemplate.yaml |
| CronWorkflow | kubectl apply -f cronworkflow.yaml |
Argo Workflows auf Kubernetes ist besonders stark, wenn Sie heterogene Workloads mit unterschiedlichen Container-Images orchestrieren muessen. ML-Pipelines, CI/CD und Datenverarbeitung profitieren von der nativen Kubernetes-Integration und der DAG-basierten Ausfuehrung.
Verwandte Artikel
- ArgoCD Tutorial: GitOps fuer Kubernetes einrichten
- Kubernetes CI/CD Enterprise Scale
- Airflow auf Kubernetes betreiben
- Kubernetes GPU-Cluster fuer ML-Workloads
- Kubernetes Monitoring und Observability
Sie moechten Argo Workflows in Ihrer Kubernetes-Umgebung einrichten oder bestehende CI/CD-Pipelines migrieren? Wir unterstuetzen Sie bei Architektur, Installation und Betrieb. Kontaktieren Sie uns unter /kontakt.
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
Tekton Pipelines: Cloud-native CI/CD auf Kubernetes
Tekton Pipelines auf Kubernetes einrichten: Tasks, Pipelines und PipelineRuns für cloud-native CI/CD mit praktischen YAML-Beispielen.
Kubernetes GxP-Validierung automatisieren für Pharma
Kubernetes in GxP-regulierten Pharma-Umgebungen einsetzen: Validierung automatisieren, Immutable Infrastructure nutzen und Audit Trails einrichten.
ArgoCD Enterprise: App-of-Apps, RBAC und SSO
ArgoCD im Unternehmen einführen mit App-of-Apps-Pattern, RBAC, SSO-Integration und Multi-Repo-Strategien anhand realer YAML-Beispiele.
ArgoCD Tutorial: GitOps für Kubernetes einrichten
ArgoCD installieren und konfigurieren: Von der Einrichtung bis zur automatischen Synchronisation mit praktischen GitOps-Workflow-Beispielen.
Kubernetes CI/CD mit GitOps: Argo CD und Tekton einrichten
GitOps-basierte CI/CD-Pipelines für Kubernetes mit Argo CD, Tekton und Helm einrichten: Architektur, YAML-Beispiele und Deployment-Strategien.