Le Blog de C-quad

Archive pour septembre 2014

Docker – Les images et comment faire communiquer deux conteneurs

Nous avons vu comment utiliser les conteneurs dans docker dans l’article « Docker – une petite révolution pour moi », nous allons maintenant voir comment gérer les images qui servent à construire notre conteneur.

Voir les images présentes en local

Dès que l’on crée un conteneur à partir d’une image, celle ci est stockée en local et peut être ré-utilisée. Pour voir la liste des images disponibles en local :

$ docker images
REPOSITORY                  TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
training/webapp             latest              31fa814ba25a        3 months ago        278.6 MB

Si l’on désire télécharger une image :

$ docker pull centos

Créer ses propres images

Pour créer ses propres images, deux solutions sont possibles :

  • Partir d’une conteneur existant
  • Créer un Dockerfile

En partant d’un conteneur existant :

$ docker run -i -t centos /bin/bash
bash-4.2# yum install mysql
bash-4.2# exit
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
1c97b8bd7df9        centos:centos7      "/bin/bash"         5 minutes ago       Exited (0) 8 seconds ago                     drunk_perlman 
$ docker commit -m "Ajout de mysql" -a="Cedric OLIVIER" 1c97b8bd7df9 cquad/centos:mysql
64b17daafd4bfbf2f4af84efbb2d551c4565470a1c4e6d0150af6deb8d4735da

En partant d’un DockerFile :

Il s’agit dans ce cas de créer un fichier qui décrit ce que l’on veut et l’on construit ensuite le conteneur à partir de ce fichier.
Dans notre cas cela donne le Dockerfile suivant :

# Fichier Dockerfile à partir de l'image Centos, on ajoute mysql
FROM centos
MAINTAINER Cédric OLIVIER <mail@exemple.com>
RUN yum install -y mysql

On lance ensuite la construction à partir du fichier Dockerfile ci dessus :

$ docker build -t="cquad/centos:mysql" .
Sending build context to Docker daemon  2.56 kB
Sending build context to Docker daemon 
Step 0 : FROM centos
 ---> 70214e5d0a90
Step 1 : MAINTAINER Cédric OLIVIER <mail@exemple.com>
 ---> Running in 539bff6918b2
 ---> 3cfce923bb60
Removing intermediate container 539bff6918b2
Step 2 : RUN yum install -y mysql
 ---> Running in a7e711864bfc
Loaded plugins: fastestmirror
Determining fastest mirrors
 * base: centos.mirror.fr.planethoster.net
 * extras: centos.mirror.fr.planethoster.net
 * updates: centos.quelquesmots.fr
Resolving Dependencies
--> Running transaction check
...
Complete!
 ---> 8d3d8442cb55
Removing intermediate container a7e711864bfc
Successfully built 8d3d8442cb55

Faire communiquer deux conteneurs

Une petite option qui pourra vous être bien utile, il est possible de nommer les conteneurs au lancement avec l’option --name

Nous allons ici nommer web le conteneur qui heberge notre application python Flask

$ docker run -d -P --name web training/webapp python app.py
add2f97c63b01b79f3a4a9d6ba26525b2fe8bb358569e893e54f53b4fe302d02
$ docker ps 
CONTAINER ID        IMAGE                    COMMAND             CREATED             STATUS              PORTS                     NAMES
add2f97c63b0        training/webapp:latest   "python app.py"     6 minutes ago       Up 6 minutes        0.0.0.0:49154->5000/tcp   web       

Nous avons un conteneur web maintenant nous allons créer un conteneur db :

$ docker run -d --name db training/postgres

La base de données ne sera accessible que par le conteneur web, nous n’avons pas passé l’option -p pour « exposer » le conteneur au réseau.

Pour pouvoir créer le lien entre les 2 conteneurs, nous devons stopper et supprimer le conteneur web :

$ docker rm -f web
web
$ docker run -d -P --name web --link db:db training/webapp python app.py

Nous relançons le conteneur avec l’option --link pour lier les 2 conteneurs ensemble. l’option --link recoit pour argument nom:alias.
Le nom correspond au nom que l’on a donné au conteneur, l’alias permet de donner un autre nom pour le conteneur web si l’on veut.

$ docker ps
CONTAINER ID        IMAGE                      COMMAND                CREATED             STATUS              PORTS                     NAMES
4bdbc71d428f        training/webapp:latest     "python app.py"        15 seconds ago      Up 13 seconds       0.0.0.0:49155->5000/tcp   web                 
02ca8208e75d        training/postgres:latest   "su postgres -c '/us   9 minutes ago       Up 9 minutes        5432/tcp                  db,web/db           

On constate dans le champs NAMES le lien entre les deux conteneurs.
 

Docker – Une petite révolution pour moi

Docker est une application open source qui se base sur les conteneurs. Elle permet de faire la même chose qu’avec de la virtualisation (uniquement si l’os de la machine virtualisée est basée sur du Linux) mais en économisant la virtualisation.  Extrait de wikipedia :

Contrairement aux machines virtuelles traditionnelles, un conteneur Docker n’inclut pas de système d’exploitation, à la place il s’appuie sur les fonctionnalités du système d’exploitation fourni par l’infrastructure sous-jacente

Cela permet donc d’avoir des environnements léger et peu consommateur de ressources. Docker permet aussi d’automatiser le déploiement. Avant d’aborder le déploiement, commençons par le début et voyons comment l’utiliser.

Débuter avec Docker

Pour l’installer sous Fedora, un simple appel à yum permet de l’installer :

yum install docker

Pour ceux qui veulent pouvoir en profiter sous Windows, il existe boot2docker, qui lui par contre fonctionne à base d’une machine virtuelle Linux qui hébergera docker.

Lancement simple

Docker permet de lancer des applications dans un conteneur via la commande docker run

Par exemple :

$ docker run fedora:20 echo "Hello World"
Hello World

docker run lance un conteneur, ensuite nous lui avons passé en argument une image fedora version 20. docker cherche l’image en premier lieu en local et si elle n’est pas présente, il va chercher sur le repository dockerHub.

Ensuite docker lance la commande echo « Hello World » dans le conteneur. Par contre dès que la commande est terminée le conteneur est terminé.

Lancement interactif

Lançons maintenant :

$ docker run -t -i fedora:20 /bin/bash
bash-4.2# 

Nous avons lancé la même image (fedora:20) sauf que cette fois ci nous avons demandé un terminal tty avec l’option -t dans le conteneur et l’option -i permet d’interagir avec ce terminal.
Nous avons lancé un shell avec /bin/bash qui va nous permettre de lancer des commandes dans le conteneur.

Pour quitter, de la même façon que le conteneur est stoppé quand le echo « Hello World » a terminé, le conteneur sera fermé quand le process /bin/bash sera terminé. Il suffit donc de le quitter avec un exit.

bash-4.2# exit
exit
$

Lancement d’un daemon (en tâche de fond)

Nous avons vu comment lancer une commande dans un conteneur, comment interagir avec un conteneur, mais il peut aussi être utile de pouvoir lancer un processus en tache de fond.

$ docker run -d fedora:20 sh -c "while true; do echo hello world; sleep 1; done"
5b1507abe7ed9094e0ef15bf4f90c86764c1b38fced6feb2d699e4dae5eaa79d

L’option -d nous permet de lancer le conteneur en tache de fond. Par contre, comme vous pouvez le constater par de traces de nos « hello world » toutes les secondes…
Quand on lance un conteneur en tache de fond, docker retourne un identifiant dans notre cas : 5b1507abe7ed9094e0ef15bf4f90c86764c1b38fced6feb2d699e4dae5eaa79d

On peut via la commande docker ps voir la liste des conteneurs en cours d’executions :

$ docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS               NAMES
5b1507abe7ed        fedora:20           "sh -c 'while true;    5 minutes ago       Up 5 minutes                            jolly_leakey        

On retrouve bien notre conteneur avec un nom défini aléatoirement par docker jolly_leakey.

Si on veut voir la sortie du conteneur, on utilise docker logs avec le nom du conteneur:

$ docker logs jolly_leakey
hello world
hello world
hello world

Nous allons maintenant arreter le conteneur avec la commande docker stop :

$ docker stop jolly_leakey
jolly_leakey
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

Notre conteneur est bien terminé.

Lancement d’un daemon sur le réseau

Nous allons maintenant lancer une application web qui tourne avec python Flask :

$ docker run -d -P training/webapp python app.py

L’option -P permet de pouvoir accéder à l’ensemble des ports ouverts à l’intérieur du conteneur à l’exterieur. L’application python Flask tourne sur le port 5000, mais ce n’est pas ce port qui sera utilisé en local pour accéder au conteneur. Pour connaitre l’association, nous lancons :

$ docker ps -l
CONTAINER ID        IMAGE                    COMMAND             CREATED             STATUS              PORTS                     NAMES
d749f39a560b        training/webapp:latest   "python app.py"     9 seconds ago       Up 7 seconds        0.0.0.0:49153->5000/tcp   boring_albattani    

Notre application est disponible sur le port 49153. Si on veut que le port local soit le même que le port interne 5000 dans notre cas, il faut lancer la commande suivante :

$ docker run -d -p 5000:5000 training/webapp python app.py
$ docker ps -l
CONTAINER ID        IMAGE                    COMMAND             CREATED             STATUS              PORTS                    NAMES
522394e84c05        training/webapp:latest   "python app.py"     5 seconds ago       Up 3 seconds        0.0.0.0:5000->5000/tcp   pensive_fermi    

Pour connaitre le port local sans faire appel à docker ps -l il existe une commande qui nous donne directement le mapping : docker port conteneur_name 5000

$ docker run -d -P training/webapp python app.py
26b92cf6f4aec2d59232dd664e5508423155426a487010b3c61d201ab2b80400
$ docker port 26b92 5000
0.0.0.0:49154

Vous constaterez qu’à la place du nom du conteneur, il est possible de passer les 4 premiers caractères de l’identifiant retourné au moment du lancement.

Relancer un conteneur arretté

Nous avons vu qu’a chaque fois que nous lancions docker run un nouveau conteneur est créé. Nous allons voir ici comment reprendre un conteneur qui a déjà été lancé.

$ docker start pensive_fermi
pensive_fermi
$ docker ps
CONTAINER ID        IMAGE                    COMMAND             CREATED             STATUS              PORTS                    NAMES
522394e84c05        training/webapp:latest   "python app.py"     About an hour ago   Up 18 seconds       0.0.0.0:5000->5000/tcp   pensive_fermi       

Suppression d’un conteneur

Une fois que l’on a fini avec un conteneur et que le décide de le supprimer, un simple docker rm permettra de la supprimer. Mais attention, la suppression est définitive.

$ docker stop pensive_fermi 
pensive_fermi
$ docker rm pensive_fermi 
pensive_fermi
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES