DevOps Elastic Hayway
Document

SUBSCRIBE TO GET FULL ACCESS TO THE E-BOOKS FOR FREE 🎁SUBSCRIBE NOW

Professional Dropdown with Icon

SUBSCRIBE NOW TO GET FREE ACCESS TO EBOOKS

Docker Compose vs Kubernetes : différences, même app, quand basculer

À la fin de ce tutoriel, vous saurez comparer Docker Compose et Kubernetes sur la même app (3 services), mapper chaque concept Compose vers les objets Kubernetes, migrer via Kompose ou Helm/Kustomize, et décider quand rester sur Compose, quand basculer, ou utiliser les deux.

Niveau : Intermédiaire · Temps estimé : 45–60 min · Versions testées : Docker Engine 27+ · Compose v2 (plugin) · Kubernetes 1.31+ · Dernière vérification : 2026-09-11

Prérequis

  • Docker Compose v2 : compose.yaml sans clé version:, plugin docker compose
  • Bases Kubernetes : Pods, Deployments, Services (tutoriel Kubernetes débutant)
  • Docker Engine 27+ (docker compose version OK) ; cluster local (kind/minikube) + kubectl pour la partie K8s
  • Terminal Linux / WSL2 / macOS · Coût : 0 € (lab local)

Réécriture FR originale 2026 de la page EN #4253 : même intention, contenu enrichi (mapping, pièges, FAQ, quiz).

Ce que nous allons construire

Lab « docker-compose-vs-kubernetes »
  ├── Rôles : Compose (1 hôte) vs Kubernetes (cluster)
  ├── Tableau comparatif « en un coup d’œil »
  ├── App 3 services : API + PostgreSQL + Redis (Compose)
  ├── Équivalent K8s : Deployment, StatefulSet, Service, ConfigMap, Secret
  ├── Mapping Compose → objets Kubernetes
  ├── Migration : Kompose · Helm/Kustomize · Compose pour le dev
  └── Guide de décision + FAQ + quiz

(Schéma à remplacer par une image locale Excalidraw / draw.io, alt : « Même app API + Postgres + Redis : à gauche compose.yaml sur un hôte Docker ; à droite Deployments/StatefulSet/Services sur un cluster Kubernetes ».)

Compose et Kubernetes ne résolvent pas le même problème : souvent Compose en dev/CI, Kubernetes en prod.

Rôles : portée de chaque outil

Docker Compose : app multi-conteneurs sur une machine. Un YAML, docker compose up, démarrage rapide — dev local, CI, petit mono-serveur.

Kubernetes orchestre un cluster : self-healing, HPA, rolling updates, CNI, stockage dynamique. Courbe et charge ops plus élevées — ou service managé (EKS, GKE, AKS).

La question n’est pas « lequel est meilleur ? », mais quel problème — et comment les deux coexistent.

Tableau : en un coup d’œil

Critère Docker Compose Kubernetes
Portée Un hôte (Docker Engine) Cluster de nœuds
Fichier compose.yaml (~50 lignes) Manifests (Deployment, Service, ConfigMap, Secret, Ingress, PVC…) ou Helm
Self-healing restart: sur le même hôte Reschedule sur nœuds sains ; remplace pods unhealthy
Scaling --scale sur une machine HPA + Cluster Autoscaler
Rolling updates Recreate (bref downtime) RollingUpdate + readiness, zéro downtime
Réseau Bridge, nom = DNS CNI, Services, Ingress / Gateway API
Config / secrets env, fichiers secrets ConfigMaps, Secrets, opérateurs externes
Stockage Volumes nommés, bind mounts PVC + StorageClasses
Courbe Heures Semaines
Charge ops Quasi nulle Upgrades, RBAC, observabilité (ou managé)
Usage typique Dev, CI, petit serveur Prod, microservices, multi-équipes

App échantillon : 3 services (Compose)

API (ghcr.io/example/api:1.4.0, port 8000) + PostgreSQL (volume) + Redis. Mot de passe DB via secret ; feature flag en config. L’image API est un placeholder : tout HTTP exposant /healthz convient.

compose.yaml moderne (sans version:)

services:
  api:
    image: ghcr.io/example/api:1.4.0
    ports: ["8080:8000"]
    environment:
      DATABASE_URL: postgres://app@db:5432/app
      REDIS_URL: redis://cache:6379
      FEATURE_NEW_CHECKOUT: "true"
    secrets: [db_password]
    depends_on:
      db: { condition: service_healthy }
      cache: { condition: service_started }
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/healthz"]
      interval: 10s
      retries: 3
    deploy:
      resources:
        limits: { memory: 256M }
    restart: unless-stopped

  db:
    image: postgres:17-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_DB: app
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets: [db_password]
    volumes: [pgdata:/var/lib/postgresql/data]
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 5s
      retries: 10

  cache:
    image: redis:7.4-alpine
    command: ["redis-server", "--maxmemory", "64mb", "--maxmemory-policy", "allkeys-lru"]

volumes:
  pgdata:

secrets:
  db_password:
    file: ./secrets/db_password.txt   # .gitignore — ne jamais committer
mkdir -p secrets && openssl rand -base64 24 > secrets/db_password.txt
docker compose up -d && docker compose ps
curl -s localhost:8080/healthz
docker compose up -d --scale api=3   # port hôte : un seul mapping
docker compose pull && docker compose up -d
docker compose down                  # -v pour effacer les volumes

~50 lignes, une commande, tout sur le laptop. Limites : scale API sans reverse proxy (un seul conteneur possède 8080) ; update = stop/start.

Équivalent Kubernetes

Même app, plusieurs objets. Postgres en StatefulSet (+ Service headless + PVC) ou base managée ; Redis en Deployment + Service ; API en Deployment + Service (+ Ingress).

# k8s/api.yaml — ConfigMap + Deployment + Service (extrait)
apiVersion: v1
kind: ConfigMap
metadata: { name: api-config }
data:
  DATABASE_URL: postgres://app@db:5432/app
  REDIS_URL: redis://cache:6379
  FEATURE_NEW_CHECKOUT: "true"
---
apiVersion: apps/v1
kind: Deployment
metadata: { name: api }
spec:
  replicas: 3
  selector: { matchLabels: { app: api } }
  strategy:
    rollingUpdate: { maxSurge: 1, maxUnavailable: 0 }
  template:
    metadata: { labels: { app: api } }
    spec:
      initContainers:
        - name: wait-for-db
          image: postgres:17-alpine
          command: ["sh", "-c", "until pg_isready -h db -U app; do sleep 2; done"]
      containers:
        - name: api
          image: ghcr.io/example/api:1.4.0
          ports: [{ containerPort: 8000 }]
          envFrom: [{ configMapRef: { name: api-config } }]
          env:
            - name: DB_PASSWORD
              valueFrom: { secretKeyRef: { name: db-credentials, key: password } }
          readinessProbe:
            httpGet: { path: /healthz, port: 8000 }
            periodSeconds: 5
          livenessProbe:
            httpGet: { path: /healthz, port: 8000 }
            periodSeconds: 10
          resources:
            requests: { cpu: 100m, memory: 128Mi }
            limits: { memory: 256Mi }
---
apiVersion: v1
kind: Service
metadata: { name: api }
spec:
  selector: { app: api }
  ports: [{ port: 80, targetPort: 8000 }]
kubectl create namespace shop
kubectl -n shop create secret generic db-credentials 
  --from-literal=password="$(openssl rand -base64 24)"
kubectl -n shop apply -f k8s/db.yaml -f k8s/api.yaml
kubectl -n shop port-forward svc/api 8080:80 &
curl -s localhost:8080/healthz

kubectl -n shop scale deployment/api --replicas=6
kubectl -n shop set image deployment/api api=ghcr.io/example/api:1.5.0
kubectl -n shop rollout undo deployment/api
kubectl -n shop autoscale deployment/api --min=3 --max=20 --cpu-percent=70

~150 lignes : 3 réplicas, update sans perte de requête, remplacement auto si un nœud tombe, autoscaling CPU.

Mapping concepts Compose → objets Kubernetes

Compose Kubernetes
services.api (stateless) Deployment + Service
services.db (stateful) StatefulSet + Service headless + PVC (ou DB managée)
ports: "8080:8000" Service ClusterIP + Ingress / Gateway
environment env ou ConfigMap (envFrom)
secrets Secret (fichier ou env)
volumes: pgdata PVC + StorageClass
healthcheck livenessProbe + readinessProbe
deploy.resources resources.requests / limits
depends_on Pas d’équivalent : probes + init + retries app
restart Toujours, via le controller
Nom service = DNS <svc>.<ns>.svc.cluster.local

Migration : de Compose vers Kubernetes

Option A — Kompose (premier jet)

kompose convert -f compose.yaml -o k8s/
kompose convert -f compose.yaml --chart -o chart/

Manifests valides rapidement, mais point de départ seulement : Deployments là où il faudrait un StatefulSet, depends_on ignoré, pas de probes/requests inventés.

Option B — Helm ou Kustomize à la main

Pour la prod, écrivez les manifests, puis paramétrez avec Helm ou Kustomize. Préférez les services managés pour le stateful (RDS, ElastiCache) si possible.

Garder Compose pour le développement

Migrer la prod ne veut pas dire abandonner Compose. Conservez compose.yaml pour le local et la CI. Tilt, Skaffold ou DevSpace offrent une boucle contre un cluster local si vous visez la parité.

Approfondir la migration (HowTo)

Convertissez par couche : Deployments/Services API+Redis (stateless) d’abord — probes et resources.requests — puis StatefulSet Postgres ou base managée (RDS). Clarifie le remplacement de depends_on, volumes et réseaux Compose.

En local, gardez compose.yaml v2 ; les mêmes images circulent vers kind/minikube. Sans équipe plateforme : Swarm ou k3s avant un EKS — Kubernetes débutant, Deployment.

Helm : factorisez replicaCount / image.tag / resources. Kustomize convient souvent mieux (overlays dev/prod). Documentez le mapping Compose → objets dans le README.

Terrain du milieu

  • Docker Swarm : Compose + deploy: multi-hôtes, rolling updates. Courbe minimale ; écosystème plus petit.
  • k3s : Kubernetes ~70 Mo ; 1–5 serveurs sans gros setup.
  • Plateformes managées (ECS/Fargate, Container Apps, Cloud Run) : scaling/updates sans exposer K8s.
  • Compose en CI : utile pour les tests d’intégration même si la prod est sur Kubernetes.

Guide de décision

Situation Choix
Un serveur, downtime OK, petite équipe, pas d’autoscaling Compose seul
Multi-machines, zero-downtime, recovery nœud, autoscaling, multi-équipes ou K8s déjà payé Basculer vers Kubernetes
Plus d’un hôte, pas d’équipe plateforme Swarm, k3s ou conteneur managé
Prod K8s + itération locale/CI rapide Les deux (Compose en dev, mêmes images)

Quoi que vous choisissiez en production, gardez Compose pour le local.

Critères décision (checklist 2026)

  1. Hôtes / SLO : un VPS → Compose ; multi-nœuds + zero-downtime → Kubernetes (ou managé).
  2. Ops : pas d’astreinte plateforme → Swarm/k3s/managé avant un cluster vanilla.
  3. Stateful : StatefulSet + backups/PVC, sinon RDS/équivalent.
  4. Parité images : Compose local reste le plus rapide pour onboarding — Docker débutant.
  5. Coût caché : control plane, CNI, observabilité (Prometheus/Grafana) > YAML initial.

Erreurs fréquentes

Piège Cause Correction
Crash-loop au démarrage K8s Ordre depends_on Retries app + readiness ; init en convenance
Mauvais placement pods Pas de resources.requests Toujours déclarer requests (+ limits mémoire)
DB instable / données perdues Postgres en Deployment StatefulSet + PVC, ou DB managée
Secrets dans ConfigMap / image Mauvais objet Secret + gestionnaire externe
Tout en NodePort Exposition brute Ingress ou Gateway API
Kompose tel quel en prod Jet non revu Revoir StatefulSet, probes, PSA, resources

2026 : Pod Security Admission (PSA), pas PSP ; images composants via registry.k8s.io.

FAQ

Compose remplace-t-il Kubernetes ?
Non. Portées différentes, souvent complémentaires (Compose = 1 hôte ; K8s = cluster).

Abandonner Compose en passant en prod K8s ?
Non. Gardez-le pour le dev et la CI ; les images restent les mêmes.

Kompose suffit-il pour la production ?
Non. Premier jet seulement ; peaufinez puis Helm/Kustomize.

StatefulSet ou base managée pour Postgres ?
Lab : StatefulSet + PVC. Prod : base managée (RDS, Cloud SQL…).

Compose v2 change-t-il le débat vs Kubernetes ?
Non. docker compose et la fin de version: modernisent le fichier ; la portée reste un hôte. K8s reste l’orchestrateur cluster — Compose v2.

Apprendre Swarm avant Kubernetes ?
Utile pour multi-hôtes sans équipe plateforme. Swarm est plus simple ; le marché favorise K8s — Swarm.

Secrets Compose → K8s ?
Lab Compose : .env gitignoré. K8s : Secret + (prod) gestionnaire externe ; jamais en ConfigMap ni dans l’image.

CI : Compose ou kind ?
Compose pour intégration API+DB (rapide). kind/minikube pour probes/Ingress/policies. Souvent Compose en CI courante, job K8s sur main.

Quiz (5 questions)

1. Quelle affirmation décrit le mieux Compose vs Kubernetes ?
– A. Compose gère un cluster multi-région ; Kubernetes est réservé au laptop
– B. Compose décrit une stack sur un hôte ; Kubernetes orchestre un cluster (self-healing, scaling)
– C. Les deux font exactement la même chose

2. Quel objet remplace typiquement un service Compose stateful (PostgreSQL) ?
– A. Un Job unique
– B. Un StatefulSet + Service headless + PVC (ou une base managée)
– C. Un ConfigMap seul

3. Bonne posture après une conversion Kompose ?
– A. Déployer tels quels en production
– B. Traiter comme un premier jet, puis corriger StatefulSets, probes et resources
– C. Supprimer Compose du dépôt

4. Pourquoi déclarer resources.requests sur les pods ?
– A. C’est purement cosmétique
– B. Pour le scheduling et éviter la contention silencieuse sur le nœud
– C. Pour remplacer Ingress

5. Bonne pratique secrets Compose → Kubernetes ?
– A. Mettre les mots de passe dans un ConfigMap partagé
– B. Secret K8s (+ gestionnaire externe en prod), jamais dans l’image
– C. Committer le .env pour la parité

Réponses : 1‑B · 2‑B · 3‑B · 4‑B · 5‑B

Pour aller plus loin

Maillage série (P3)

← Précédent Docker Compose v2 (docker-compose-v2)
→ Latéral Docker Swarm cluster & services (docker-swarm-cluster-services)
Aussi Deployment · Services · Helm · Tutoriel Docker débutant · Tutoriel Kubernetes débutant

Retour parcours Kubernetes — hub de la série et leçons sœurs.

Share your love

Leave a Reply

Your email address will not be published. Required fields are marked *