Compose et Kubernetes peuvent tous les deux exécuter les mêmes trois processus : une interface web, une API et Postgres. Compose est un projet sur un seul moteur. Kubernetes est un ensemble d’objets API qu’un plan de contrôle peut réorganiser. Ci-dessous se trouve un compose.yaml, les manifests qui le correspondent, et le moment où une équipe devrait changer d’outil.
Réponse courte
Choisissez Compose quand perdre la machine signifie que l’application est down, et que c’est acceptable. Choisissez Kubernetes quand un nœud peut disparaître et le Pod devrait démarrer ailleurs, ou quand vous exploitez déjà un cluster. Les deux outils lancent les conteneurs web, API et base de données. Seul Kubernetes a un scheduler, un Service qui suit les Pods prêts, et un historique de déploiement.
Les noms de service Compose sont des noms DNS sur le réseau projet. Les noms de Service Kubernetes sont des noms DNS à l’intérieur du namespace (api et api.demo.svc.cluster.local). http://api:3000 fonctionne dans les deux fichiers si le Service s’appelle api et écoute le port 3000.
Côte à côte
| Élément | compose.yaml | Kubernetes |
|---|---|---|
| Processus web, API, base de données | services.web, services.api, services.postgres |
Déploiement + modèle Pod |
| Port UI publié | ports: ["8080:80"] sur web |
Service ClusterIP, puis kubectl port-forward ou un Ingress |
| Adresse API | http://api:3000 |
Service api port 3000 |
| Paramètres non-secrets | environment |
ConfigMap app-config |
| Mot de passe | variable .env |
Secret app-secret |
| Disque de base de données | volume nommé pgdata |
PersistentVolumeClaim pgdata |
| Ordre de démarrage | depends_on avec service_healthy |
readinessProbe ; les clients réessaient |
| Vérification de santé | healthcheck à l’intérieur du conteneur |
readinessProbe et livenessProbe, exécutées par le kubelet |
| Redémarrage | restart: unless-stopped |
Le Déploiement recrée le Pod (restartPolicy: Always) |
| Copies supplémentaires de l’API | docker compose up --scale api=3 |
spec.replicas |
| Build | docker build, puis un tag d’image |
même référence d’image ; le cluster ne construit pas |
Le fichier Compose
change-me se substitue à un mot de passe. Mettez-le dans un fichier .env à côté du fichier Compose et laissez ce fichier en dehors de git. Compose lit .env automatiquement. Les détails de commande se trouvent dans la feuille de référence Docker Compose.
services:
web:
image: example/web:1.4.0
ports:
- "8080:80"
environment:
API_URL: http://api:3000
depends_on:
api:
condition: service_healthy
restart: unless-stopped
api:
image: example/api:1.4.0
environment:
DATABASE_URL: postgres://app:${POSTGRES_PASSWORD}@postgres:5432/app
depends_on:
postgres:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/health"]
interval: 10s
timeout: 3s
retries: 5
start_period: 10s
restart: unless-stopped
postgres:
image: postgres:16
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: app
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d app"]
interval: 5s
timeout: 3s
retries: 10
restart: unless-stopped
volumes:
pgdata:
Cette vérification wget s’exécute à l’intérieur de l’image, donc le binaire doit y exister. Construisez des tags avec la feuille de référence Dockerfile.
# --wait retourne un code non-zéro si une vérification de santé n'est jamais réussie
docker compose up -d --wait
docker compose ps
docker compose down -v
down -v supprime le volume pgdata. Utilisez-le en CI. Ne l’utilisez pas sur une base de données que vous aviez l’intention de conserver.
Les manifests Kubernetes
Enregistrez ceci sous shop.yaml et appliquez-le avec kubectl. La valeur du Secret doit correspondre à POSTGRES_PASSWORD ou l’API ne peut pas se connecter. Sur un cluster partagé, créez ce Secret en dehors du dépôt git et supprimez le bloc stringData.
apiVersion: v1
kind: Namespace
metadata:
name: demo
---
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: demo
data:
API_URL: "http://api:3000"
POSTGRES_USER: app
POSTGRES_DB: app
---
apiVersion: v1
kind: Secret
metadata:
name: app-secret
namespace: demo
type: Opaque
stringData:
POSTGRES_PASSWORD: change-me
DATABASE_URL: postgres://app:change-me@postgres:5432/app
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pgdata
namespace: demo
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
namespace: demo
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
securityContext:
fsGroup: 999
containers:
- name: postgres
image: postgres:16
ports:
- containerPort: 5432
env:
- name: POSTGRES_USER
valueFrom:
configMapKeyRef: {name: app-config, key: POSTGRES_USER}
- name: POSTGRES_DB
valueFrom:
configMapKeyRef: {name: app-config, key: POSTGRES_DB}
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef: {name: app-secret, key: POSTGRES_PASSWORD}
readinessProbe:
exec:
command: ["pg_isready", "-U", "app", "-d", "app"]
periodSeconds: 5
livenessProbe:
exec:
command: ["pg_isready", "-U", "app", "-d", "app"]
initialDelaySeconds: 15
periodSeconds: 10
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumes:
- name: data
persistentVolumeClaim:
claimName: pgdata
---
apiVersion: v1
kind: Service
metadata:
name: postgres
namespace: demo
spec:
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: demo
spec:
replicas: 1
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: example/api:1.4.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3000
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef: {name: app-secret, key: DATABASE_URL}
readinessProbe:
httpGet: {path: /health, port: 3000}
periodSeconds: 10
resources:
requests: {cpu: "100m", memory: 128Mi}
limits: {memory: 256Mi}
---
apiVersion: v1
kind: Service
metadata:
name: api
namespace: demo
spec:
selector:
app: api
ports:
- port: 3000
targetPort: 3000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: demo
spec:
replicas: 1
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: example/web:1.4.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
env:
- name: API_URL
valueFrom:
configMapKeyRef: {name: app-config, key: API_URL}
readinessProbe:
httpGet: {path: /, port: 80}
periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: web
namespace: demo
spec:
selector:
app: web
ports:
- port: 80
targetPort: 80
Les probes httpGet s’exécutent sur le kubelet, donc ces images n’ont pas besoin de wget. fsGroup: 999 permet à l’image officielle Postgres d’écrire sur son volume. imagePullPolicy: IfNotPresent convient à un tag chargé localement ; :latest bascule toujours par défaut à Always et contacte le registre.
kubectl apply -f shop.yaml
kubectl rollout status deployment/api -n demo
kubectl port-forward -n demo svc/web 8080:80
port-forward remplace le 8080:80 de Compose sur votre ordinateur portable. Les autres machines devraient utiliser un Ingress.
Une PVC sans StorageClass reste Pending (Pod Pending / FailedScheduling). Une limite qui est trop petite est OOMKilled. Un mauvais DATABASE_URL est CrashLoopBackOff. Une image manquante est ImagePullBackOff.
Laissez Postgres à une seule réplique. ReadWriteOnce ne montera pas le même disque sur deux nœuds. Utilisez un StatefulSet et des volumeClaimTemplates plus tard si vous avez besoin d’un nom stable et d’un volume par réplique.
Quand choisir Compose
Choisissez Compose quand tous ces éléments sont vrais :
- La pile tient sur une seule machine, y compris le disque pour Postgres.
- Une politique de redémarrage suffit quand un processus s’arrête.
- Les développeurs et la CI exécutent déjà
docker compose up. - Un Pod n’a pas besoin de se déplacer vers un autre nœud.
Gardez Compose pour la boucle interne même après que la production soit un cluster. Un changement de fichier et docker compose up est plus court qu’un push et un déploiement.
Quand choisir Kubernetes
Choisissez Kubernetes quand l’un de ces éléments est vrai :
- Vous avez besoin de plus d’un nœud ou un nœud peut être drained tandis que l’API continue de servir.
- Vous voulez un historique de déploiement enregistré et
kubectl rollout undopar Déploiement. - Plusieurs environnements doivent partager les mêmes manifests, avec de petites différences gérées par Helm ou Kustomize.
- L’équipe plateforme exécute déjà le cluster et s’attend à des demandes, limites et probes.
Une deuxième réplique n’est pas une raison suffisante. --scale lance déjà des conteneurs API supplémentaires sur un seul moteur. Passez quand le placement, les mises à jour ou la politique importent.
Voie intermédiaire
Compose en CI. Démarrez la pile, échouez le job si les vérifications de santé ne passent pas, puis supprimez les volumes :
docker compose up -d --wait
docker compose ps
docker compose down -v
kind pour un plan de contrôle local. Chargez les images web et API, puis appliquez shop.yaml. Le nœud peut toujours tirer postgres:16. Quel cluster local utiliser est couvert dans kind vs minikube vs k3d.
kind create cluster --name demo
kind load docker-image example/web:1.4.0 --name demo
kind load docker-image example/api:1.4.0 --name demo
kubectl apply -f shop.yaml
Kompose comme brouillon, pas comme pipeline. Depuis le répertoire qui contient compose.yaml :
kompose convert -f compose.yaml
Kompose écrit un fichier YAML par objet dans le répertoire courant. Examinez les probes, le mot de passe, imagePullPolicy et le type de Service avant que quelqu’un ne les applique. Kubernetes n’exécute pas compose.yaml lui-même.
Chemin de migration
- Épinglez les tags d’image en CI. Le cluster devrait référencer
example/api:1.4.0, pas un flottantlatestet pas un blocbuild:. - Séparez la configuration. Les non-secrets vont à la ConfigMap. Le mot de passe va à un Secret créé en dehors de git sur tout cluster partagé.
- Tournez chaque vérification de santé Compose en readiness probe. Gardez une liveness probe seulement pour une vérification qui signifie « redémarrer ce conteneur ».
- Créez la PVC et copiez les données avec votre propre sauvegarde.
docker compose down -vplus une nouvelle réclamation abandonne la base de données. - Appliquez
shop.yamlsur kind. Corrigez les pods Pending et les image pulls là. - Ajoutez les demandes et les limites, et regardez l’API sous charge avant de copier les chiffres.
- Mettez un Ingress devant web. Laissez
kubectl port-forwardpour le débogage. - Décidez où vivent les Postgres avant que les utilisateurs se déplacent : une base de données gérée, ou un StatefulSet avec sauvegardes.
- Appliquez sur le cluster partagé, exécutez
kubectl rollout status, puis changez DNS.
FAQ
Docker Compose et Kubernetes sont-ils la même chose ?
Non. Compose lance les conteneurs sur un seul moteur Docker et les connecte avec un réseau projet. Kubernetes stocke les Déploiements, Services et volumes dans une API et peut placer les Pods sur d’autres nœuds. L’image peut être identique. Le modèle d’objet ne l’est pas.
Quand devrais-je passer de Docker Compose à Kubernetes ?
Passez quand le processus doit survivre à une défaillance de nœud, déployer sans temps d’arrêt, ou partager un cluster que d’autres équipes exécutent déjà. Restez sur Compose quand une seule machine, une politique de redémarrage et un job CI suffisent. Une diapositive qui dit « production » ne signifie pas obligatoirement Kubernetes.
Kompose produit-il des manifests prêts pour la production ?
Il produit un premier brouillon. kompose convert -f compose.yaml écrit un Déploiement et un Service par service Compose, et une PersistentVolumeClaim pour les volumes nommés. Vous devez toujours modifier les probes, les Secrets, les limites de ressources et le type de Service avant que quelqu’un d’autre applique les fichiers.
Qu’est-ce qui remplace depends_on dans Kubernetes ?
Rien n’attend une fois au démarrage et puis se retire. Une readinessProbe retire un Pod des endpoints du Service jusqu’à ce qu’il puisse servir, et elle le fait continuellement pendant la vie du Pod. Les clients doivent réessayer. Un initContainer peut bloquer l’app container, mais ne remplace pas la probe.
Comment ce guide a été vérifié
Rédigé à la main à partir de la documentation officielle, chaque commande revérifiée, puis relu une seconde fois avant publication. Dernière relecture le .
Sources officielles consultées pour cet article

