Tutoriel

Mettre à jour une stack Docker Compose en production

Déploiement9 min de lecture5 étapes

Un `docker compose pull` suivi d'un `up -d` : ça a toujours marché, jusqu'au jour où ça ne marche plus. Les breaking changes récents de Meilisearch v1.54, Supabase PostgreSQL 15→17, Langfuse v3→v4 et NocoDB 2026.09 l'ont confirmé brutalement — des instances stables, en production depuis des mois, irrécupérables après une mise à jour non préparée. Ce guide vous donne un protocole reproductible : avant de puller, vous sauvegardez ; avant de relancer, vous vérifiez les notes de version ; et si quelque chose casse, vous revenez à l'image précédente en moins de deux minutes.

Sommaire· Pourquoi `latest` est le vrai coupable1/9
  1. 01Pourquoi `latest` est le vrai coupable
  2. 02Ce que ce guide couvre — et ce qu'il ne couvre pas
  3. 03Étape 1 — Épingler toutes vos images
  4. 04Protocole de mise à jour — les 5 étapes
  5. 05Gardez la version précédente disponible localement
  6. 06Les breaking changes récents qui ont cassé des instances
  7. 07Stratégies de mise à jour : comparatif
  8. 08Intégrer ce protocole dans votre workflow
  9. 09Automatiser sans perdre le contrôle

Pourquoi `latest` est le vrai coupable

Quand une image Docker taguée latest est mise à jour dans le registry, votre docker compose pull la télécharge silencieusement. Aucun avertissement, aucun diff. Vous relancez la stack, et vous découvrez que le nouveau conteneur ne peut pas lire les données laissées par l'ancien.

C'est exactement ce qui s'est produit avec Meilisearch v1.54. Le moteur de recherche a introduit dans cette version un nouveau format de stockage vectoriel (passage d'arroy à HNSW par défaut) qui rend le répertoire de données incompatible avec les versions antérieures. Résultat : au démarrage, Meilisearch refuse d'ouvrir la base et entre en crash-loop. Le seul chemin de sortie propre est de créer un dump avant la mise à jour — opération impossible une fois le conteneur bloqué.

L'image latest ne résout pas la même chose selon l'heure du pull. Deux développeurs qui exécutent docker compose pull à douze heures d'intervalle peuvent tirer des versions différentes. Sur une stack de production, cette ambiguïté est inacceptable. La solution n'est pas de ne jamais mettre à jour : c'est de contrôler explicitement quelle version tourne et de décider consciemment quand passer à la suivante.

Ce que ce guide couvre — et ce qu'il ne couvre pas

  • Ce que ce guide couvre : le protocole pas-à-pas pour mettre à jour une stack Docker Compose sur un VPS — pinning de version, sauvegarde de volumes, vérification des notes de version, rollback rapide, healthchecks comme garde-fou.
  • Prérequis couverts par d'autres guides : la checklist de durcissement initiale (docker-compose-production-checklist), la configuration de depends_on et service_healthy (docker-compose-depends-on-healthcheck), et la comparaison des outils de mise à jour automatique comme Watchtower ou Diun.
  • Ce que ce guide ne recommande pas : Watchtower ou tout outil d'auto-pull en production — c'est précisément le contre-patron que les cas de breaking changes illustrent.
  • Public cible : développeurs et agences qui gèrent une ou plusieurs stacks Docker Compose en production sur VPS, avec accès root et volumes persistants.

Étape 1 — Épingler toutes vos images

La première action, avant toute mise à jour, est de remplacer chaque image: meili/meilisearch:latest ou image: supabase/postgres par une version explicite.

Deux formes sont acceptables :

- Tag de version : image: getmeili/meilisearch:v1.53.0 — lisible, versionnable dans git, facile à patcher.
- Digest SHA256 : image: getmeili/meilisearch@sha256:abc123… — immuable, garantit que vous tirez exactement le même artefact à chaque redéploiement, même si le tag a été réécrit (ce qui arrive sur les registries publics).

Pour connaître le digest d'une image déjà en cours d'exécution :

docker inspect --format='{{index .RepoDigests 0}}' getmeili/meilisearch:v1.53.0

Une fois vos images épinglées, committez le fichier docker-compose.yml dans git. Chaque bump de version devient un commit, ce qui vous donne un historique clair et un rollback trivial (git revert + docker compose up -d).

Protocole de mise à jour — les 5 étapes

  1. Lire les notes de version avant de puller

    Avant tout, consultez les release notes de la nouvelle version. Cherchez les mots breaking, migration, incompatible, pg_upgrade, dump. Ce n'est pas facultatif : Supabase a documenté explicitement que la mise à jour de PostgreSQL 15 vers 17 exige un pg_upgrade manuel — le conteneur PG 17 refuse de démarrer sur un volume PG 15, et le processus d'initialisation ne migre pas automatiquement les données.

    Pour Langfuse v4 (sorti le 17 août 2026), les SDKs Python v2 et antérieurs sont rejetés à l'ingestion par le nouveau stack — une rupture qui affecte tous les services clients qui tracent via l'ancienne API.

    Trois minutes de lecture vous évitent plusieurs heures de récupération de données.

  2. Sauvegarder les volumes avant le pull

    Ne pullez jamais avant d'avoir un backup exploitable. Pour les volumes nommés, deux approches :

    Dump applicatif (recommandé pour les bases de données) — le service doit être healthy avant de dumper :

    docker compose exec db pg_dump -U postgres -Fc mydb > backup_$(date +%Y%m%d_%H%M%S).dump

    Snapshot de volume brut — utile pour les stockages binaires (Meilisearch, Redis, MinIO) :

    docker run --rm \
      --volumes-from $(docker compose ps -q meilisearch) \
      -v $(pwd)/backups:/backup \
      alpine tar czf /backup/meili_$(date +%Y%m%d_%H%M%S).tar.gz /meili_data

    Vérifiez que le backup est lisible avant de continuer. Un fichier de dump corrompu découvert pendant la récupération est le scénario le plus coûteux qui soit.

  3. Puller la nouvelle image et tester hors ligne

    Mettez à jour le tag dans votre docker-compose.yml, puis pullez l'image sans redémarrer le service :

    docker compose pull meilisearch

    Si votre environnement le permet, testez la nouvelle image sur un clone du volume dans un environnement ddev ou sur une VM de staging avant de toucher à la production. Vérifiez dans les logs de démarrage qu'aucune erreur de migration ne s'affiche :

    docker compose up -d meilisearch
    docker compose logs -f meilisearch

    Attendez que le healthcheck passe à healthy avant de valider. Un service qui démarre mais qui n'est pas encore healthy n'est pas un service prêt.

  4. Vérifier les healthchecks

    Un healthcheck bien configuré est votre première ligne de détection. Il doit être présent sur chaque service critique de la stack, au format Compose v2 :

    healthcheck:
      test: ["CMD-SHELL", "curl -sf http://localhost:7700/health || exit 1"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

    Le champ start_period est critique pour les services à démarrage lent (bases de données, moteurs de recherche) : il évite que Docker déclare le conteneur unhealthy pendant la phase d'initialisation et déclenche un redémarrage prématuré.

    Consultez docker-compose-depends-on-healthcheck pour la configuration complète de service_healthy sur PostgreSQL — le même principe s'applique à tout service qui a besoin d'un temps d'amorçage.

  5. Rollback en cas de problème

    Si la nouvelle version ne démarre pas ou produit des erreurs, le rollback doit prendre moins de deux minutes. La procédure :

    1. Revenez au tag précédent dans docker-compose.yml (ou git revert si vous avez commité le bump).
    2. Relancez uniquement le service concerné, sans recréer les volumes :

    docker compose up -d --no-deps --force-recreate meilisearch

    3. Vérifiez immédiatement les logs :

    docker compose logs -f meilisearch

    Le flag --no-deps est essentiel : il redémarre le service cible sans toucher aux autres conteneurs (base de données, cache, proxy). Sans lui, docker compose up -d peut recréer la totalité de la stack.

    ⚠️ Si la nouvelle version a migré le format des données sur disque (cas Meilisearch v1.54, Supabase PG17), le rollback d'image ne suffit pas — c'est pourquoi le backup du volume est une précondition, pas une option.

Gardez la version précédente disponible localement

Avant de puller la nouvelle image, taguez l'image actuellement en production sous un nom de rétention :

docker tag getmeili/meilisearch:v1.53.0 getmeili/meilisearch:rollback

Cela vous permet de revenir à l'état exact en cas d'urgence, même si vous n'avez plus accès au registry ou si la connexion est lente. Sur un VPS avec une bande passante contrainte, ce tag local vous économise plusieurs minutes de téléchargement au pire moment.

Les breaking changes récents qui ont cassé des instances

Ces quatre exemples illustrent pourquoi le protocole ci-dessus n'est pas théorique.

Meilisearch v1.53 → v1.54 (2026) : introduction du store vectoriel HNSW comme format par défaut. Meilisearch refuse d'ouvrir un index créé avec l'ancien format arroy. Le démarrage entre en crash-loop avec Your database version is incompatible with your current engine version. La seule sortie propre est de créer un dump (meilisearch --db-path /data --import-dump /backup.dump sur la nouvelle version) — opération possible uniquement si vous avez exporté avant de mettre à jour.

Supabase Docker PostgreSQL 15 → 17 (migration activée le 17 juin 2026) : le conteneur supabase/postgres:17 ne peut pas lire un volume initialisé par PG 15. Supabase documente explicitement que le saut nécessite un pg_upgrade via un script dédié — le processus d'initialisation du conteneur ne le fait pas automatiquement. Sans migration préalable, la base ne démarre pas.

Langfuse v3 → v4 (GA le 17 août 2026) : la v4 abandonne les endpoints d'ingestion batch legacy au profit d'OpenTelemetry. Les SDKs Python v2 et antérieurs et les SDKs JS/TS v3 et antérieurs sont rejetés à l'ingestion dès le démarrage de la stack v4. Si vos services clients n'ont pas migré avant la mise à jour du serveur, ils perdent silencieusement toutes leurs traces.

NocoDB 2026.09.x : la série 2026.09 reconstruit les images Docker pour éliminer des dépendances vulnérables. Les installations utilisant des bind-mounts (./postgres, ./nocodb) au lieu de volumes nommés peuvent démarrer sur une base vide après le pull — NocoDB ne retrouve pas ses données si le chemin de montage a changé entre versions. Migration vers les volumes nommés requise avant la mise à jour.

Stratégies de mise à jour : comparatif

Faites défiler le tableau

StratégieSécurité des donnéesTemps de préparationRollback
`docker compose pull` + `up -d` directAucune garantie — breaking changes non détectés< 1 minuteDifficile si migration de données
Bump de tag versionné + backup de volumeÉlevée — données sauvegardées avant tout changement10 à 20 minutesTrivial : revert du tag + `up -d --no-deps`
Test sur staging avant prodMaximale — breaking changes détectés hors prodVariable selon l'envNon nécessaire si le test a passé
Image pinnée par digest SHA256Élevée — immunisé contre le tag-overwriteIdentique au tag versionnéIdentique au tag versionné

Intégrer ce protocole dans votre workflow

Un protocole qui reste dans un guide ne sert à rien. Pour qu'il soit appliqué systématiquement, externalisez la version dans un fichier .env versionné dans git :

# .env
MEILISEARCH_VERSION=v1.53.0
POSTGRES_VERSION=15.6
# docker-compose.yml
services:
  meilisearch:
    image: getmeili/meilisearch:${MEILISEARCH_VERSION}

Mettre à jour une version devient alors un commit unique sur .env — lisible dans git log, réversible par git revert, et déployable par CI/CD sans modifier le fichier Compose principal.

Pour les agences qui gèrent plusieurs stacks clients, créez un fichier CHANGELOG_INFRA.md par client : chaque mise à jour y est tracée avec la version précédente, la date, le backup effectué et l'issue de la mise à jour. C'est aussi ce qui vous protège contractuellement en cas d'incident ultérieur.

Automatiser sans perdre le contrôle

Si vous voulez être alerté des nouvelles versions sans auto-pull, Diun (Docker Image Update Notifier) surveille votre registry et vous envoie une notification (Slack, email, webhook) quand une nouvelle image est disponible. Vous restez décisionnaire sur le moment de la mise à jour.

C'est la différence fondamentale avec Watchtower : Diun notifie, Watchtower agit. Sur une stack de production avec des volumes persistants, la notification est le bon niveau d'automatisation — l'action reste manuelle et précédée du protocole ci-dessus.

Un VPS avec accès root pour appliquer ce protocole

Dumps complets, snapshots avant mise à jour, rollback sur une image précédente : ce protocole exige un accès root et un stockage local contrôlable. Un hébergement mutualisé ne donne pas ce niveau de contrôle sur les volumes Docker.

Besoin d'aide ?

Parcourez notre centre d'aide et notre FAQ, ou contactez notre équipe — rappel, WhatsApp ou e-mail. Support en français, anglais et arabe.

Écrire sur WhatsApps'ouvre dans un nouvel onglet