Start / Blog / Runtime-Management / Container-Orchestrierung Deep-Dive

Container-Orchestrierung Deep-Dive

Zusammenfassen mit ChatGPT

Container-Orchestrierung ist die Automatisierung von Deployment, Skalierung und Management containerisierter Anwendungen. Für KI-intensive Workloads wie Konfuzio’s Dokumentenverarbeitung ermöglicht Kubernetes (K8s) elastische Skalierung, GPU-Ressourcen-Management und Cloud-übergreifende Portabilität. Die moderne Infrastruktur für Cloud-Hosting und On-Premise-Deployments setzt zunehmend auf Container-Technologie, um Flexibilität und Skalierbarkeit zu maximieren.

Was ist Container-Orchestrierung?

Containers 101

Container-Technologie hat die Art und Weise revolutioniert, wie Anwendungen entwickelt und betrieben werden. Im Gegensatz zu virtuellen Maschinen, die ein vollständiges Betriebssystem virtualisieren, teilen sich Container den Kernel des Host-Systems und kapseln nur die Anwendung selbst samt ihren spezifischen Abhängigkeiten. Diese Architektur führt zu erheblich geringerem Ressourcenverbrauch und ermöglicht es, Dutzende Container auf Hardware zu betreiben, die nur wenige VMs bewältigen würde.

Container verpacken Anwendungen mit allen Abhängigkeiten in isolierte, portable Einheiten.

Vorteile:

  • Portabilität: Läuft überall (Laptop, On-Premise, Cloud)
  • Isolation: Keine Konflikte zwischen Applikationen
  • Effizienz: Teilen sich OS-Kernel (leichtgewichtiger als VMs)
  • Schnelligkeit: Start in Sekunden (VMs: Minuten)

Docker-Beispiel:

# Konfuzio OCR-Service
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "ocr_service.py"]
# Build & Run
docker build -t konfuzio-ocr:v1 .
docker run -d -p 8000:8000 konfuzio-ocr:v1

Warum Orchestrierung?

Problem ohne Orchestrierung:

  • Manuelles Deployment auf jeden Server
  • Kein Auto-Restart bei Crashes
  • Keine automatische Skalierung
  • Load-Balancing manuell konfigurieren

Orchestrierung löst:

  • ✅ Automatisches Deployment über Cluster
  • ✅ Self-Healing (Neustart bei Fehler)
  • ✅ Horizontal Pod Autoscaler (HPA)
  • ✅ Service Discovery & Load Balancing
  • ✅ Rolling Updates ohne Downtime

Kubernetes: De-facto-Standard für Orchestrierung

Kubernetes-Architektur

Kubernetes Cluster
├── Control Plane (Management)
│   ├── API-Server (Zentrale Schnittstelle)
│   ├── etcd (Key-Value-Store für Cluster-State)
│   ├── Scheduler (Platziert Pods auf Nodes)
│   └── Controller Manager (Steuert Desired State)
└── Worker Nodes (Ausführung)
    ├── kubelet (Agent auf jedem Node)
    ├── kube-proxy (Netzwerk-Routing)
    └── Container Runtime (Docker/containerd)

Kern-Konzepte

Pod:

  • Kleinste deploybare Einheit
  • Ein oder mehrere Container
  • Shared Network & Storage

Deployment:

  • Beschreibt gewünschten State
  • Automatisches ReplicaSet-Management
  • Rolling Updates

Service:

  • Stabiler Netzwerk-Endpoint für Pods
  • Load Balancing über Replicas
  • DNS-Name (z.B. ocr-service.default.svc.cluster.local)

ConfigMap & Secret:

  • Konfiguration getrennt von Code
  • Secrets verschlüsselt

PersistentVolume:

  • Persistenter Storage für Pods
  • Überdauert Pod-Neustarts

Konfuzio auf Kubernetes: Beispiel-Deployment

Minimal-Setup (Docker Compose → Kubernetes)

Alt (Docker Compose):

version: '3'
services:
  ocr:
    image: konfuzio/ocr:latest
    ports:
      - "8000:8000"
    environment:
      - DB_HOST=postgres

Neu (Kubernetes):

# ocr-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ocr-service
spec:
  replicas: 3  # 3 Instanzen für Load Balancing
  selector:
    matchLabels:
      app: ocr
  template:
    metadata:
      labels:
        app: ocr
    spec:
      containers:
      - name: ocr
        image: konfuzio/ocr:latest
        ports:
        - containerPort: 8000
        env:
        - name: DB_HOST
          value: postgres-service
        resources:
          requests:
            memory: "2Gi"
            cpu: "1000m"
          limits:
            memory: "4Gi"
            cpu: "2000m"
---
# ocr-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: ocr-service
spec:
  selector:
    app: ocr
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8000
  type: LoadBalancer  # Extern erreichbar

Deployment:

kubectl apply -f ocr-deployment.yaml
kubectl get pods  # 3 OCR-Pods sollten laufen
kubectl get service ocr-service  # Externe IP holen

Auto-Scaling mit HPA

Horizontal Pod Autoscaler:

# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: ocr-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: ocr-service
  minReplicas: 2
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 30
      policies:
      - type: Percent
        value: 100  # Verdopplung möglich
        periodSeconds: 30
    scaleDown:
      stabilizationWindowSeconds: 300  # 5 Min Cooldown
      policies:
      - type: Pods
        value: 1  # Max 1 Pod/5min runterskalieren
        periodSeconds: 300

Funktionsweise:

Normal-Betrieb (1.000 Docs/Tag):
- CPU: 30% durchschnittlich
- HPA: 2 Pods (Minimum)
Lastspitze (10.000 Docs/Tag):
- CPU: 85% (über Threshold 70%)
- HPA skaliert hoch: 2 → 4 → 8 → 12 Pods
- CPU sinkt auf 60%
Nach Lastspitze:
- CPU: 20% (unter Threshold)
- HPA skaliert runter: 12 → 11 → 10 → ... → 2 Pods
  (langsam, 1 Pod alle 5 Minuten)

GPU-Management in Kubernetes

NVIDIA Device Plugin:

# Installation
kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/main/nvidia-device-plugin.yml
# Verifizierung
kubectl get nodes -o json | jq '.items[].status.allocatable'
# Sollte "nvidia.com/gpu: 2" zeigen (wenn Node 2 GPUs hat)

GPU-Pod:

apiVersion: v1
kind: Pod
metadata:
  name: ocr-gpu
spec:
  containers:
  - name: ocr
    image: konfuzio/ocr-gpu:latest
    resources:
      limits:
        nvidia.com/gpu: 1  # 1 GPU anfordern

GPU-Sharing (MIG – Multi-Instance GPU):

# A100 GPU in 7 Instanzen aufteilen
apiVersion: v1
kind: Pod
metadata:
  name: ocr-mig
spec:
  containers:
  - name: ocr
    image: konfuzio/ocr:latest
    resources:
      limits:
        nvidia.com/mig-1g.5gb: 1  # 1/7 einer A100 (5GB VRAM)

Vorteile:

  • ✅ Mehrere Workloads teilen sich teure GPU
  • ✅ Bessere GPU-Auslastung (kein Idle-Zeit-Waste)
  • ✅ Isolierung (ein Workload crasht nicht die GPU für andere)

Storage: Persistent Volumes für ML-Modelle

Problem: Pods sind ephemeral (können jederzeit neu starten, Daten weg)
Lösung: PersistentVolumes für Modelle, Dokumente

PVC (PersistentVolumeClaim):

# models-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: models-storage
spec:
  accessModes:
    - ReadWriteMany  # Mehrere Pods gleichzeitig
  storageClassName: nfs  # NFS für Shared-Access
  resources:
    requests:
      storage: 100Gi
---
# ocr-deployment mit PVC
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ocr-service
spec:
  template:
    spec:
      containers:
      - name: ocr
        image: konfuzio/ocr:latest
        volumeMounts:
        - name: models
          mountPath: /app/models
      volumes:
      - name: models
        persistentVolumeClaim:
          claimName: models-storage

Vorteile:

  • Modelle müssen nicht bei jedem Pod-Start heruntergeladen werden
  • Shared-Access: Alle OCR-Pods nutzen gleiche Modelle
  • Überdauert Pod-Restarts

Kubernetes-Distributionen: Welche wählen?

Managed Kubernetes (Cloud)

AWS EKS (Elastic Kubernetes Service):

  • Vorteile: Tief integriert mit AWS-Services (IAM, VPC, EBS)
  • Nachteile: AWS-spezifische Konfiguration (weniger portabel)
  • Kosten: 0,10€/h für Control Plane + Worker-Node-Kosten
  • Siehe: Cloud-Hosting

Google GKE (Google Kubernetes Engine):

  • Vorteile: Beste K8s-Integration (K8s wurde bei Google entwickelt)
  • Nachteile: Kleineres Ökosystem als AWS
  • Kosten: Kostenloser Control Plane + Worker-Node-Kosten

Azure AKS (Azure Kubernetes Service):

  • Vorteile: Beste Microsoft-Integration (AD, DevOps)
  • Nachteile: Komplexere Netzwerk-Konfiguration
  • Kosten: Kostenloser Control Plane + Worker-Node-Kosten

Self-Managed Kubernetes (On-Premise)

Rancher (RKE/RKE2):

  • Vorteile: Einfachstes On-Premise-Setup, Web-UI
  • Nachteile: Weniger Enterprise-Support als Red Hat
  • Kosten: Open Source (kostenfrei)

Red Hat OpenShift:

  • Vorteile: Enterprise-Support, Security-Features, Operator-Hub
  • Nachteile: Hohe Lizenzkosten (ca. 50€/Core/Jahr)
  • Kosten: ab 15.000€/Jahr für kleine Cluster

Vanilla Kubernetes (kubeadm):

  • Vorteile: Maximale Kontrolle, keine Vendor-Lock-in
  • Nachteile: Komplexer Setup, kein Support
  • Kosten: Open Source (kostenfrei)

K3s (Lightweight K8s):

  • Vorteile: Minimaler Footprint (40MB Binary), ideal für Edge/IoT
  • Nachteile: Einige Features entfernt (Cloud-Provider-Integrationen)
  • Kosten: Open Source (kostenfrei)

Konfuzio-Empfehlung:

  • Cloud: GKE (beste K8s-Experience) oder EKS (größtes Ökosystem)
  • On-Premise: Rancher (einfach) oder OpenShift (Enterprise mit Support)
  • Edge: K3s

Microservices-Architektur mit Kubernetes

Monolith (alt):

┌───────────────────────┐
│   Konfuzio Monolith   │
│  (API + OCR + DB)     │
└───────────────────────┘
  • Ein großer Container
  • Schwierig zu skalieren (alles oder nichts)
  • Ein Fehler bringt alles down

Microservices (neu):

┌─────────┐   ┌─────────┐   ┌──────────┐
│   API   │ → │   OCR   │ → │ Extract  │
│ Gateway │   │ Service │   │ Service  │
└─────────┘   └─────────┘   └──────────┘
     ↓              ↓               ↓
┌───────────────────────────────────────┐
│         PostgreSQL (Database)         │
└───────────────────────────────────────┘
  • Jeder Service skaliert unabhängig
  • API-Gateway: 2 Replicas (wenig Last)
  • OCR-Service: 10 Replicas (rechenintensiv)
  • Extract-Service: 5 Replicas

Kubernetes-Deployment:

# api-gateway (wenig Last)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-gateway
spec:
  replicas: 2
  template:
    spec:
      containers:
      - name: api
        resources:
          requests:
            cpu: "500m"
            memory: "1Gi"
---
# ocr-service (rechenintensiv, GPU)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ocr-service
spec:
  replicas: 10
  template:
    spec:
      containers:
      - name: ocr
        resources:
          requests:
            cpu: "2000m"
            memory: "4Gi"
            nvidia.com/gpu: "1"
---
# extraction-service (mittel)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: extraction-service
spec:
  replicas: 5
  template:
    spec:
      containers:
      - name: extraction
        resources:
          requests:
            cpu: "1000m"
            memory: "2Gi"

Vorteile:

  • Optimale Ressourcen-Nutzung (jeder Service nach Bedarf)
  • Isolierte Fehler (OCR-Crash betrifft nicht API)
  • Unabhängige Deployments (Extraction-Update ohne OCR-Downtime)

CI/CD mit Kubernetes

GitOps: Infrastructure as Code

Konzept:

  • Git-Repository als Single Source of Truth
  • Änderungen per Git-Commit (kein manuelles kubectl apply)
  • Automatisches Deployment via CI/CD-Pipeline

Flux/ArgoCD (GitOps-Operatoren):

# FluxCD installieren
flux bootstrap github \
  --owner=konfuzio \
  --repository=k8s-manifests \
  --path=clusters/production
# Flux überwacht Git-Repo
# Bei neuem Commit:
git commit -m "Update OCR to v2.3"
git push
# → Flux erkennt Änderung automatisch
# → Deployed neue Version auf Cluster

Vorteile:

  • ✅ Audit-Trail (jede Änderung in Git-Historie)
  • ✅ Rollback einfach (git revert)
  • ✅ Disaster Recovery (Cluster-Recreation aus Git)

CI/CD-Pipeline-Beispiel (GitHub Actions)

# .github/workflows/deploy.yml
name: Build and Deploy
on:
  push:
    branches: [main]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Build Docker Image
      run: |
        docker build -t konfuzio/ocr:${{ github.sha }} .
    - name: Push to Registry
      run: |
        docker push konfuzio/ocr:${{ github.sha }}
  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
    - name: Update Kubernetes Manifest
      run: |
        kubectl set image deployment/ocr-service \
          ocr=konfuzio/ocr:${{ github.sha }} \
          --record
    - name: Wait for Rollout
      run: kubectl rollout status deployment/ocr-service
    - name: Run Smoke Tests
      run: |
        curl https://api.konfuzio.com/health
        # Wenn Fehler: kubectl rollout undo

Monitoring & Observability

Prometheus + Grafana Stack

Installation (Helm):

# Prometheus Operator
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install prometheus prometheus-community/kube-prometheus-stack
# Zugriff
kubectl port-forward svc/prometheus-grafana 3000:80
# → http://localhost:3000 (User: admin, Password: prom-operator)

Key Metrics:

  • Node-Level: CPU, RAM, Disk, Network
  • Pod-Level: Container CPU/RAM, Restart-Count
  • Application: Request-Rate, Latency, Error-Rate
  • GPU: GPU-Auslastung, VRAM-Usage, Temperatur

Grafana-Dashboard (Beispiel):

┌─────────────────────────────────────────┐
│  Konfuzio OCR Service Dashboard         │
├─────────────────────────────────────────┤
│  Pods Running: 12 / 12 (100%)           │
│  Request Rate: 150 req/s                │
│  P95 Latency: 1.8s                      │
│  Error Rate: 0.05%                      │
├─────────────────────────────────────────┤
│  [Graph: CPU Usage over Time]           │
│  [Graph: Memory Usage]                  │
│  [Graph: GPU Utilization]               │
└─────────────────────────────────────────┘

Logging: ELK-Stack oder Loki

Loki (Lightweight-Alternative zu Elasticsearch):

# Loki + Promtail (Log-Collector)
helm install loki grafana/loki-stack
# Logs in Grafana
# → Explore → Data Source: Loki
# → Query: {app="ocr-service"} |= "error"

Vorteile:

  • Zentrale Log-Aggregation über alle Pods
  • Korrelation mit Metrics (Prometheus + Loki in einem Dashboard)
  • Label-basierte Queries (ähnlich Prometheus)

Security: Best Practices

1. Network Policies (Mikrosegmentierung)

# Nur API-Gateway darf auf OCR-Service zugreifen
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: ocr-service-policy
spec:
  podSelector:
    matchLabels:
      app: ocr
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: api-gateway
    ports:
    - protocol: TCP
      port: 8000

2. Pod Security Standards

# Restrictive Pod Security
apiVersion: v1
kind: Pod
metadata:
  name: ocr-secure
spec:
  securityContext:
    runAsNonRoot: true  # Nicht als Root laufen
    runAsUser: 1000
    fsGroup: 1000
  containers:
  - name: ocr
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true  # Read-Only-FS
      capabilities:
        drop:
        - ALL  # Alle Linux-Capabilities droppen

3. Secret Management

# Secrets verschlüsselt in etcd
kubectl create secret generic db-password \
  --from-literal=password=SuperSecure123
# In Pod nutzen
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: app
    env:
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-password
          key: password

Bessere Alternative: Sealed Secrets:

# Sealed Secrets: Verschlüsselte Secrets in Git
kubeseal < secret.yaml > sealed-secret.yaml
git add sealed-secret.yaml
# Sicher für Git (nur Cluster kann entschlüsseln)

Beste Alternative: Vault Integration:

Kosten-Optimierung

1. Spot Instances / Preemptible VMs

AWS:

# Node Group mit Spot Instances (70% günstiger)
apiVersion: v1
kind: Node
metadata:
  labels:
    node.kubernetes.io/lifecycle: spot

Kubernetes-Tolerations:

# Pods tolerieren Spot-Instance-Evictions
apiVersion: v1
kind: Pod
spec:
  tolerations:
  - key: "node.kubernetes.io/lifecycle"
    operator: "Equal"
    value: "spot"
    effect: "NoSchedule"

Wichtig: Nur für zustandslose Workloads (Stateless)

2. Resource Requests richtig setzen

Fehler: Über-Provisioning

resources:
  requests:
    cpu: "4000m"
    memory: "8Gi"
# Tatsächliche Nutzung: 500m CPU, 2Gi RAM
# → 75% Ressourcen verschwendet

Richtig: Nach Monitoring optimieren

# Prometheus-Query: Tatsächliche Nutzung
avg(rate(container_cpu_usage_seconds_total[1d]))
# Ergebnis: 550m
# Requests entsprechend setzen (+ 20% Buffer)
resources:
  requests:
    cpu: "700m"
    memory: "2.5Gi"

3. Vertical Pod Autoscaler (VPA)

# VPA empfiehlt/setzt automatisch Resource Requests
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: ocr-vpa
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: ocr-service
  updatePolicy:
    updateMode: "Auto"  # Automatisch Pods mit neuen Requests neu starten

Troubleshooting

Pod startet nicht

# Status prüfen
kubectl get pods
# NAME                   READY   STATUS              RESTARTS
# ocr-6d5b8f9-xxx        0/1     ImagePullBackOff    0
# Logs
kubectl describe pod ocr-6d5b8f9-xxx
# Events: Failed to pull image "konfuzio/ocr:v99": not found
# → Image-Tag falsch oder Registry-Auth fehlt

Pod crasht wiederholt

# Logs des abstürzenden Pods
kubectl logs ocr-6d5b8f9-xxx --previous
# OOMKilled → Speicher-Limit zu niedrig
# Memory-Limit erhöhen
resources:
  limits:
    memory: "8Gi"  # vorher: 2Gi

Fanden Sie die Seite hilfreich?

Vielen Dank für Ihr Feedback!

Würden Sie mir Feedback geben? (anonym)

Wir entwickeln KI-Software für Unternehmen und verzichten bewusst auf störende Werbebanner. Durch unsere Artikel dokumentieren wir Themen, die uns beschäftigen, interessieren und auch unser tägliches Brot finanzieren.

Da unsere Inhalte kostenfrei sind, ist Ihr Feedback unser Lob.

Jeder Autor liest Ihr anonymes Feedback persönlich, obwohl KI es automatisieren könnten, und integriert konstruktive Vorschläge direkt in die nächste Überarbeitung oder nutzt es als Inspiration für den nächsten Artikel.



    • Florian Zyprian
      (Autor)

      Als CTO bei der Helm & Nagel GmbH, dem Unternehmen hinter der Marke Konfuzio.

    de_DEDE