---
title: "Migrer depuis un docker-compose"
description: "Convertir un docker-compose.yml en manifests Kubernetes déployables sur Kontainers : table de correspondance complète et migration guidée d'une stack web + base de données."
source_url:
  html: https://docs.blackswift.cloud/migrer/depuis-un-docker-compose/
  md: https://docs.blackswift.cloud/migrer/depuis-un-docker-compose.md
---

# Migrer depuis un docker-compose

> Convertir un docker-compose.yml en manifests Kubernetes déployables sur Kontainers : table de correspondance complète et migration guidée d'une stack web + base de données.

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](https://docs.blackswift.cloud/deployer/exposer-en-https.md) — jamais de `ports:` publiés directement |
| `ports:` (TCP brut) | Service **NodePort** ou **LoadBalancer** | Avec le label [`exposition: public`](https://docs.blackswift.cloud/deployer/exposer-en-https.md#3-exposer-un-protocole-non-http) sur les pods |
| `environment:` | `env:` ou **ConfigMap** | [Guide](https://docs.blackswift.cloud/deployer/configmaps-et-secrets.md) |
| `env_file:` | **ConfigMap** (+ **Secret** pour le sensible) | `envFrom:` reproduit le comportement |
| `volumes:` (named volume) | **PersistentVolumeClaim** | [Guide](https://docs.blackswift.cloud/deployer/stockage-persistant.md) |
| `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](https://docs.blackswift.cloud/reference/mutations-et-politiques.md) |
| `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é](https://docs.blackswift.cloud/reference/limitations-connues.md) —
  repensez le besoin ou parlez-en au [support](https://docs.blackswift.cloud/depanner/contacter-le-support.md) ;
- **`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 :

```yaml
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/data
volumes:
  dbdata:
```

Sa traduction complète pour Kontainers — un seul fichier, prêt à adapter :

```yaml
# --- Le volume de la base (remplace "volumes: dbdata") ---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: dbdata
spec:
  accessModes: [ReadWriteOnce]
  storageClassName: ceph-block-rwo
  resources:
    requests:
      storage: 10Gi
---
# --- Les secrets (remplacent les mots de passe en clair) ---
apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
stringData:
  POSTGRES_USER: app
  POSTGRES_PASSWORD: changez-moi
  POSTGRES_DB: app
  DATABASE_URL: postgres://app:changez-moi@db:5432/app
---
# --- Le service "db" ---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: db
spec:
  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: v1
kind: Service
metadata:
  name: db                   # ← le nom que "web" utilise, comme dans compose
spec:
  selector: {app: db}
  ports: [{port: 5432}]
---
# --- Le service "web" ---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  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: v1
kind: Service
metadata:
  name: web
spec:
  selector: {app: web}
  ports: [{port: 8080}]
---
# --- L'exposition publique (remplace ports: "8080:8080") ---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
  annotations:
    cert-manager.io/issuer: letsencrypt
spec:
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service: {name: web, port: {number: 8080}}
  tls:
    - hosts: [app.example.com]
      secretName: web-tls
```

Déployez, puis vérifiez :

```bash
kubectl apply -f stack.yaml -n <votre-namespace>
kubectl get pods -n <votre-namespace>
```

Pointez ensuite votre [DNS](https://docs.blackswift.cloud/deployer/configurer-votre-dns.md) vers la plateforme —
et votre application est en ligne, en HTTPS.

## Les pièges de conversion à connaître

1. **Posez vos `resources.requests` dès la conversion** — compose n'en exigeait
   pas, Kontainers en injecte sinon
   ([et les facture](https://docs.blackswift.cloud/reference/facturation.md)) ;
2. **La limite mémoire = la request** : si votre conteneur consommait 800 Mi sous
   compose, demandez 1 Gi de request, pas 200 Mi
   ([pourquoi](https://docs.blackswift.cloud/reference/mutations-et-politiques.md)) ;
3. **`depends_on` n'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) ;
4. **Quotas** : 20 pods, 10 vCPU, 20 Gi de requests par namespace
   ([les chiffres](https://docs.blackswift.cloud/reference/quotas-et-limites.md)) — largement suffisant pour une
   stack compose typique, mais à connaître avant de scaler.

:::tip[PostgreSQL : encore mieux que le conteneur]
Plutôt que de porter votre conteneur `postgres`, Kontainers propose un opérateur
PostgreSQL managé (haute dispo, backups self-service) — voir
[vos permissions CNPG](https://docs.blackswift.cloud/reference/permissions-et-rbac.md#postgresql-managé-cnpg)
*(guide dédié à venir)*.
:::
