Comment déployer un conteneur Docker et un conteneur de données associé, y compris le contenu?

18

Je commencerai par admettre que je suis assez nouveau pour Docker et que je peux aborder ce problème à partir d'un mauvais ensemble d'hypothèses ... faites-moi savoir si c'est le cas. J'ai vu beaucoup de discussions sur la façon dont Docker est utile pour le déploiement, mais aucun exemple de la façon dont cela est réellement fait.

Voici comment je pensais que cela fonctionnerait:

  1. créer le conteneur de données pour contenir certaines données persistantes sur la machine A
  2. créer le conteneur d'application qui utilise les volumes du conteneur de données
  3. faire du travail, potentiellement changer les données dans le conteneur de données
  4. arrêter le conteneur d'application
  5. valider et baliser le conteneur de données
  6. pousser le conteneur de données vers un référentiel (privé)
  7. tirer et exécuter l'image de l'étape 6 sur la machine B
  8. reprendre là où vous vous étiez arrêté sur la machine B

L'étape clé ici est l'étape 5, qui, selon moi, sauverait l'état actuel (y compris le contenu du système de fichiers). Vous pouvez ensuite pousser cet état vers un référentiel et le retirer ailleurs, vous donnant un nouveau conteneur qui est essentiellement identique à l'original.

Mais cela ne semble pas fonctionner de cette façon. Ce que je trouve, c'est que l'étape 5 ne fait pas ce que je pense ou l'étape 7 (tirer et exécuter l'image) "réinitialise" le conteneur à son état initial.

J'ai mis en place un ensemble de trois images et conteneurs Docker pour tester cela: un conteneur de données, un écrivain qui écrit une chaîne aléatoire dans un fichier dans le conteneur de données toutes les 30 s, et un lecteur qui évalue simplement echola valeur des données fichier conteneur et quitte.

Conteneur de données

Créé avec

docker run \
    --name datatest_data \
    -v /datafolder \
    myrepository:5000/datatest-data:latest

Dockerfile:

FROM ubuntu:trusty

# make the data folder
#
RUN mkdir /datafolder

# write something to the data file
#
RUN echo "no data here!" > /datafolder/data.txt

# expose the data folder
#
VOLUME /datafolder

Écrivain

Créé avec

docker run \
    --rm \
    --name datatest_write \
    --volumes-from datatest_data \
    myrepository:5000/datatest-write:latest

Dockerfile:

FROM ubuntu:trusty

# Add script
#
ADD run.sh /usr/local/sbin/run.sh
RUN chmod 755 /usr/local/sbin/*.sh

CMD ["/usr/local/sbin/run.sh"]

run.sh

#!/bin/bash

while :
do
    sleep 30s

    NEW_STRING=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)

    echo "$NEW_STRING" >> /datafolder/data.txt

    date >> /datafolder/data.txt

    echo "wrote '$NEW_STRING' to file"
done

Ce script écrit une chaîne aléatoire et la date / heure /datafolder/data.txtdans le conteneur de données.

Lecteur

Créé avec

docker run \
    --rm \
    --name datatest_read \
    --volumes-from datatest_data \
    myrepository:5000/datatest-read:latest

Dockerfile:

FROM ubuntu:trusty

# Add scripts
ADD run.sh /run.sh
RUN chmod 0777 /run.sh

CMD ["/run.sh"]

run.sh:

#!/bin/bash

echo "reading..."

echo "-----"

cat /datafolder/data.txt

echo "-----"

Lorsque je crée et exécute ces conteneurs, ils fonctionnent correctement et fonctionnent comme je m'y attendais:

Stop & Start sur la machine de développement:

  1. créer le conteneur de données
  2. exécuter l'écrivain
  3. lancez le lecteur immédiatement, voir le "pas de données ici!" message
  4. Attends un moment
  5. exécuter le lecteur, voir la chaîne aléatoire
  6. arrêter l'écrivain
  7. redémarrer l'écrivain
  8. exécuter le lecteur, voir la même chaîne aléatoire

Mais commettre et pousser ne fait pas ce que j'attends:

  1. créer le conteneur de données
  2. exécuter l'écrivain
  3. lancez le lecteur immédiatement, voir le "pas de données ici!" message
  4. Attends un moment
  5. exécuter le lecteur, voir la chaîne aléatoire
  6. arrêter l'écrivain
  7. valider et baliser le conteneur de données avec docker commit datatest_data myrepository:5000/datatest-data:latest
  8. pousser vers le référentiel
  9. supprimer tous les conteneurs et les recréer

À ce stade, je m'attends à exécuter le lecteur et à voir la même chaîne aléatoire, car le conteneur de données a été validé, poussé vers le référentiel, puis recréé à partir de la même image dans le référentiel. Cependant, ce que je vois en fait, c'est "pas de données ici!" message.

Quelqu'un peut-il expliquer où je me trompe ici? Ou, sinon, montrez-moi un exemple de la façon dont le déploiement se fait avec Docker?

Kryten
la source

Réponses:

22

Vous vous trompez sur le fonctionnement des volumes dans Docker. J'essaierai d'expliquer comment les volumes sont liés aux conteneurs Docker et aux images Docker et j'espère que les différences entre les volumes de données et les conteneurs de volumes de données deviendront claires.

Rappelons d'abord quelques définitions

Images Docker

Les images Docker sont essentiellement un système de fichiers union + métadonnées. Vous pouvez inspecter le contenu du système de fichiers union image docker avec la docker exportcommande, et vous pouvez inspecter les métadonnées d'une image docker avec la docker inspectcommande.

Volumes de données

du guide de l'utilisateur Docker :

Un volume de données est un répertoire spécialement désigné dans un ou plusieurs conteneurs qui contourne le système de fichiers Union pour fournir plusieurs fonctionnalités utiles pour les données persistantes ou partagées.

Il est important de noter ici qu'un volume donné (comme le répertoire ou le fichier qui contient des données) n'est réutilisable que s'il existe au moins un conteneur Docker l'utilisant. Les images Docker n'ont pas de volumes, elles n'ont que des métadonnées qui indiquent finalement où les volumes seraient montés sur le système de fichiers union. Les volumes de données ne font pas non plus partie du système de fichiers union des conteneurs Docker, alors où sont-ils? sous /var/lib/docker/volumessur l'hôte docker (pendant que les conteneurs sont stockés sous /var/lib/docker/containers).

Conteneurs de volume de données

Ce type spécial de conteneur n'a rien de spécial. Ce sont simplement des conteneurs arrêtés utilisant un volume de données dans le seul et unique but d'avoir au moins un conteneur utilisant ce volume de données. N'oubliez pas que dès que le dernier conteneur (en cours d'exécution ou arrêté) utilisant un volume de données donné est supprimé, ce volume deviendra inaccessible via l' option runer docker --volumes-from .

Utilisation de conteneurs de volumes de données

Comment créer un conteneur de volume de données

L'image utilisée pour créer un conteneur de volume de données n'a pas d'importance car un tel conteneur peut rester arrêté et remplir sa fonction. Ainsi, pour créer un conteneur de données nommé datatest_datapour un volume, il /datafoldervous suffit d'exécuter:

docker run --name datatest_data --volume /datafolder busybox true

Voici basele nom de l'image (une petite taille pratique) et trueest une commande que nous fournissons juste pour éviter de voir le démon docker se plaindre d'une commande manquante. Quoi qu'il en soit, après avoir un conteneur arrêté nommé datatest_datadans le seul but de vous permettre d'atteindre ce volume avec l' --volumes-fromoption de la docker runcommande.

Comment lire à partir d'un conteneur de volume de données

Je connais deux façons de lire un volume de données: la première est à travers un conteneur. Si vous ne pouvez pas avoir un shell dans un conteneur existant pour accéder à ce volume de données, vous pouvez exécuter un nouveau conteneur avec l' --volumes-fromoption dans le seul but de lire ces données.

Par exemple:

docker run --rm --volumes-from datatest_data busybox cat /datafolder/data.txt

L'autre façon consiste à copier le volume à partir du /var/lib/docker/volumesdossier. Vous pouvez découvrir le nom du volume dans ce dossier en inspectant les métadonnées de l'un des conteneurs utilisant le volume. Voir cette réponse pour plus de détails.

Travailler avec des volumes (depuis Docker 1.9.0)

Comment créer un volume (depuis Docker 1.9.0)

Docker 1.9.0 a introduit une nouvelle commande docker volumequi permet de créer des volumes:

docker volume create --name hello

Comment lire à partir d'un volume (depuis Docker 1.9.0)

Disons que vous avez créé un volume nommé helloavec docker volume create --name hello, vous pouvez le monter dans un conteneur avec l' -voption:

docker run -v hello:/data busybox ls /data

À propos de la validation et de la poussée des conteneurs

Il doit maintenant être clair que, puisque les volumes de données ne font pas partie d'un conteneur (le système de fichiers union), la validation d'un conteneur pour produire une nouvelle image Docker ne conservera aucune donnée qui serait dans un volume de données.

Faire des sauvegardes de volumes de données

Le guide de l'utilisateur du docker contient un bel article sur la sauvegarde de volumes de données .


Bon article qui remet en question les volumes: http://container42.com/2014/11/03/docker-indepth-volumes/

Thomasleveil
la source
Il semble que "l'image utilisée pour créer un conteneur de volume de données n'a pas d'importance" n'est pas tout à fait correcte. Essayez simplement avec une image "scratch" qui vous donnera "exec:" true ": fichier exécutable introuvable"
tcurdt
Malgré cette erreur, votre conteneur sera créé et remplira son rôle de détenteur de volume
Thomasleveil
1
Hm - ça vaut peut-être la peine d'ouvrir un problème pour ça alors.
tcurdt
non, ce comportement est attendu car l'image scratch est une image vide qui ne peut pas avoir le /bin/truebinaire (ou tout autre) de toute façon
Thomasleveil
1
Juste une chose. Vous avez dit que "dès que le dernier conteneur (en cours d'exécution ou arrêté) utilisant un volume de données donné est supprimé, docker détruira ce volume de données de / var / lib / docker / volumes.", Mais ce n'est en fait pas vrai: il suffit de voir: docs.docker.com/userguide/dockervolumes (les volumes de données persistent même si le conteneur lui-même est supprimé. Vous devez spécifier la docker rm -vcommande sur le dernier conteneur pour supprimer également un volume)
juanra
1

Vous pouvez également utiliser un conteneur de données Docker pour déployer le code

Je ne sais pas si c'est une bonne pratique, mais je le fais comme ça:

FROM ubuntu:trusty

# make the data folder
#
RUN mkdir /data-image

# in my case, I have a 
# ADD dest.tar /data-image/
#
# but to follow your example :
# write something to the data file
RUN echo "no data here!" > /data-image/data.txt

# expose the data folder 
#
VOLUME /datafolder

ENTRYPOINT cp -r /data-image/* /datafolder/

Vous pouvez maintenant pousser votre image et utiliser des volumes-from, etc ...

jmny
la source
C'est ce que je recherche, mais la réponse acceptée mentionne explicitement que cela ne peut pas être fait. Je vais l'essayer maintenant.
andho
1
Au deuxième coup d'œil, la réponse acceptée indique que les volumes (ou les données qu'ils contiennent) ne seront pas validés, mais vous pouvez ajouter les données dans le conteneur en utilisant COPYou ADDet créer le volume en utilisant VOLUMEdans le Dockerfile.
andho