Migrer depuis un docker-compose
Vous avez une application qui tourne avec docker compose up et vous voulez la
faire tourner sur Kontainers ? Bonne nouvelle : les concepts se correspondent
presque un pour un. Cette page donne la table de conversion, puis migre une stack
réaliste de bout en bout.
Table de correspondance
| docker-compose | Kubernetes | Notes |
|---|---|---|
services.<nom> | Deployment + Service | Le Service reprend le nom : les autres conteneurs le joignent par ce nom, comme dans compose |
image: | spec.containers[].image | Registre privé ? Il faudra un pull secret |
ports: (exposition web) | Ingress | HTTPS automatique — jamais de ports: publiés directement |
ports: (TCP brut) | Service NodePort ou LoadBalancer | Avec le label exposition: public sur les pods |
environment: | env: ou ConfigMap | Guide |
env_file: | ConfigMap (+ Secret pour le sensible) | envFrom: reproduit le comportement |
volumes: (named volume) | PersistentVolumeClaim | Guide |
volumes: (bind mount ./conf:...) | ConfigMap montée en volume | Pas de bind mount sur un cluster |
depends_on: | readinessProbe (+ initContainers au besoin) | Kubernetes redémarre jusqu’à ce que ça marche — les probes rendent ça propre |
restart: always | (comportement par défaut d’un Deployment) | Rien à faire |
deploy.resources | resources.requests | À poser d’emblée : sinon 0,1 vCPU / 200 Mi sont injectés et facturés |
networks: | (rien) | Tous les pods d’un namespace se joignent par nom de Service |
Ce qui ne se transpose pas
network_mode: host,privileged: true, montages de/var/run/docker.sock: rejetés par les politiques de sécurité — repensez le besoin ou parlez-en au support ;build:: Kubernetes ne construit pas d’images. Construisez et poussez vers un registre en amont (CI ou poste local), puis référencez l’image (guide registre privé à venir).
Migration guidée : web + base de données + volume
Le docker-compose.yml de départ, très classique :
services: web: image: ghcr.io/acme/mon-app:1.4 ports: - "8080:8080" environment: DATABASE_URL: postgres://app:secret@db:5432/app db: image: postgres:17-alpine environment: POSTGRES_USER: app POSTGRES_PASSWORD: secret POSTGRES_DB: app volumes: - dbdata:/var/lib/postgresql/datavolumes: dbdata:Sa traduction complète pour Kontainers — un seul fichier, prêt à adapter :
# --- Le volume de la base (remplace "volumes: dbdata") ---apiVersion: v1kind: PersistentVolumeClaimmetadata: name: dbdataspec: accessModes: [ReadWriteOnce] storageClassName: ceph-block-rwo resources: requests: storage: 10Gi---# --- Les secrets (remplacent les mots de passe en clair) ---apiVersion: v1kind: Secretmetadata: name: db-credentialsstringData: POSTGRES_USER: app POSTGRES_PASSWORD: changez-moi POSTGRES_DB: app DATABASE_URL: postgres://app:changez-moi@db:5432/app---# --- Le service "db" ---apiVersion: apps/v1kind: Deploymentmetadata: name: dbspec: replicas: 1 strategy: type: Recreate # volume RWO : jamais 2 pods db en même temps selector: matchLabels: {app: db} template: metadata: labels: {app: db} spec: containers: - name: postgres image: postgres:17-alpine envFrom: - secretRef: {name: db-credentials} resources: requests: {cpu: 250m, memory: 512Mi} volumeMounts: - name: data mountPath: /var/lib/postgresql/data volumes: - name: data persistentVolumeClaim: {claimName: dbdata}---apiVersion: v1kind: Servicemetadata: name: db # ← le nom que "web" utilise, comme dans composespec: selector: {app: db} ports: [{port: 5432}]---# --- Le service "web" ---apiVersion: apps/v1kind: Deploymentmetadata: name: webspec: replicas: 2 selector: matchLabels: {app: web} template: metadata: labels: {app: web} spec: containers: - name: web image: ghcr.io/acme/mon-app:1.4 env: - name: DATABASE_URL valueFrom: secretKeyRef: {name: db-credentials, key: DATABASE_URL} resources: requests: {cpu: 100m, memory: 256Mi} readinessProbe: # remplace depends_on httpGet: {path: /, port: 8080} initialDelaySeconds: 5---apiVersion: v1kind: Servicemetadata: name: webspec: selector: {app: web} ports: [{port: 8080}]---# --- L'exposition publique (remplace ports: "8080:8080") ---apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: web annotations: cert-manager.io/issuer: letsencryptspec: rules: - host: app.example.com http: paths: - path: / pathType: Prefix backend: service: {name: web, port: {number: 8080}} tls: - hosts: [app.example.com] secretName: web-tlsDéployez, puis vérifiez :
kubectl apply -f stack.yaml -n <votre-namespace>kubectl get pods -n <votre-namespace>Pointez ensuite votre DNS vers la plateforme — et votre application est en ligne, en HTTPS.
Les pièges de conversion à connaître
- Posez vos
resources.requestsdès la conversion — compose n’en exigeait pas, Kontainers en injecte sinon (et les facture) ; - La limite mémoire = la request : si votre conteneur consommait 800 Mi sous compose, demandez 1 Gi de request, pas 200 Mi (pourquoi) ;
depends_onn’existe pas : votre app doit tolérer une base pas encore prête au premier démarrage (elle redémarrera jusqu’à ce que ça passe — c’est normal et sain) ;- Quotas : 20 pods, 10 vCPU, 20 Gi de requests par namespace (les chiffres) — largement suffisant pour une stack compose typique, mais à connaître avant de scaler.