Migration d'un conteneur docker entre deux hôtes Linux

Migration d'un conteneur docker entre deux hôtes Linux

Quand on change d’hôte Docker, on se dit souvent : “je copie, je relance, et c’est réglé”. Sauf qu’un service Docker, ce n’est pas juste une image : il y a aussi des volumes, des variables d’environnement, des ports, parfois une base de données… et c’est exactement là que ça casse si on va trop vite.

Ici, on va faire simple et propre : inventaire d’abord, migration des données ensuite, puis redéploiement (idéalement via Docker Compose) sur le nouvel hôte. Objectif : remettre tout en route comme avant, sans service qui démarre “vide” ni config qui se perd en chemin.


Conseils

  • Testez d'abord la procédure avec un service non critique.
  • Gardez l'ancien serveur actif pendant quelques heures voire jours, le temps de vous assurer que tous les services fonctionnent correctement.
  • Documentez tout ce que vous faites, cela vous aidera en cas d'erreur et pourra vous servir à nouveau plus tard.
  • Réalisez une sauvegarde avant de migrer. On n'est jamais trop prudent.

La préparation

Avant de toucher à quoi que ce soit, prenez quelques minutes pour faire l’inventaire. L’idée est simple : savoir exactement ce qui tourne, où sont les données, et comment tout est démarré. Un tableau rapide suffit largement (conteneurs, ports, volumes, images, variables d’environnement…).

‼️
Avant tout, pensez à réaliser une sauvegarde de votre système.

Docker Compose

L'utilisation de Docker Compose simplifie la migration, parce que l'inventaire est déjà réalisé. Si vous l'utilisez, vous avez fait 80 % du travail. Si vous ne l'utilisez pas encore, c'est LE moment de vous y mettre. Il y a de grandes chances que vous sachiez déjà si vous en avez et où ils sont stockés, sinon voici les commandes pour chercher des fichiers compose sur votre système :

find / -name "docker-compose.yml" 2>/dev/null
find / -name "compose.yaml" 2>/dev/null

Si des fichiers sont trouvés, c'est bien et cela vous aidera pour la suite !

Si aucun fichier compose n'est trouvé, la migration pourra être un peu plus complexe… mais pas d'inquiétude, on va voir ensemble les points essentiels à vérifier. Je vous invite néanmoins à étudier la possibilité de basculer sur ce mode de gestion des conteneurs, cela ne pourra que vous simplifier la vie.

Lister vos conteneurs

On liste tous les conteneurs, qu’ils soient démarrés ou arrêtés (ça permet de repérer les services oubliés) :

docker ps -a --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"

Et on note les informations nécessaires pour chaque conteneur : le nom, l'image source, les ports exposés et le statut.

Analyser les volumes / !\

Les volumes, c’est le point clé de la migration : c’est là que vivent vos données (config, bases, fichiers, historiques…).
Migrer une stack sans ses volumes, c’est redémarrer un service “neuf”. Donc ici, on prend le temps de comprendre comment chaque conteneur stocke ses données.

# Voir les volumes d'un conteneur spécifique
docker inspect nom-du-conteneur | grep -A 20 "Mounts"

# Lister tous les volumes peu importe leur type
docker ps -a --format "table {{.Names}}\t{{.Mounts}}"

# Lister l'ensemble des volumes de type local
docker volume ls
"Mounts": [
    {
        "Type": "bind",
        "Source": "/opt/data/homeassistant",
        "Destination": "/config",
        ...
    },
    {
        "Type": "volume",
        "Name": "influxdb-data",
        "Destination": "/var/lib/influxdb2",
        ...
    }
]

Premier tri rapide :

  • si vous voyez un chemin qui commence par / (ex : /opt/data/...), vous êtes sur un bind mount : c’est un dossier de l’hôte. Vous n'aurez qu'à copier le dossier et son contenu.
  • si vous voyez un nom de volume (ex : influxdb-data), c’est un volume Docker nommé : Docker le gère pour vous. Il y a un peu de travail de préparation, le mieux étant d'envisager le passage en volume de type bind.

Identifier le type d'images

Suivant le type d'image utilisée, vous pouvez la télécharger directement ou la transférer.

# Lister toutes vos images
docker images

# Pour chaque conteneur, voir l'image complète
docker inspect nom-du-conteneur | grep -E "Image"
# Exemple de résultats
docker images
REPOSITORY                    TAG       IMAGE ID       CREATED        SIZE
homeassistant/home-assistant  stable    abc123def456   2 weeks ago    1.2GB
postgres                      15        def456abc123   1 month ago    379MB
utcar-utcar                   latest    789xyz456def   3 months ago   856MB
nodered/node-red              latest    456def789xyz   2 weeks ago    558MB

Les images officielles Docker Hub (postgres, nginx, redis, alpine…) et celles d'organisations reconnues (homeassistant/home-assistant, nodered/node-red…) n'ont pas besoin d'être transférées : notez juste les versions utilisées, elles seront retéléchargées directement sur le nouvel hôte.

Pour les images personnalisées — celles sans / dans le nom (utcar-utcar, mon-app…), construites localement ou créées avec docker commit — il faudra les exporter et les transférer manuellement, on verra ça juste après.

Enfin, si vous avez des images modifiées sans trace documentée, profitez-en pour les reconstruire proprement depuis un Dockerfile, ou transférez-les en attendant.

On vérifie notre checklist pré-migration

Avant de continuer, assurez-vous que votre tableau récapitulatif comporte bien les informations suivantes :

  • Liste de tous vos conteneurs avec leurs noms
  • Type de volumes pour chaque conteneur (bind/volume)
  • Chemins des bind mounts ou noms des volumes
  • Liste des images avec leur classification (à télécharger/ à transférer)
  • Versions des images standards
  • Fichier compose existant
  • Liste des ports utilisés
  • Variables d'environnement importantes
  • Dépendance à l'adresse IP, autre remarque

La migration des données

Maintenant qu'on sait ce qu'on a, voyons comment le migrer. On va attaquer pour de bon…

‼️
Avant de toucher quoi que ce soit, pensez à faire une sauvegarde. Oui, encore. On ne le dira jamais assez.

Dans la mesure du possible, essayez de convertir vos volumes locaux en volumes de type bind avant de migrer, ça simplifie grandement le transfert.

Voici la procédure avec mon conteneur patchmon-database, dont le volume source est /var/lib/docker/volumes/patchmon_postgres_data/_data :

  1. Arrêtez la stack : docker compose down
  2. Copiez le contenu du volume vers votre dossier de stack : cp -RT /var/lib/docker/volumes/patchmon_postgres_data/_data /docker/stacks/patchmon/postgres-data
  3. Modifiez le volume dans le fichier compose.yaml : remplacez le volume nommé par un chemin relatif de type ./postgres-data, et supprimez la déclaration du volume en bas du fichier.
  4. Relancez : docker compose up -d
  5. Vérifiez que le volume apparaît bien en type bind avec docker inspect et que le service fonctionne normalement.

Si vous avez des erreurs de droits, ajustez les permissions du dossier : chmod -R 755 /docker/stacks/patchmon/postgres-data.

Migrer des volumes

Le but est de copier un dossier d'un serveur à l'autre, voici un exemple avec mon docker stirling-pdf

Depuis l'hôte source :

cd /docker/stacks/stirling-pdf  # ou là où sont vos données

# On arrête le docker
docker compose down

# On va dans le dossier de l'ensemble de nos stacks
cd /docker/stacks # A adapter suivant votre configuration

# Créer une archive
tar czf migration-data-stirling-pdf$(date +%Y%m%d).tar.gz stirling-pdf


# Vérifier la taille
ls -lh migration-data-*.tar.gz

# Transférer vers le nouvel hôte
scp migration-data-*.tar.gz user@IP-nouvel-hote:/tmp/

Si vous souhaitez utiliser l'utilisateur root mais que celui-ci n'a pas l'accès SSH activé, vous pouvez l'activer temporairement en éditant le fichier /etc/ssh/sshd_config et en modifiant les lignes suivantes :

PermitRootLogin yes
PasswordAuthentication yes

Redémarrez ensuite le service SSH avec la commande :

systemctl restart sshd
‼️
À la fin des transferts, n'oubliez pas de remettre ces lignes comme elles étaient.

Sur le nouvel hôte :

# Créer le dossier pour les stacks
mkdir -p /opt/stacks/

# Extraire l'archive
cd /tmp
tar xzf migration-data-stirling-pdf20251117.tar.gz -C /opt/stacks/

Migration des images

Les images standards identifiées lors de la préparation seront téléchargées automatiquement au redémarrage des stacks, ou alors vous pouvez simplement vous rendre dans le dossier de la stack et utiliser la commande docker compose pull.

Pourquoi télécharger plutôt que transférer ?
C'est plus rapide, plus simple, vous obtenez la dernière version optimisée pour votre architecture, et vous évitez de consommer de la bande passante entre vos serveurs.

Les images personnalisées sont à exporter depuis l'ancien serveur. Dans mon exemple je vais le faire pour l'image utcar-utcar :

# Sur l'hôte source
# Exporter chaque image personnalisée
cd /tmp/
docker save -o utcar-utcar.tar utcar-utcar:latest

# Vérifier les tailles
ls -lh *.tar

# Transférer
scp utcar-utcar.tar  user@IP-nouvel-hote:/tmp/
# Sur le nouvel hôte
# Charger les images
cd /tmp/
docker load -i utcar-utcar.tar

# Vérifier
docker images | grep utcar

Si vous aviez modifié un conteneur en direct avec docker commit :

# Sur l'hôte source : sauvegarder l'état actuel
docker commit mon-conteneur-modifie mon-conteneur-backup:$(date +%Y%m%d)
docker save -o mon-conteneur-backup.tar mon-conteneur-backup:*
scp mon-conteneur-backup.tar user@IP-nouvel-hote:/tmp/

# Sur le nouvel hôte
docker load -i mon-conteneur-backup.tar

Profitez de la migration pour créer un Dockerfile propre !

Déploiement

Tout est prêt, on passe à l'assemblage des différents éléments.

Vous avez préparé l'arborescence des répertoires et fichiers :

/opt
  ├──stack/
     ├── homeassistant/
     │  ├── compose.yaml
     │  ├── .env    
     │  ├── homeassistant-data/ 
     ├── nodered/
     │  ├── compose.yaml
     │  ├── .env    
     │  ├── nodered-data/

Vous transférez les fichiers compose.yaml et les volumes :

# Copier le compose.yaml si cela n'est pas fait en même temps que les volumes
scp compose.yaml user@IP-nouvel-hote:/opt/stacks/homeassistant/compose.yaml

# Les données ont déjà été transférées et extraites
# Vérifier qu'elles sont bien sur le nouvel hôte
ls -la

# Ajuster les permissions si nécessaire
sudo chown -R $USER:$USER .

Et enfin vous lancez la stack :

# Télécharger toutes les images standards
docker compose pull

# Charger les images personnalisées (si pas déjà fait)
docker load -i ~/utcar-utcar.tar

# Démarrer tous les services
docker compose up -d

# Suivre les logs
docker compose logs -f

Vérification et validation

Vérifiez que les conteneurs sont correctement lancés, que ceux ayant un healthcheck sont bien sains

# État des conteneurs
docker compose ps

# Tous doivent être "Up" avec leur uptime
# Si un conteneur est en "Restarting", check ses logs :
docker compose logs nom-du-service
# Voir les volumes montés
docker compose exec homeassistant ls -la /config

# Vérifier qu'on retrouve bien nos fichiers
docker compose exec homeassistant cat /config/configuration.yaml

Checklist de validation

Aidez-vous de votre tableau pour valider chaque étape :

  • Les répertoires, volumes et fichiers compose.yaml sont sauvegardés et déplacés.
  • Les services sur votre ancien hôte sont arrêtés pour éviter les conflits.
  • Les conteneurs sont bien démarrés et en bonne santé.
  • Les interfaces web sont accessibles.
  • Les données sont bien présentes (configurations, historiques…).
  • Les logs ne montrent pas d'erreurs critiques.
‼️
Attention : Sécurité SSH️
N’oubliez pas de revérouiller l’accès SSH du compte root après vos opérations. De cette façon vous réduisez les potentielles attaques.

Conclusion

Voilà, j'espère que ces explications auront été suffisamment claires pour que vous compreniez comment effectuer une migration de conteneurs.

La clé du succès ? Prendre son temps pour la préparation initiale. Les 30 minutes investies au début vous éviteront des heures de debug plus tard. Et n'oubliez pas : Docker Compose est votre meilleur ami. Si vous ne l'utilisez pas encore, cette migration est l'occasion parfaite de vous y mettre !

Si vous avez toujours des questions sur Docker ou avez besoin d'aide pour vous aiguiller dans la migration d'un service, n’hésitez pas à poser vos questions en commentaire ou à venir en discuter avec la communauté sur le groupe Telegram !