web-dev-qa-db-fra.com

Comment mettre à niveau un conteneur Docker après modification de son image

Disons que j'ai tiré le fonctionnaire mysql: 5.6.21 image .

J'ai déployé cette image en créant plusieurs conteneurs Docker.

Ces conteneurs fonctionnent depuis un certain temps jusqu'à la publication de MySQL 5.6.22. L'image officielle de mysql: 5.6 est mise à jour avec la nouvelle version, mais mes conteneurs fonctionnent toujours sous 5.6.21.

Comment puis-je propager les modifications apportées à l'image (c'est-à-dire mettre à niveau la distribution MySQL) vers tous mes conteneurs existants? Quelle est la bonne façon pour Docker de procéder?

453

Après avoir évalué les réponses et étudié le sujet, je voudrais résumer.

La façon dont Docker met à niveau les conteneurs semble être la suivante:

Les conteneurs d'application ne doivent pas stocker de données d'application . De cette façon, vous pouvez remplacer le conteneur d'applications par sa version la plus récente à tout moment en exécutant quelque chose comme ceci:

docker pull mysql
docker stop my-mysql-container
docker rm my-mysql-container
docker run --name=my-mysql-container --restart=always \
  -e MYSQL_ROOT_PASSWORD=mypwd -v /my/data/dir:/var/lib/mysql -d mysql

Vous pouvez stocker des données sur l'hôte (dans un répertoire monté en volume) ou dans un (des) conteneur (s) spécial (s) de données . En savoir plus à ce sujet

La mise à niveau d'applications (par exemple, avec yum/apt-get upgrade) au sein des conteneurs est considérée comme un anti-motif . Les conteneurs d'applications sont supposés être immuables , ce qui garantit un comportement reproductible. Certaines images d'application officielles (mysql: 5.6 en particulier) ne sont même pas conçues pour se mettre à jour automatiquement (apt-get upgrade ne fonctionnera pas).

Je voudrais remercier tous ceux qui ont donné leurs réponses, afin que nous puissions voir toutes les approches différentes.

512

Je n'aime pas monter de volumes en tant que lien vers un répertoire d'hôte. J'ai donc créé un modèle pour la mise à niveau des conteneurs Docker avec des conteneurs entièrement gérés par Docker. La création d'un nouveau conteneur de menu fixe avec --volumes-from <container> donnera au nouveau conteneur contenant les images mises à jour la propriété partagée des volumes gérés par le menu fixe.

docker pull mysql
docker create --volumes-from my_mysql_container [...] --name my_mysql_container_tmp mysql

En ne retirant pas encore immédiatement le my_mysql_container d'origine, vous avez la possibilité de revenir au conteneur de travail connu si le conteneur mis à niveau ne contient pas les données appropriées ou échoue à un test de validité.

À ce stade, je lance généralement tous les scripts de sauvegarde que j'ai pour le conteneur afin de me donner un filet de sécurité en cas de problème.

docker stop my_mysql_container
docker start my_mysql_container_tmp

Vous avez maintenant la possibilité de vous assurer que les données que vous vous attendez dans le nouveau conteneur sont présentes et d'exécuter un contrôle de cohérence.

docker rm my_mysql_container
docker rename my_mysql_container_tmp my_mysql_container

Les volumes du menu fixe resteront aussi longtemps que le conteneur les utilisera, ce qui vous permettra de supprimer le conteneur d'origine en toute sécurité. Une fois que le conteneur d'origine a été supprimé, le nouveau conteneur peut assumer le nom du conteneur d'origine pour que tout soit aussi joli qu'il était au début.

Ce modèle présente deux avantages majeurs pour la mise à niveau des conteneurs Docker. Premièrement, cela élimine le besoin de monter des volumes sur des répertoires hôte en permettant aux volumes d'être directement transférés vers des conteneurs mis à niveau. Deuxièmement, vous n'êtes jamais dans une position où il n'y a pas de conteneur docker en état de fonctionnement; Par conséquent, si la mise à niveau échoue, vous pouvez facilement revenir à la manière dont elle fonctionnait auparavant en rediffusant le conteneur d'origine.

75
kMaiSmith

Je voudrais ajouter que si vous souhaitez effectuer ce processus automatiquement (télécharger, arrêter et redémarrer un nouveau conteneur avec les mêmes paramètres que ceux décrits par @Yaroslav), vous pouvez utiliser WatchTower. Un programme qui met automatiquement à jour vos conteneurs quand ils sont modifiés https://github.com/v2tec/watchtower

23
Ricardo Polo

Juste pour fournir une réponse plus générale (pas spécifique à mysql) ...

  1. En bref

Synchroniser avec le registre des images de service ( https://docs.docker.com/compose/compose-file/#image ):

docker-compose pull 

Recréez le conteneur si l'image ou le fichier composé par docker a changé:

docker-compose up -d
  1. Contexte

La gestion des images de conteneur est l’un des motifs d’utilisation de docker-compose (voir https://docs.docker.com/compose/reference/up/ )

S'il existe des conteneurs pour un service et si la configuration ou l'image du service a été modifiée après la création du conteneur, docker-up-up enregistre les modifications en arrêtant et en recréant les conteneurs (en préservant les volumes montés). Pour empêcher Compose de prendre en compte les modifications, utilisez l'indicateur --no-receate.

L’aspect gestion des données étant également couvert par docker-compose via des "volumes" externes montés (voir https://docs.docker.com/compose/compose-file/#volumes ) ou un conteneur de données.

Cela laisse intact les problèmes potentiels de compatibilité ascendante et de migration des données, mais ce sont des problèmes "applicatifs", non spécifiques à Docker, qui doivent être vérifiés par rapport aux notes de publication et aux tests ...

20
Ronan Fauglas

Considérons pour cette réponse:

  • Le nom de la base de données est app_schema
  • Le nom du conteneur est app_db
  • Le mot de passe root est root123

Comment mettre à jour MySQL lors du stockage des données d'application dans le conteneur

Ceci est considéré comme une mauvaise pratique , car si vous perdez le conteneur, vous perdrez les données. Bien que ce soit une mauvaise pratique, voici une solution possible:

1) Faites un dump de base de données en tant que SQL:

docker exec app_db sh -c 'exec mysqldump app_schema -uroot -proot123' > database_dump.sql

2) mettre à jour l'image:

docker pull mysql:5.6

3) Mettez à jour le conteneur:

docker rm -f app_db
docker run --name app_db --restart unless-stopped \
-e MYSQL_ROOT_PASSWORD=root123 \
-d mysql:5.6

4) Restaurez le vidage de la base de données:

docker exec app_db sh -c 'exec mysql -uroot -proot123' < database_dump.sql

Comment mettre à jour le conteneur MySQL en utilisant un volume externe

Utiliser un volume externe est un meilleur moyen de gérer les données et facilite la mise à jour de MySQL. La perte du conteneur ne perdra aucune donnée. Vous pouvez utiliser docker-compose pour faciliter la gestion des applications Docker à conteneurs multiples dans un seul hôte:

1) Créez le fichier docker-compose.yml afin de gérer vos applications:

version: '2'
services:
  app_db:
    image: mysql:5.6
    restart: unless-stopped
    volumes_from: app_db_data
  app_db_data:
    volumes: /my/data/dir:/var/lib/mysql

2) Mettez à jour MySQL (à partir du même dossier que le fichier docker-compose.yml]):

docker-compose pull
docker-compose up -d

Remarque: la dernière commande ci-dessus met à jour l'image MySQL, recrée et lance le conteneur avec la nouvelle image.

20
Alexandre Verri

Réponse similaire à ci-dessus

docker images | awk '{print $1}' | grep -v 'none' | grep -iv 'repo' | xargs -n1 docker pull
15
Eddie Jaoude

Voici à quoi cela ressemble en utilisant docker-compose lors de la construction d'un Dockerfile personnalisé.

  1. Construisez d’abord votre fichier Docker personnalisé en ajoutant un numéro de version pour la différencier. Ex: docker build -t imagename:version . Ceci stockera votre nouvelle version localement.
  2. Exécuter docker-compose down
  3. Modifiez votre fichier docker-compose.yml afin de refléter le nouveau nom d'image que vous avez défini à l'étape 1.
  4. Exécutez docker-compose up -d. Elle recherchera localement l'image et utilisera celle qui a été mise à niveau.

-MODIFIER-

Mes étapes ci-dessus sont plus verbeuses que nécessaire. J'ai optimisé mon flux de travail en incluant le paramètre build: . dans mon fichier docker-compose. Les étapes ressemble à ceci maintenant:

  1. Vérifiez que mon fichier Docker est ce que je veux qu'il ressemble.
  2. Définissez le numéro de version du nom de mon image dans mon fichier docker-compose.
  3. Si mon image n'est pas encore construite: lancez docker-compose build
  4. Exécuter docker-compose up -d

Je ne m'en étais pas rendu compte à l'époque, mais docker-compose est assez intelligent pour mettre simplement à jour mon conteneur avec la nouvelle image avec la seule commande, au lieu de devoir le supprimer au préalable.

11
gdbj

Si vous ne voulez pas utiliser Docker Compose, je peux recommander portainer . Il a une fonction de recréation qui vous permet de recréer un conteneur tout en extrayant la dernière image.

4
beruic

Vous devez soit reconstruire toutes les images et redémarrer tous les conteneurs, soit mettre à jour le logiciel et redémarrer la base de données. Il n'y a pas de chemin de mise à niveau mais vous vous concevez vous-même.

3
seanmcl

Prenant de http://blog.stefanxo.com/2014/08/update-all-docker-images-at-once/

Vous pouvez mettre à jour toutes vos images existantes à l'aide du pipeline de commandes suivant:

docker images | awk '/^REPOSITORY|\<none\>/ {next} {print $1}' | xargs -n 1 docker pull
3
gvlx

J'ai eu le même problème alors j'ai créé docker-run , un outil de ligne de commande très simple qui s'exécute dans - conteneur docker pour mettre à jour les packages dans d'autres conteneurs en cours d'exécution.

Il utilise docker-py pour communiquer avec les conteneurs de dockers en cours d'exécution et mettre à jour les packages ou exécuter une commande unique arbitraire.

Exemples:

docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run exec

par défaut, la commande date est exécutée dans tous les conteneurs en cours d'exécution et les résultats sont renvoyés, mais vous pouvez émettre n'importe quelle commande, par exemple. docker-run exec "uname -a"

Pour mettre à jour les paquets (n'utilisant actuellement qu'apt-get):

docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run update

Vous pouvez créer un alias et l'utiliser comme une ligne de commande normale, par exemple.

alias docker-run='docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run'

2
iTech

Assurez-vous que vous utilisez des volumes pour toutes les données persistantes (configuration, journaux ou données d'application) que vous stockez dans les conteneurs liés à l'état des processus à l'intérieur de ce conteneur. Mettez à jour votre fichier Docker et reconstruisez l'image avec les modifications souhaitées, puis redémarrez les conteneurs avec vos volumes montés à leur emplacement approprié.

2
Daniel Dinnyes

Même si le conteneur que je souhaite mettre à jour fait partie du groupe docker-compose, je peux toujours mettre à jour un conteneur individuel avec ces deux commandes:

docker pull image.uri.io:latest
docker restart the-container

À condition que

docker ps --format 'table{{.Names}}\t{{.Image}}'
NAMES              IMAGE
the-container      image.uri.io:latest

L'avantage de cette méthode est qu'il n'est pas nécessaire d'exécuter docker run et de répéter tous ces paramètres de création comme dans le réponse de @ Yaroslav .

1
Yuriy Pozniak

C'est quelque chose avec lequel j'ai également lutté pour mes propres images. J'ai un environnement de serveur à partir duquel je crée une image Docker. Lors de la mise à jour du serveur, j'aimerais que tous les utilisateurs qui exécutent des conteneurs basés sur mon image Docker puissent effectuer la mise à niveau vers le dernier serveur.

Idéalement, je préférerais générer une nouvelle version de l'image Docker et faire en sorte que tous les conteneurs basés sur une version précédente de cette image soient automatiquement mis à jour vers la nouvelle image "en place". Mais ce mécanisme ne semble pas exister.

La conception optimale suivante que j'ai pu concevoir jusqu'à présent consiste à fournir un moyen de mettre à jour le conteneur lui-même - de la même manière qu'une application de bureau vérifie les mises à jour, puis se met à niveau. Dans mon cas, cela impliquera probablement de créer un script qui implique que Git tire une étiquette bien connue.

L'image/conteneur ne change pas réellement, mais les "internes" de ce conteneur changent. Vous pouvez imaginer faire la même chose avec apt-get, yum ou avec tout ce qui est approprié pour votre environnement. Parallèlement à cela, je mettrais à jour myserver: la dernière image du registre afin que tous les nouveaux conteneurs soient basés sur la dernière image.

Je serais intéressé de savoir s'il existe un état de la technique qui aborde ce scénario.

1
bjlevine