Lancement / Blog / Gestion de l'exécution / Orchestration de conteneurs Deep-Dive

Orchestration de conteneurs Deep-Dive

Résumer avec ChatGPT

L'orchestration de conteneurs est l'automatisation du déploiement, de la mise à l'échelle et de la gestion. des applications conteneurisées. Pour les charges de travail intensives en IA, comme le traitement de documents de Konfuzio, Kubernetes (K8s) permet une mise à l'échelle élastique, une gestion des ressources GPU et une portabilité inter-cloud. L'infrastructure moderne pour Hébergement en nuage et Déploiements sur site utilise de plus en plus la technologie des conteneurs pour maximiser la flexibilité et l'évolutivité.

Qu'est-ce que l'orchestration de conteneurs ?

Containers 101

La technologie des conteneurs a révolutionné la manière dont les applications sont développées et exploitées. Contrairement aux machines virtuelles qui virtualisent un système d'exploitation complet, les conteneurs partagent le noyau du système hôte et n'encapsulent que l'application elle-même, avec ses dépendances spécifiques. Cette architecture permet de réduire considérablement la consommation de ressources et de faire fonctionner des dizaines de conteneurs sur du matériel qui ne pourrait supporter que quelques VM.

Conteneur emballent les applications avec toutes leurs dépendances dans des unités isolées et portables.

Avantages :

  • PortabilitéFonctionne partout (ordinateur portable, sur site, cloud)
  • IsolationPas de conflit entre les applications
  • Efficacitépartage du noyau du système d'exploitation (plus léger que les VM)
  • Rapidité: démarrage en secondes (VMs : minutes)

Exemple de Docker :

# 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

Pourquoi l'orchestration ?

Problème sans orchestration :

  • Déploiement manuel sur chaque serveur
  • Pas de redémarrage automatique en cas de crash
  • Pas de mise à l'échelle automatique
  • Configurer manuellement l'équilibrage de charge

Orchestration résout :

  • ✅ Déploiement automatique via des clusters
  • ✅ Self-Healing (redémarrage en cas d'erreur)
  • ✅ Détecteur automatique de pod horizontal (HPA)
  • ✅ Découverte de services et équilibrage de charge
  • ✅ Mises à jour glissantes sans temps d'arrêt

Kubernetes : le standard de facto pour l'orchestration

Architecture Kubernetes

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)

Concepts clés

Pod :

  • La plus petite unité déployable
  • Un ou plusieurs conteneurs
  • Réseau et stockage partagés

Déploiement :

  • Décrit l'état souhaité
  • Gestion automatique de ReplicaSet
  • Mises à jour roulantes

service :

  • Point d'accès réseau stable pour les pods
  • Équilibrage de charge via des réplicas
  • Nom DNS (par exemple ocr-service.default.svc.cluster.local)

ConfigMap & Secret :

  • Configuration séparée du code
  • Secrets cryptés

Volume persistant :

  • Stockage persistant pour les pods
  • Survit aux redémarrages des pods

Konfuzio sur Kubernetes : exemple de déploiement

Configuration minimale (Docker Compose → Kubernetes)

Alt (Docker Compose) :

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

Nouveau (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

Déploiement :

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

Auto-scaling avec HPA

Autoscaler le pod horizontal :

# 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

Fonctionnement :

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)

Gestion des GPU dans Kubernetes

Plugin de périphérique NVIDIA :

# 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)

Pod de GPU :

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

Partage de GPU (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)

Avantages :

  • ✅ Plusieurs charges de travail se partagent un GPU coûteux
  • ✅ Meilleure utilisation du GPU (pas de gaspillage de temps au repos)
  • ✅ Isolation (une charge de travail ne crashe pas le GPU pour les autres)

Stockage : Volumes persistants pour les modèles ML

problème : Les pods sont éphémères (peuvent redémarrer à tout moment, données disparues)
Solution : Volumes persistants pour les modèles, les documents

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

Avantages :

  • Les modèles ne doivent pas être téléchargés à chaque démarrage du pod
  • Accès partagé : tous les pods OCR utilisent les mêmes modèles
  • Survit aux redémarrages en pod

Les distributions Kubernetes : Que choisir ?

Managed Kubernetes (Cloud)

AWS EKS (Elastic Kubernetes Service) :

  • Avantages : Profondément intégré avec les services AWS (IAM, VPC, EBS)
  • Inconvénients : Configuration spécifique à AWS (moins portable)
  • Coûts : 0,10€/h pour Control Plane + frais de nœuds de travail
  • Voir Hébergement en nuage

Google GKE (Google Kubernetes Engine) :

  • Avantages : Meilleure intégration de K8s (K8s a été développé chez Google)
  • Inconvénients : Un écosystème plus petit qu'AWS
  • Coûts : Plan de contrôle gratuit + coût du nœud de travail

Azure AKS (Azure Kubernetes Service) :

  • Avantages : Meilleure intégration Microsoft (AD, DevOps)
  • Inconvénients : Configuration réseau plus complexe
  • Coûts : Plan de contrôle gratuit + coût du nœud de travail

Kubernetes autogéré (sur site)

Rancher (RKE/RKE2) :

  • Avantages : Configuration sur site très simple, interface utilisateur Web
  • Inconvénients : Moins de support aux entreprises que Red Hat
  • Coûts : Open Source (gratuit)

Red Hat OpenShift :

  • Avantages : Support d'entreprise, fonctions de sécurité, hub opérateur
  • Inconvénients : Coûts de licence élevés (environ 50€/core/an)
  • Coûts : à partir de 15.000€/an pour les petits clusters

Vanilla Kubernetes (kubeadm) :

  • Avantages : Contrôle maximal, pas de verrouillage par le vendeur
  • Inconvénients : Configuration complexe, pas de support
  • Coûts : Open Source (gratuit)

K3s (K8s léger) :

  • Avantages : Empreinte minimale (40MB binaire), idéale pour Edge/IoT
  • Inconvénients : Suppression de certaines fonctionnalités (intégrations de fournisseurs de cloud)
  • Coûts : Open Source (gratuit)

Konfuzio-recommandation :

  • Cloud : GKE (meilleure expérience K8s) ou EKS (plus grand écosystème)
  • Sur site : Rancher (simple) ou OpenShift (Enterprise avec support)
  • Edge : K3s

Architecture de microservices avec Kubernetes

Monolithe (ancien) :

┌───────────────────────┐
│   Konfuzio Monolith   │
│  (API + OCR + DB)     │
└───────────────────────┘
  • Un grand conteneur
  • Difficile à mettre à l'échelle (tout ou rien)
  • Une erreur fait tout tomber

Microservices (nouveau) :

┌─────────┐   ┌─────────┐   ┌──────────┐
│   API   │ → │   OCR   │ → │ Extract  │
│ Gateway │   │ Service │   │ Service  │
└─────────┘   └─────────┘   └──────────┘
     ↓              ↓               ↓
┌───────────────────────────────────────┐
│         PostgreSQL (Database)         │
└───────────────────────────────────────┘
  • Chaque service évolue de manière indépendante
  • Passerelle API : 2 réplicas (peu de charge)
  • Service OCR : 10 réplicas (calcul intensif)
  • Service d'extraction : 5 répliques

Déploiement de Kubernetes :

# 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"

Avantages :

  • Utilisation optimale des ressources (chaque service selon les besoins)
  • Erreurs isolées (le crash OCR ne concerne pas l'API)
  • Déploiements indépendants (mise à jour de l'extraction sans downtime OCR)

CI/CD avec Kubernetes

GitOps : Infrastructure as Code

Concept :

  • Le référentiel Git comme source unique de vérité
  • Modifications par Git-Commit (pas de modification manuelle) kubectl apply)
  • Déploiement automatique via le pipeline CI/CD

Flux/ArgoCD (opérateurs GitOps) :

# 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

Avantages :

  • ✅ Piste d'audit (chaque modification dans l'historique Git)
  • ✅ Rollback simple (git revert)
  • ✅ Récupération après sinistre (recréation de cluster à partir de Git)

Exemple de pipeline CI/CD (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

Suivi et observabilité

Prometheus + Grafana Stack

Installation (casque) :

# 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)

Principaux indicateurs de performance :

  • Niveau du nœud : CPU, RAM, disque, réseau
  • Niveau du pod : Conteneur CPU/RAM, compte de redémarrage
  • Application : Taux de requête, latence, taux d'erreur
  • GPU : Utilisation du GPU, utilisation de la VRAM, température

Tableau de bord Grafana (exemple) :

┌─────────────────────────────────────────┐
│  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]               │
└─────────────────────────────────────────┘

Journalisation : pile ELK ou Loki

Loki (alternative légère à Elasticsearch) :

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

Avantages :

  • Agrégation centrale des logs sur tous les pods
  • Corrélation avec Metrics (Prometheus + Loki dans un tableau de bord)
  • Requêtes basées sur les étiquettes (similaires à Prometheus)

Sécurité : meilleures pratiques

1. politiques de réseau (microsegmentation)

# 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. normes de sécurité Pod

# 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. gestion secrète

# 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

Meilleure 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)

Meilleure alternative : l'intégration de Vault :

Optimisation des coûts

1. les instances spot / les VM préemptibles

AWS :

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

Tolérances Kubernetes :

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

Important : Uniquement pour les charges de travail sans état (stateless)

2. définir correctement les demandes de ressources

❌ Erreur : surprovisionnement

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

✅ Correct : optimiser après le monitoring

# 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. autoscaler de pod vertical (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

Dépannage

Le pod ne démarre pas

# 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

Crash répété du pod

# 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

Avez-vous trouvé cette page utile ?

Merci beaucoup pour vos commentaires !

Voulez-vous me donner un feedback ? (anonyme)

Nous développons des logiciels d'intelligence artificielle pour les entreprises et renonçons délibérément aux bannières publicitaires gênantes. Par le biais de nos articles, nous documentons des thèmes qui nous préoccupent, nous intéressent et financent également notre pain quotidien.

Comme nos contenus sont gratuits, vos commentaires sont nos félicitations.

Chaque auteur lit personnellement vos commentaires anonymes, même si les IA pourraient les automatiser, et intègre directement les suggestions constructives dans la prochaine révision ou les utilise comme source d'inspiration pour le prochain article.



    • Florian Zyprian
      (auteur)

      En tant que CTO chez Helm & Nagel GmbH, l'entreprise derrière la marque Konfuzio.

    fr_FRFR