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 dedepends_onetservice_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.0Une 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
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 unpg_upgrademanuel — 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.
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
healthyavant de dumper :docker compose exec db pg_dump -U postgres -Fc mydb > backup_$(date +%Y%m%d_%H%M%S).dumpSnapshot 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_dataVé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.
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 meilisearchSi 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 meilisearchAttendez que le healthcheck passe à
healthyavant de valider. Un service qui démarre mais qui n'est pas encorehealthyn'est pas un service prêt.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: 30sLe champ
start_periodest critique pour les services à démarrage lent (bases de données, moteurs de recherche) : il évite que Docker déclare le conteneurunhealthypendant la phase d'initialisation et déclenche un redémarrage prématuré.Consultez
docker-compose-depends-on-healthcheckpour la configuration complète deservice_healthysur PostgreSQL — le même principe s'applique à tout service qui a besoin d'un temps d'amorçage.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(ougit revertsi vous avez commité le bump).
2. Relancez uniquement le service concerné, sans recréer les volumes :docker compose up -d --no-deps --force-recreate meilisearch3. Vérifiez immédiatement les logs :
docker compose logs -f meilisearchLe flag
--no-depsest essentiel : il redémarre le service cible sans toucher aux autres conteneurs (base de données, cache, proxy). Sans lui,docker compose up -dpeut 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:rollbackCela 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égie | Sécurité des données | Temps de préparation | Rollback |
|---|---|---|---|
| `docker compose pull` + `up -d` direct | Aucune garantie — breaking changes non détectés | < 1 minute | Difficile si migration de données |
| Bump de tag versionné + backup de volume | Élevée — données sauvegardées avant tout changement | 10 à 20 minutes | Trivial : revert du tag + `up -d --no-deps` |
| Test sur staging avant prod | Maximale — breaking changes détectés hors prod | Variable selon l'env | Non nécessaire si le test a passé |
| Image pinnée par digest SHA256 | Élevée — immunisé contre le tag-overwrite | Identique 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.