100% ont trouvé ce document utile (6 votes)
2K vues320 pages

Docker

Transféré par

Baderou Abdoulaziz
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
100% ont trouvé ce document utile (6 votes)
2K vues320 pages

Docker

Transféré par

Baderou Abdoulaziz
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

1:

-1-
:)

::1
Il
1:--

Pierre. . Yves Cloux


Thomas Garlot
Johann Kohler
Illustration de couverture : © eyetronic - [Link]

Le pictogramme qui figure ci-contre d'enseignement supérieur, provoquant une


mérite une explication. Son objet est baisse brutale des achats de livres el de
d'alerter le lecteur sur la menace que rewes, au point que la possibilité même pour
représente pour l'avenir de l'écrit,
particulièrement dans le domaine DANGER
de l'édition technique el universi·
taire, le développement massif du
photocopilloge.
® les auteurs de créer des œwres
nouvelles et de les faire éditer cor-
redemenl est aujourd'hui menacée.
Nous rappelons donc que Ioule
reproduction, partielle ou lolole,
Le Code de la propriété intellec- de la présente publication est
tuelle du 1er juillet 1992 interdit lE PlfJTOCaWŒ interdite sans autorisation de
en effet expressément la photoco· TUE LE LIVRE l'auteur, de son éditeur ou du
pie à usage collectif sons aulori· Centre français d'exploitation du
sation des ayants droit. Or, celte pratique droit de copie (CFC, 20, rue des
s'est généralisée dans les établissements Grands-Augustins, 75006 Paris).

l:J
0
c
::J
© Dunod, 20 16
0 11 rue Paul Bert, 92240 Malakoff
\.0
.-t [Link]
0
N
@ lSBN 978-2-10-075350-5
.......
..c:
O'l
·;::
>-
0.. Le Code de Io propriété intellectuelle n'oulorisont, aux termes de l'article
0
u L. 122-5, 2° et 3° a), d'une part, que les «copies ou reproductions strictement
réservées o l'usage privé du copiste et non destinées o une utilisation collective »
et, d'autre part, que les analyses et les courtes citations dons un but d'exemple el
d' illustration, cc toute représentation ou reproduction intégrale ou partielle faite
sons le consentement de l'a uteur ou de ses ayants droit ou ayants couse est
illicite ,. (art. L. 122-4).
Cette représentation ou reproduction, por quelque procédé que ce soit, constitue-
rait donc une contrefaçon sanctionnée por les articles L. 335-2 et suivants du
Code de Io propriété intellectuelle.
Table des matières

Avant,propos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . XI

Première partie - Les conteneurs : principes, objectifs et solutions

Chapitre 1 - Les conteneurs et le cas Docker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3


1.1 La conteneurisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1 .1 .1 L'histoire des conteneurs intermodaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.2 Les avantages d'un transport par conteneur .. ........... . ............... . 5
1.1.3 Extrapolation au monde logiciel ....................................... . 5
1.1.4 Les différences avec la virtualisation matérielle ........................... . 6
"'Cl
0
1.2 Les fondations: Linux, CGroups et Namespaces ........................ .. 9
c ~
,.,
0
:::i
"O 1.2 .1 Docker= Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
[Link];
\.0
.-t ~
V
1.2.2 CGroups................ ... ............. . ............... . .......... 10
0
N V

@
'ii
·c 1.2 .3 N amespaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ÎÎ
....... B
..c
:::;
CO 1.2.4 Qu'est,ce qu'un conteneur finalement?................................. ÎÎ
O'l c
0
ï::::: c
>-
o. c 1.3 Les apports de Docker : structure en couches, images, volumes et registry .... IT
u
0 ·3ù
:::;
"O
0
1.3 .1 La notion d'image ................................................... . IT
....
c.
~ 1.3.2 Organisation en couches : union file system ............................. . IT
~
:::;
rS 1.3 .3 Docker Hub et registry ....................... ........................ . T4
17
1
"O
0
1.3.4 Copy on write, persistance et volumes . ....................... .. ........ .
c
8
(Ç)
S Docker

1.4 Les outils de l'écosysteme des conteneurs : Docker et les autres . . . . . . . . . . . . . 20


1 .4 .1 Les moteurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.4.2 Les OS spécialisés.... .... ....... . .... .... . . ..... ........... ..... ..... 22
1.4.3 Les outils d' orchestration: composition et clustering....................... 22

Chapitre 2 - Conteneurs et infrastructures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

2.1 Automatiser la gestion de l'infrastructure : du IaaS au CaaS. . . . . . . . . . . . . . . . 25


2.1.1 Virtualiser l'infrastructure ............................................ . 25
2.1.2 Le conteneur n'est-il qu'un nouveau niveau de virtualisation ? ... . ......... . 27
2.1. 3 I.: apport du modèle de déploiement CaaS ............................... . 29
2.1.4 I.: architecture générique d'une solution CaaS ............................ . 32
2.2 Les solutions CaaS .................................................... . 35
2 .2. 1 Docker Datacenter : vers une suite intégrée ............................. . 35
2.2. 2 Kubernetes : l'expérience de Google offerte à la communauté .... . ......... . 39
2. 2. 3 DCOS : le cas Apache Mesas et Marathon ... . ..... . ......... .. .... .. .. . 43
2. 2. 4 Fleet + Rkt + Etcd : la solution de CoreOS ......... .... ... . ............ . 45
2 .2. 5 Les offres cloud de container service .. ... .......... . ......... .. ......... . 45
2.3 Ansible, Chef et Puppet : objet et lien avec Docker et CaaS .............. . 46
2 .3 .1 Objectif de ces solutions .. . .... . ..... .. ... .. ... ... ... .. ... ... .... .. ... . 46
2.3. 2 Un exemple: Ansible .... . ......... ... ........ . ..... ... ......... . .... . 48
2. 3.3 Le lien avec Docker et les solutions CaaS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ST
2 .3 .4 Controller Kubernetes avec Puppet ou Chef. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

"'Cl
0
c Deuxième partie - Docker en pratique : les outils de base
:::i
0
\.0
C: Chapitre 3 - Prise en main . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
N

@ 3 .1 Installation de Docker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
.......
-§i 3 . l. l Docker Toolbox : la solution rapide pour Windows et Mac OS X. . . . . . . . . . . . 55
ï:::::
~ 3 .1 . 2 Linux sous VirtualBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
u
3.2 Votre premier conteneur.... . .......... ...... ............ .......... ..... 64
3 .2. 1 Kitematic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
3 .2. 2 Le client Docker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
3 .2. 3 API Docker Remote . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Table des matières 0
Chapitre 4 - Docker sur un serveur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
4 .1 Docker Machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
4. 1 . 1 Installation de Docker Machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
4 .1 . 2 Prise en main de Docker Machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4 .1 .3 La commande docker-machine create . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
4 .1 .4 Installation de Docker avec Docker Machine sur Amazon AWS . . . . . . . . . . . . . 77
4 .1 .5 Installation de Docker avec Docker Machine et Oracle VirtualBox . . . . . . . . . . . 81
4.1 .6 Quelques autres commandes utiles...................................... 82

4.2 Project Atomic: la distribution Docker de Fedora......................... 85


4. 2. 1 Préparer l'image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
4. 2. 2 Création de la VM Atomic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
4.2.3 Lancement et configuration de devicemapper............................. 92

Chapitre 5 - Conteneurs et images. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97

5.1 Le cycle de vie du conteneur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97


5 .1 .1 Créer et démarrer un conteneur (commande run) . . . . . . . . . . . . . . . . . . . . . . . . . 98
5 .1 . 2 Stopper un conteneur (commande stop ou kill) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
5 .1 .3 Détruire un conteneur (commande rm) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
5 .1 .4 La commande create.................................................. 102
5.2 Accéder au conteneur et modifier ses données............................ 103
5. 2 .1 Connexion en mode terminal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
5.2.2 Créerunvolume ..................................................... 105
5. 2. 3 Monter un répertoire de notre hôte dans un conteneur . . . . . . . . . . . . . . . . . . . . . 108
"'Cl
0
c ~
,., 5 . 2. 4 La configuration des ports IP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
:::i
"O
0 [Link];
\.0 5 .3 Construire une image Docker originale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
.-t ~
0 V
N V
'ii
5 .3 .1 Lister les images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ÎÎÎ
@ ·c
....... [Link]; 5 .3. 2 Charger et effacer des images. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
..c CO
O'l c
ï::::: 0
c 5. 3. 3 Créer une image à partir d'un conteneur. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
>-
o. c
u
0 ·3ù 5.4 Le [Link].......................................................... 115
:::;
"O
0
....
c. 5 .4 .1 Les risques d'une création d'image par commit. . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
~
~
:::; 5. 4. 2 Programmer la création des images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
rS
"O
1 5 .4 .3 Quelques explications. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
0
c
8
(Ç)
El--------------------------- Docker

Troisième partie - Apprendre Docker

Chapitre 6 - Prise en main du client Docker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123


6.1 Introduction à la CU Docker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
6 .1 .1 Les variables d'environnement Docker. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
6 .1 . 2 Les options des commandes Docker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
6.2 Les commandes système.... ....... ... .......... . .. .... ... .. .... .. ... ... 128
6.2.1 docker daemon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
6.2.2 docker info.......................................................... 129
6.2.3 docker version.............. ....... ........... ..... ...... . .... . . .... . 129
6.2.4 docker stats................ . ... .... ............. ... ............. .... 129
6.2.5 docker ps........................................................... 130
6.2.6 dockerevents ................................... . .. . ............ . .... 130
6. 2 .7 docker inspect . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

6.3 Cycle de vie des conteneurs............................................. 132


6 .3 .1 docker start . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 2
6.3.2 docker stop ....... ... .. ... .... .. ... .. .... .. .... ... ....... ... ... ... .. . 132
6.3.3 docker kill........................................................... 132
6.3.4 dockerrestart....... . .......... .. ... .. .......... . ..... .......... . . ... 132
6 .3 .5 docker pause et docker unpause . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
6.3.6 dockerrm........................................................... 133
6. 3.7 docker wait . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 3
6 .3 .8 doclœr update . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 4
-0
0
c 6. 3 .9 doclœr create et docker run ........................................... . 134
:::i
0
\.0
6.4 Interactions avec un conteneur démarré ......... ...... ..... . ..... .. ..... . 136
.-t
0
N
6 .4 .1 doclœr logs ... . .. ... .......... . .................... .. ........... . ... . 136
@
.......
6 .4. 2 docker exec ........................................................ . 137
..c
O'l
ï:::::
6. 4. 3 docker attach .................. . .. .............. . ................... . 138
>-
0.
0 6. 4. 4 doclœr rename .... .. ....... ... .... ... . .. .............. ... .... ... .... . 138
u
6.4.5 dockercp . .... . .. ..... .. ....... ... ...... . . .. ... .... ... .. .... . .... .. . 139
6. 4. 6 docker diff ......................... · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · 139
6.4.7 docker top.. ........................................................ 140
6. 4. 8 doclœr export . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
6. 4. 9 docker port . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
Table des matières ------------------------8
6.5 Commandes relatives aux images. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
6. 5 . 1 docker build . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
6.5.2 dockercommit ....................................................... 142
6.5.3 docker history ... ... .......... . .... ... ........ .. ... ... ....... .... .... 142
6.5.4 docker images....................................................... 142
6. 5 .5 docker rmi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
6. 5 .6 docker save et docker load . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
6. 5. 7 docker import. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
6.6 Interactions avec le registry.................... .... ..................... 143
6. 6. 1 docker login . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
6. 6. 2 docker logout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
6. 6 .3 docker push .. .. .. . .. . .. . . .. . . . . . . . .. .. . . . .. . .. . . . .. . .. . .. .. . . . . . . .. . 144
6.6 .4 docker pull.......................................................... 144
6. 6 .5 docker search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
6.6.6 docker tag.................................................. . ........ 145
6. 7 Réseau et volumes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
6. 7. 1 Les commandes docker network . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
6. 7.2 Les commandes docker volume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146

Chapitre 7 - Les instructions Dockerfile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147


7.1 Les modèles d'instruction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
7 .1 .1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
7. 1.2 Terminal ou exécution ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
"'Cl
0 7 .1 .3 Les commentaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
c
:::i
~
,.,
"O
0
\.0
[Link]; 7.2 Les instructions d'un Dockerfile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
.-t ~
0
N
V
V 7.2.l FROM. .. . . . .. . .. ...... .. . . . .. .. . . ... . . ....... .. . .. ... .. ... . . . .. . . . 150
'ii
@ ·c
....... [Link];
7.2.2 MAINTAINER..................................................... 152
..c CO
O'l
ï:::::
c
0 7.2.3 RUN.............................................................. 153
>- c
o. c
0 ·3ù 7.2.4 CMD.............................................................. 158
u :::;
"O
0
....
7.2.5 ENTRYPOINT... .. ..................... .... ........... ........ ... . 160
c.
~
~
7.2.6 EXPOSE........................................................... 163
:::;
rS 7.2.7 ADD...... .. . ............... ... ............. ..... ........ ........ . 167
1
"O
0
c 7.2.8 COPY............................................................. 171
8 7.2.9 VOLUME............... . ................................. . ........ 175
(Ç)
Jvm 1---------------------------- Docker

7.3 Bonnes pratiques. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179

Chapitre 8 - Usage avancé de Docker........... .... . ... .......... .. ......... . 183


8.1 Dockerfile: quelques instructions supplémentaires . . . . . . . . . . . . . . . . . . . . . . . . 183
8.1.l ENV............................................................... 183
8.1.2 LABEL............................................................ 186
8.1.3 WORKDIR.. .. . . . . .. .. . . . . .. .. . . .. . . . .. . . .. . . . .. . . . . .. . .. .. . .. ... . . 187
8.1.4 USER.............................................................. 189
8.1.5 ARG.................... .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . 192
8.1.6 ONBUILD......................................................... 198
8.1.7 STOPSIGNAL..................................................... 201
8.2 Sécurisons Docker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
8 .2 .1 SSL/TLS pour la Remo te API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
8. 2. 2 Docker Content Trust . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
8.3 Installer un registry privé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
8. 3 .1 Mot de passe et certificats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
8 .3 .2 Exécution de notre conteneur de configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
8 .3 .3 Lancement du registry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
8 .3 .4 Pousser une image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212

Quatrième partie - Exemples d'architectures et concepts avancés

Chapitre 9 - Application multi,conteneurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 7


"'Cl
0 9 .1 Un seul conteneur, plusieurs processus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
c
:::i
0 9 .1 .1 Installation des moteurs d'exécution. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
\.0
.-t
0
N
9 .1.2 Nginx.............................................................. 220
@ 9.1.3 PHP-FPM .......................................................... 221
.......
..c
O'l
'i:
9 .1.4 MariaDB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
>-
0.
0 9 .1 .5 Ports et volumes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
u
9 .1.6 Supervisor. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
9 .1.7 Notre code source ...... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
9 .1 .8 En conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
9.2 Application multi-conteneurs........................................... 230
9. 2. 1 N ginx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
Table des matières --------------------------[!]
9.2.2 PHP,FPM.......................................................... 232
9. 2 .3 Notre code source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2
9 .2 .4 Assemblons tout cela . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
9 .3 Le réseau Docker. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
9 .3 .1 Libnetwork et le modèle CNM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
9.3.2 L'interface dockerO et le réseau bridge................................... 236
9 .3 .3 Communication entre conteneurs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
9 .3 .4 Mise en œuvre sur notre application Symfony . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
9 .4 Orchestration avec Docker Compose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
9 .4 .1 Introduction et premiers pas avec Docker Compose.... ... . . . . . . . . . . . . . . . . . 245
9 .4. 2 Notre application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246

Chapitre 10 - Intégration continue avec Docker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249

10.1 Avant de commencer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249


10 .1 .1 Quelques mots sur l'intégration continue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
10 .1 . 2 Les conteneurs outils . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
10.1.3 NotreapplicationHelloWorld.. .. . . . . . . . . . .. . . . .. . . . . . .. . . . . . . . . . .. . . . . 253
10.2 La préparation des conteneurs. .. ..................... . . . . . . . . . . . . . . . . . . . 256
10.2. 1 Prérequis........................................................... 256
10.2.2 Le conteneur dépôt de code Gitlab...................................... 256
10.2.3 Le conteneur d'intégration continue]enkins .............................. 258
10.2 .4 Le conteneur d'API Docker distant Docker API.......................... 258
10. 2. 5 Les conteneurs d'environnement de développement . . . . . . . . . . . . . . . . . . . . . . . . 259
"'Cl
0
c ~
,., 10. 2. 6 Mise à jour du fichier /etc/hasts sur notre machine hôte. . . . . . . . . . . . . . . . . . . . . 260
:::i
"O
0 [Link];
\.0 10.3 Configuration de notre CI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
.-t ~
0 V
N V
'ii
10.3 .1 Initialiser GitLab pour l'application HelloWorld .. ........ . . . . . . . . . . . . . . . . . 262
@ ·c
....... [Link]; 10.3 .2 Testons l'application.................................................. 262
..c CO
O'l c
ï::::: 0
c 10.3 .3 Configuration de Jenkins ................. ... .... ... ................... 263
>-
o. c
u
0 ·3ù 10.3 .4 Création des jobs ]enkins et Web Hook..... ........ .. ....... ... .... ... .. 267
:::;
"O
0
....
c. 10.4 L'exploitation de notre C I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
~
~
:::; 10 .4 .1 Développement d'une nouvelle fonctionnalité. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
rS
"O
1 10.4.2 Mise en production.. . .... . .......... . .... .... ............ . . . ......... 277
0
c 10.4.3 Correction d'une anomalie............... .. ......... .. ..... . ..... ... .. 279
8
(Ç)
0------------------------------ Docker

Chapitre 11 - Docker Swarm. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281


11.1 Docker Swarm ............. .... .. .... ............. ... ............. .... . 282
11 . 1. 1 Le service de découverte . . .......... . .... .. ........................... . 283
11 .1 .2 Maître et nœuds Swarm ............................................. . 283
11.2 Mise en œuvre d'un cluster Swarm ...................................... . 284
11 .2 .1 Service de regi,stre : Consul ........................................... . 285
11 .2. 2 Maître et nœuds Swarm ............................................. . 287
11.3 Déployer une application sur un cluster Swarm ....................... ... . 292
11 .3 . 1 Prise en main rapide .. ... ... .......... . ......... ... ... .. ... ... ....... . 292
11 .3 .2 Le réseau overlay ................................................... . 295

Conclusion : un potentiel en devenir .... ..... ............. ... ............... .


.
Les domames d' app l'icat1ons
. .
existants ......................................... .

De nouvelles applications pour les conteneurs ......... .... .............. .. ..... .


Les défauts de jeunesse de Docker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302

Index...................................... ... .......... . .......... . ........ 303

"'Cl
0
c
:::i
0
\.0
.-t
0
N
@
.......
..c
O'l
'i:
>-
0.
0
u
Avant-propos

Pendant longtemps, déployer du code en production revenait à tenter de transporter


de l'eau entre ses mains: c'était fonctionnel, mais pas vraiment optimal. C omme
l'eau filant entre les doigts, il manquait presque nécessairement une partie des
données de configuration lors du déploiement, ceci en dépit d'efforts méthodologiques,
documentaires et humains conséquents.

L'apport de la virtualisation
La virtualisation a tenté de répondre à cette problématique (parmi d'autres) sans
apporter une réponse complètement satisfaisante. En effet, bien qu'offrant une
isolation vis-à-vis de l'arc hitecture matérielle, qui se standardise de plus en plus, la
machine virtuelle reste ... une machine. Elle exécute un système d'explo itation dont
les paramètres peuvent différer d 'un environnement à l'autre.
Des outils comme Chef ou Puppet résolvent une partie du problème, mais
n'offrent encore une fois qu'une couche d'abstraction partielle. Enfin, le déploiement
d'application sur la base d'une image de VM (pour Virtual Machine) est lourd (plusieurs
l:J gigaoctets, y compris pour les OS les plus compacts).
0
c
::J
~
,.,
"O
0 c::;
\.0 Les architectures à base de conteneurs
.-t
0
.,.,
~

N
'~ Avec Docker, n ous sommes entrés dans l'ère des architectures à base de « conteneur» .
@ ·c
....... B::;
On parle aussi de « v irtualisation de niveau système d'exploitation » par opposi-
..c: CO
Ol
0
c tion aux technologies à base d'hyperviseurs (comme VMWare ou VirtualBox) qui
ï:::: c
>-
o.. c cherchent à émuler un environnement matériel.
u
0 ·3
<.)
::;
"O
C ontrairement à une VM, un conteneur n'embarque pas un système d'explo itation
0
.....
c. complet. Il repose pour l'essentiel sur les fonctionnalités offertes par l'OS sur lequel
~
~ il s'exécute. L'incon vénient de cette approche est qu'elle limite la portabilité du
::;
rS conteneur à des OS de la même famille (Linux dans le cas de Docker). Cette approche,
1
"O
0
en revanch e, a l'avantage d'être beaucoup plus légère (les conteneurs sont nettement
c
8 plus petits que les VM et plus rapides au démarrage ) tout en offrant une isolation
(Ç) satisfaisante en termes de réseau, de mémoire ou de système de fichiers.
Étonnamment, le concept de conteneur et son implémentation ne sont pas
nouveaux. La version de OpenVZ pour Linux date, par exemple, de 2005, de même
que Solaris Zone ou FreeBSD jail. Docker a changé la donne en simplifiant l'accès à
cette technologie par l'introduction d'innovations, comme la mise à disposition d'un
langage de domaine (DSL ou Domain Specific Language) permettant, au travers des
fameux « Dockerfile »,de décrire très simplement la configuration et la construction
d'un conteneur.

Le propos de cet ouvrage


L'objet de cet ouvrage est d'offrir une approche à 360 degrés de l'écosystème Docker.
Docker, plus qu'une technologie, est en effet aujourd'hui un écosystème de
solutions fourmillantes : Kitematic, Compose, Machine, Swarm.
Autour du runtime (moteur d'exécution) qui exécute les conteneurs (le Docker
Engine), des outils complémentaires visent à conditionner, assembler, orchestrer
et distribuer des applications à base de conteneurs. Timidement, des initiatives de
standardisation voient le jour, la issant espérer une meilleure interopérabilité de celle
qui prévaut aujourd'hui dans le domaine de la virtualisation.
Notre objectif dans cet ouvrage est donc multiple :
• aborder le concept de conteneur et d'architecture à base de conteneurs en
décryptant les avantages proposés par cette approche ;
• apprendre à installer Docker sur un poste de travail ou dans un environnement
serveur;
• apprendre à utiliser Docker pour créer des images et manipuler des conteneurs ;
• étudier des architectures plus complexes au travers d'exemples complets :
architectures multi-conteneurs, développement, intégration continue et implé-
mentation d'un cluster multi-hôtes.

La structure du livre
l:J
0 Dans une première partie, nous expliquerons ce qu'est un conteneur, sur quels principes
c
:J et quelles technologies il repose. Nous verrons aussi comment Docker se positionne
0
\.0 parmi un nombre croissant d'acteurs et de logiciels importants.
.-t
0
N Nous aborderons ensuite le concept de « CaaS »,pour« Container as a Service »,au
@ travers de divers exemples. À cette occasion, nous utiliserons des outils tels que Swarm,
.......
..c: Kubernetes, Mesos. Nous nous intéresseron s aux liens entre les approches conteneurs
O'l
·;::
>- et celles d'outils de gestion de configuration comme Puppet, Chef ou Ansible.
0..
0
u La seconde partie de cet ouvrage se focalise sur la prise en main de Docker en
étudiant son installation sur un poste de travail ou dans un environnement serveur
virtualisé ou physique. Nous commencerons alors à « jouer» avec des conteneurs pour
comprendre par la pratique les concepts abordés dans la première partie.
La troisième partie du livre est consacrée à l'apprentissage de Docker. Nous y
aborderons les commandes du client et les instructions du Dockerfile. Cette troisième
partie peut être lue séquentiellement, mais aussi servir de référence.
Avant-propos ------------------------------!XII '
La dernière partie du livre se compose de trois chapitres qui mettent en œuvres des
cas d'usages permettant d'aborder des concepts plus avancés comme:
• les architectures multi~processus et multi~conteneurs ;
• la réalisation d'une chaîne d'intégration continue s'appuyant sur l'usage de
conteneurs ;
• la mise en œuvre d'un cluster multi~hôtes en s'appuyant sur Docker Swarm.

À qui s'adresse ce livre


Cet ouvrage s'adresse à un public mixte « DevOps » :

• si vous êtes engagé dans une organisation de développement (en tant que
développeur, architecte ou manager), vous trouverez les informations nécessaires
pour maîtriser rapidement la conception d'images Docker, mais aussi pour la
réalisation d'architectures multi~conteneurs;
• si votre domaine est plutôt celui de l'explo itation, vous acquerrez les compé~
tences nécessaires au déploiement de Docker sous Linux.

L'o bjectif de ce livre est double:


• il permet d'accélérer la prise en main de cette technologie en présentant des cas
d'usages illustrés par des exemples didactiques ;
• il offre aussi une référence illustrée d'exemples du langage DSL et des corn~
mandes de Docker.

Compléments en ligne
Le code source et les exemples de ce livre sont distribués via GitHub sur le repository
public:
[Link]
Un erratum, des articles et des exemples complémentaires sont aussi distribués via le
"'Cl
0 site [Link]
c
:::i
~
,.,
"O
0 [Link];
\.0
.-t ~
0
N
V
V Remerciements
'ii
@ ·c
....... [Link]; L'écriture d'un livre est une activité consommatrice de temps qu'il n'est pas possible
..c CO
O'l c
0 de mener à son terme sans l'assistance de nombreuses personnes.
ï::::: c
>-
o. c
0 ·3ù Nous voudrions donc adresser nos remerciements à :
u :::;
"O
0
.... • Patrick Moiroux, pour son expertise de Linux en général, des architectures web
c.
~ distribuées et de Docker en particulier ;
~
:::;
rS • Bernard Wittwer, pour avoir attiré notre attention, il y a plus de trois ans, sur
"O
1
un petit projet OpenSource sympathique nommé Docker dont il percevait déjà
0
c le potentiel ;
8
(Ç) • Marc Schar, notre stagiaire de compétition, devenu expert de Kubernetes ;
• tous les contributeurs au projet open source BizDock ([Link]
[Link]/) qui a été notre premier contact avec le monde des conteneurs
et Docker;
• nos épouses et nos enfants pour leur patience en regard du temps que nous avons
passé isolés du monde extérieur à expérimenter des logiciels et à en décrire le
fonctionnement.

"'Cl
0
c
:::i
0
\.0
.-t
0
N
@
.......
..c
O'l
'i:
>-
0.
0
u
...
PREMIERE PARTIE

Les conteneurs ••
principes, obiectifs et
solutions

C ette premiè re partie vise à présenter :


• les origines du concept de conten eur ;
• l'apport de Docker à cette techno logie déjà ancienne ;
l:J
0
c ~
• comment les conten eurs autorisent la réalisation de nouvelles architectures
::J ,.,
0 "O informatiques ;
c::;
\.0
.-t .,.,
~ • comment les conten eurs colonisent les solution s de gestion d'infrastructure.
0
N
'~
@ ·c C ette première partie comprend deux ch apitres. Le premier décrit ce qu'est un
....... B::;
..c:
Ol
CO
c
conten eur d'un po int de vue technique et conceptuel. Le second chapitre présente un
ï:::: 0
>- c survol complet des solutions de gestion d'infrastructure à base de conteneurs : des plus
o.. c
0 ·3 modernes (que l'on n omme égalemen t C aaS 1 ) aux plus classiques pour lesquelles les
u <.)
::;
"O
0
con teneurs apportent les avantages décrits dans le ch apitre 1.
.....
c.
~
~
::;
rS
1
"O
0
c
8 1. CaaS est l'acron yme en anglais de C ontainer as a Service, so it en français C onteneur comme un
(Ç) service.
"'O
0
c:
:::i
0
\.0
r-1
0
N
@
......,
..c:
en
·;::
>-
0..
0
u
1
Les conteneurs et le cas
Docker

Les éléments de base de l'écosystème


L'objectif de ce chapitre est de décrire les con cepts qui ont présidé à l'émergen ce
de la notion de conteneur logicie l. N ous présenterons les briques de base sur
lesquelles les conte n eurs (e t plus spécifiquem ent les conten eu rs Docker) re posent.
Puis nous expliquerons comment sont con struits et distribués les conten eurs Docker.
Enfin, n ous nous intéresseron s aux différents éléments des architectures à base de
conteneurs : Docker et les autres.
À l'issue de ce ch apitre vous comprendrez ce qu'est un conteneur, ce qu'est Docker
et quels sont les concepts architecturaux et logiciels qu'il implémente. Vous saurez
aussi quels sont les acteurs de cet écosystème.
l:J
0
c
::J
~
,.,
"O
0 c::;
\.0 Attention : dans ce chapitre, comme dans la suite de cet ouvrage, nous allons aborder
.-t
0
.,.,
~
la question de la conception des architectures à base de conteneurs. Néanmoins, nous
N
'~
@ ·c le ferons par le prisme de Docker qui en est l'implémentation la plus populaire. De ce
B
.......
..c:
::;
CO
fait, nous nous focaliserons sur les OS qui sont officiellement supportés par Docker
Ol c (soit Linux, Windows et dans une moindre mesure Mac OS X>. Nous tenons à indiquer
ï:::: 0
>- c
o.. c que des implémentations de conteneurs existent aussi pour d'autres systèmes, comme
u
0 ·3
<.) FreeBSD ou Solaris. Néanmoins, nous ne les aborderons pas dans le cadre de ce livre.
::;
"O
0
.....
c.
~
~
::;
rS 1.1 LA CONTENEURISATION
1
"O
0
c
8 Les conteneurs logiciels ch erch ent à répon dre à la même problématique que les
(Ç) conteneurs ph ysiques aussi appelés conteneurs intermodaux, ces grandes boîtes de
8------------------- Chapitre 1. Les conteneurs et le cas Docker

métal standardisées qui transportent de nos jours l'essentiel des biens matériels par
camion, train, avion ou bateau.
Nous allons donc faire un peu d'histoire.

1.1.1 L'histoire des conteneurs intermodaux

Avant l'apparition de ces conteneurs standardisés, les biens étaient manipulés manuel,
lement. Les A nglo,Saxons utilisent le terme de break bulk cargo, ce que nous pourrions
traduire par « chargement en petits lots » . Plus simplement, les biens étaient chargés
individuellement par des armées de travailleurs.
Les biens étaient, par exemple, produits dans une usine, chargés un par un dans
un premier moyen de transport jusqu'à un han gar (généralement près d'un port ou
d'une gare ) où avait lieu un déchargement manuel. Un second ch argement survenait
alors depuis ce premier lieu de stockage jusque dans le moyen de transport lon gue
distance (par exemple un bateau). C e second ch argement était lui aussi manuel. En
fonction des destinations, des contraintes géographiques et légales, cette séquence de
chargement et déchargement pouvait avoir lieu plusieurs fo is. Le transport de biens
était donc coûteux, lent et peu fiable (biens abîmés ou perdus).
Les premières tentatives de standardisation du transport de biens sont intervenues
en A n gleterre à la fin du XVIIe siècle, essentiellement pour le transport du charbon.
L'un des exemples bien connus est celui de la ligne de ch emin de fer Liverpool -
Manchester qui utilisait des boîtes en bo is de taille standardisée qui étaient ensuite
d éch argées p ar grues sur d es ch arre ttes tirées p ar des chevaux .
Dans les années trente, la C hambre inte rnationale de commerce a mené des
tests afin de standardiser les conteneurs en vue de faire baisser les coûts de transport
dans le contexte de la grande dépression de 1929. En 1933, le Bureau international
des conten eurs ou BIC est établi à Paris (et il s'y trouve toujours) pour gérer la
standardisation de ces grosses boîtes métalliques dont le succès n 'a fait que croître
l:J
depuis.
0
c
::J
0
\.0
.-t
0
N
@
.......
1111111 1111 . ~ j i~
..c: ' .
O'l
·;:: . '·; I
~ ~
>-
0..
0
u

Figure 1. 1 - Conteneurs intermodaux

Aujourd'hui, on estime qu'il y a plus de 20 millions de conteneurs en circulation


dans le monde.
1. 1 La conten eurisation --------------------------[!]
1.1 .2 Les avantages d'un transport par conteneur

Les avantages du transport par conteneur intermodal sont liés à ce que les Anglo-
Saxons n omment separation of concems (en français ségrégation des problèmes ou
ségrégatio n des responsabilités).
Les transporteurs délèguent à leurs clients le remp lissage du conteneur qui est
ensuite scellé avant le transport. De ce fait, le transporteur n'a pas à s'occuper de
la na ture précise des biens tran sportés. Il do it s'assurer que le conten eur d ans son
ensemble arrive intact. Il assure donc la traçabilité d'un obj et dont les caractéristiques
physiques sont standardisées. Il peut les empiler, cho isir le mode de transport adapté à
la destinatio n, optimiser les coûts et la logistique. Camions, bateaux, trains et grues
vont pouvoir traiter ces biens, les arrimer correctement, qu'ils transportent des armes
ou des couches-culottes.
La personne ou l'entreprise cliente a de son côté la garantie, pour peu que le
contene ur ne soit pas perdu ou ouvert, que ses biens arriveront dans le même état
et arran gement que lors du chargement. Le client n'a donc pas à se soucier de
l'infrastructure de transport.
C ette séparation des responsabilités est à l'origine de la baisse drastique des coûts
du transport de marchandises. Grâce à la standardisation et à l'automatisation qu'elle
rend possible, les infrastructures de transport se sont mécanisées, automatisées et donc
fiabilisées.

1.1.3 Extrapolation au monde logiciel

C omme nous l'avons évoqué e n introduction , le mon de informatique reste profon-


déme nt organisé autour de l'aspect artisanal de la livraison du produit logiciel. Qu'il
s'agisse d'un éditeur livrant un logiciel à un client ou de la mise en explo itation d'un
développement, de très nombreux incidents surven ant au cours du cycle de vie d'un
logiciel sont liés à cette problématique.
l:J
0
C'est justement ce que la technologie des con teneurs logiciels cherche à résoudre.
c
::J
~
,.,
"O
0 c::;
\.0
:"/
.-t .,.,
~
0
N
'~ ~of,'~
'~ exploitant
@ ·c
.......
..c:
B::;
CO
infrastructure
Ol c
ï:::: 0
>- c

u
o..
0
c
·3
<.)
::;
"O
0
.....
c.
• conteneur 1 conteneur l_c_
on_t_e_n_e_u_r_.
~
~
::;
rS
1
"O
0
développeur
c
8 Figure 1.2 - Séparation des responsabilités dans une architecture à conteneurs
(Ç)
ŒJ------------------- Chapitre 1. Les conteneurs et le cas Docker

Dans une architecture à base de conteneurs :


• le contenu du conteneur, c'est-à-dire le code et ses dépendances (jusqu'au niveau
de l'OS), est de la responsabilité du développeur ;
• la gestio n du conteneur et les dépendances que celui-ci va entretenir avec
l'infrastructure (soit le stockage, le réseau et la puissance de calcul) sont de la
responsabilité de l'exploitant.

1.1.4 Les différences avec la virtualisation matérielle

Étudion s l'empilement des couches dans le cas du déplo iement de trois logiciels sur
un mê me hôte (host) sans machine v irtuelle ou conteneur.

BBB os

Infrastructure

Figure 1.3 - Installation native de trois logiciels sur un même hôte

Dans ce type d'installation , on imagine que plusieurs situations problématiques


peuvent survenir :

l:J
• les différents logiciels peuvent interagir entre eux s'ils n 'ont pas été conçus
0
c par le même éditeur. Ils pourraient, par exemple, nécessiter des packages
::J
0 (bibliothèques, extensions) ou des versions de système d'exploitation différen tes.
\.0
.-t Ils peuvent aussi ouvrir des ports réseaux identiques, accéder aux mêmes chemins
0
N sur le système de fichiers ou encore entrer en concurrence pour les ressources
@
.......
1/0 ouCPU ;
..c:
Ol
·;::
• toute mise à jour de l'O S hôte va nécessairement impacter tous les logiciels qui
>-
0..
tournent dessus ;
0
u • chaque mise à jour d'un logiciel pourrait entraîner des impacts sur les autres.

L'expérience montre que l'exécution , sur le même système, de logiciels fournis


par des éditeurs différents qui n 'auraient pas testé cette cohabitation est très souvent
problématique.
La virtualisation matérielle de type VMWare, VirtualBox ou HyperV n 'assure-t-elle
pas déjà cette séparation des responsabilités ?
1. 1 La conten eurisation
-------0
:::::=S=o=ft=.A==ll:::==S=o=ft=.A==l l==S=o=ft=.A==
os os os

Hypervisor (ex: VMWare)

1OS hôte

Infrastructure

Figure 1.4 - Virtualisation matérielle : trois VM sur le même hôte

La réponse est « oui, mais ... ».

Dans les faits, comme nous le voyons sur la figure précédente, cette virtualisation
matérielle offre un niveau d'isolation élevé. Chaque logiciel se trouve dans son bac à
sable (sandbox en anglais). Les problèmes évoqués précédemment sont donc résolus,
mais d'autres apparaissent :
• le poids d'une machine virtuelle est tout d'abord très important. Une machine
virtuelle est une machine et , même avec un système d'exploitation minimal,
un OS moderne consommera difficilement moins de quelques Go de mémoire.
La distribution de ce type de package demandera une bande passante réseau
conséquente;
• la machine virtuelle embarque trop d'éléments. Elle ne laisse pas le choix à
l:J
0 l'exploitant (selon la manière dont elle aura été configurée) de choisir librement
c ~
,.,
::J
"O
ses caractéristiques, comme le type de stockage, le nombre de CPU utilisés, la
0 c::;
\.0 configuration réseau. Évidemment, les solutions de gestion d'environnements
.-t
0
.,.,
~
virtualisés (par exemple, vCenter de VMWare) offrent des solutions, mais celles~
N
'~
@ ·c ci ont presque toujours des impacts sur le logiciel. Ce dernier ne peut pas être
....... B
..c:
::;
CO conçu sans savoir comment il va être exécuté .
Ol c
ï:::: 0
>- c
o.. c Une architecture à base de conteneurs offre une solution de compromis. Le
u
0 ·3
<.)
::; conteneur offre l'isolation permettant à un développeur d'embarquer l'ensemble des
"O
0
.....
c. dépendances logicielles dont il a besoin (y compris les dépendances de niveau OS).
~
~
De plus, un conteneur s'appuie sur le noyau (kemel) du système d'explo itation hôte 1.
::;
rS
1
"O
0 l. Sur la figure 1.5, le lecteur attentif aura noté les termes « cgroups » et « namespaces ». Nous les
c
8 définirons dans le paragraphe suivant. À ce stade, nous dirons qu'il s'agit d'extensions du noyau
(Ç) Linux qui rendent possible la réalisation de conte neurs « isolés » les uns des autres.
ŒJ------------------- Chapitre 1. Les conteneurs et le cas Docker

Conteneur A Conteneur B Conteneur C

Soft. A Soft. B Soft.C

Infrastructure

Figure 1.5 - Architecture à conteneurs

Il est donc très léger et démarre presque aussi vite que le processus qu'il encapsule. Le
nombre de conteneurs qu'un même hôte peut exécuter est donc nettement plus élevé
que son équivalent en machines v irtuelles.

Des conteneurs dans une VM


Qu'en est-il du risque d'impact sur le logiciel en cas de mise à jour du système
d'exploitation hôte? Effectivement, dans le cas d'une architecture à conteneurs, si
le noyau de l'OS est mis à jour, il peut affecter les conteneurs qu'il exécute. Rien
n'empêche donc de revenir dans ce type de cas à l'option VM qui va augmenter
l'isolation, tout en conservant la possibilité d'exécuter plusieurs conteneurs dans
la même VM. C'est d'ailleurs ce type d'option que Microsoft met en avant avec
HyperV-Containers, tout en offrant aussi la possibilité de faire tourner des conteneurs
nativement sur l'OS hôte.

l:J
0 Il existe par ailleurs des projets, comme Fedora Atomic ou CoreOS, visant à offrir
c
::J des OS hôtes minimaux dédiés à l'exécution de conteneurs et se focalisant uniquement
0
\.0 sur les problématiques d'infrastructure. L'usage de ces OS hôtes spécialisés va limiter
.-t
0 leur exposition aux attaques et aux bugs pouvant nécessiter des mises à jour.
N
@ Nous verrons aussi plus tard que Docker apporte deux autres avantages aux
.......
..c: solutions à base de conteneurs : la possibilité de décrire formellement comment
Ol
·;::
>- construire le conteneur et un format d'image standardisé. Cette capacité fondamen tale
0..
0 est probablement la clef du succès de Docker.
u
Maintenant que nous sommes convaincus des avantages des architectures à base
de conten eurs, nous allons en étudier les fondements techniques.
1.2 Les fondations: Linux, CGroups et N amespaces -----------------[!]
1.2 LES FONDATIONS: LINUX, CGROUPS
ET NAMESPACES
Docker est une solution open source de conteneurs Linux qui s'appuie elle-même sur
d'autres composants eux aussi ouverts. Ces briques de base sont en fait communes à
tous les types de conteneurs Linux.
Initialement, Docker utilisait notamment LXC (Linux Containers) comme implé-
mentation (on parle de driver), mais a depuis développé sa propre bibliothèque de
bas niveau nommée libcontainer 1 • Ce driver encapsule les fonctionnalités fondamen-
tales, proches du noyau du système d'exploitation, dont la combinaison permet la
virtualisation.
Nous allons étudier ces différents composants de base pour:
• en comprendre le rôle fonctionnel ;
• comprendre les différentes étapes qui ont abouti au concept de conteneur.

1.2.1 Docker = Linux


Il est en premier lieu essentiel de rappeler que Docker est une technologie liée à Linux,
son noyau (Linux Kem el) et certains de ses services orchestrés par la libcontainer de
Docker.
Co mment Docker marche-t-il sous Windows ou Mac OS X ?
Eh bien il ne marche pas sous ces OS, du moins pas nativement pour le moment.
Pour faire tourner un Docker Engine sous Windows, il était, encore jusqu'à
récemment, nécessaire d'y installer un OS Linux. La solution usuellement pratiquée
consiste à s'appuyer sur un logiciel de virtualisation matérielle : Virtua1Box 2 dans le
cas de Docker.

"'Cl
V irtualBox est un hyperviseur open source (disponible en licence GPU aujourd'hui
0
c ~
géré par O racle. Il est donc très fréquemment utilisé par des solutions open source
:::i ,.,
0 "O souhaitant disposer de fonctionnalités de virtualisation sans contraintes de licences.
[Link];
\.0
.-t ~
0
N
V
V Comme nous le verrons dans le chapitre suivant, l'installation de la Docker
'ii
@ ·c Toolbox (le kit de démarrage de Docker en environnement PC) sous Windows ou
....... [Link];
..c CO Mac OS X inclut VirtualBox et une image Linux minimale qui fournit les services
O'l c
ï::::: 0
c nécessaires à l'exécution du Docker Engine. L'installation n'est donc pas native et la
>-
o. c
0 ·3ù complexité de gestion des terminaux, comme les performances d'accès au système de
u :::;
fichiers, limite très fortement l'intérêt de Docker sous ces OS Desktop.
"O
0
....
c.
~
~
:::;
rS 1. Notons que ce driver d 'exécut ion est ce qui fait le pont entre le moteur d'exécution des
1
"O
0 conteneurs et le système d 'exploitation. Dans le cas de l'implémentation native sous W indows,
c
8 c'est ce composant que les équipes de Microsoft ont dû réécrire pour l'adapter à Windows.
(Ç) 2. h ttps://www.v [Link]/
El------------------- Chapitre 1. Les conteneurs et le cos Docker

Docker natif pour Windows Server 2016


À l'heure où nous écrivons ces lignes, Microsoft et Docker ont annoncé que la version
201 6 de Windows Serveur inclurait la possibilité d'exécuter des conteneurs nativement.
Les équipes de Microsoft, avec le support des ingénieurs de Docker, ont pour ce
faire implémenté une sorte de libcontainer s'appuyant sur les capacités natives de
Windows en lieu et place de Linux. Microsoft proposera aussi des images de base pour
Windows (évidemment non disponibles en téléchargement libre). Il est donc possible
que dans un futur indéterminé la Docker Toolbox pour Windows s'appuie sur cette
implémentation native en lieu et place d'une machine virtuelle VirtualBox contenant
un système Linux.

Pour comprendre comment fonctionnent les conteneurs, il est utile de décrire


les services Linux de base sur lesquels s'appuie la libcontainer de Docker. Docker,
tout comme d'autres implémentations de conteneurs, est basé sur deux extensions du
kernel Linux :
• Cgroups;
• N amespaces.

1.2.2 CGroups

CGroups 1 (pour Control Groups) permet de partitionner les ressources d'un hôte
(processeur, mémoire, accès au réseau ou à d'autres terminaux). L'objectif est de
contrôler la consommation de ces ressources par processus.
Prenons par exemple une machine sur laquelle serait installée une application
web avec un front,end PHP et une base de données MySQL. CGroups permettrait
de répartir la puissance de calcul (CPU) et la mémoire disponible entre les différents
processus, afin de garantir une bonne répartition de la ch arge (et donc probablement
des temps de réponse).

l:J
0 RAM CP Us
c
:i
0
\.0
.-t
0
N
@
.......
..c
en
ï:::::
>-
0.
0
u web-front-end group database group
PI D CMD PID CMD
7459 httpd . worker 11751 mysqld-safe
7462 httpd .worker 11958 mysqld

Figure 1.6 - Répartition de ressources grâce à CGroups

1. htrps://[Link] [Link]/doc/Documenration/cgroups/cgroups. txt


1.2 Les fondations: Linux, CGroups et Namespaces -----------------[!!]
CGroups introduit une notio n de contrô leur qui, comme son nom l'indique, a
pour objectif de contrôler l'accès à une ressource pour une hiérarchie de processus. En
effet, par défaut, les processus fils d'un processus associé à un group donné héritent des
paramètres de leur parent.

1.2.3 Namespaces

Les Namespaces sont indépendants de CGroups, mais fon ctionnent de concert. Ils
permettent de faire en sorte que des processus ne voient pas les ressources utilisées par
d'autres. Si C G roups gère la distribution des ressources, N amespaces apporte l'isolation
nécessaire à la créatio n de conteneurs.
L'ancêtre du mécanisme des N amespaces est la commande chroot qui existe au
sein du système U N IX depuis 1979 !
La fonction de cette commande est de ch anger pour un processus donné le
répertoire racine du système. Le processus en question a l'impression d'être à la racine
du système. L'objectif étant, par exemple, pour des raisons de sécurité, d 'empêch er
l'utilisateur de se promener dans des sections du système de fichiers dont il n'aurait a
priori pas l'usage. Il s'agit donc conceptuellement d'une sorte de v irtualisation.
N amespaces étend ce concept à d 'autres ressources.

Tableau 1.1 - Namespaces Linux

Namespace Isole
IPC Communication interprocessus
Network Terminaux réseau, ports, etc.
Mount Point de montage <système de fichiers)
PID Identifiant de processus
User Utilisateurs et groupes
l:J
UTS Nom de domaines
0
c
::J
~
.
.,
"O
0 c::;
\.0
.-t
0
.,.,
~

N
·~
@ ·c
B
1.2.4 Qu'est-ce qu'un conteneur finalement ?
....... ::;
..c: CO
Ol c
ï:::: 0
c Un conteneur est tout simplement un système de fi chiers sur lequel s'exécutent des
>- c
o.. processus (de préférence un par conteneur) de manière :
u
0 ·3
<.)
::;
"O
0
..... • contrainte : grâce à CGroups qui spécifie les limites en termes de ressources ;
c.
~
~
• isolée : grâce notamment à Namespaces qui fait en sorte que les conteneurs ne
::;
rS se voien t pas les uns les autres.
1
"O
0
c
8
(Ç)
8------------------- Chapitre 1. Les conteneurs et le cos Docker

1.3 LES APPORTS DE DOCKER : STRUCTURE EN


COUCHES, IMAGES, VOLUMES ET REGISTRY

C omme nous l'avons précédemment expliqué, les conteneurs existent depuis long-
temps, mais Docker a apporté des n ouveautés décisives qui ont clairement favorisé
leur popularisation .
L'une d 'entre elle a trait à la manière don t Docker optimise la taille des conteneurs
en permettant une mutualisation des données. C 'est ce que nous allons expliquer dans
cette section.
N ous allons aussi aborder la question de la persistance des données dans un
conteneur, en expliquant la notion de volume.
Notez que nous expérimenterons ces concepts ultérieurement, à l'aide des outils
Docker.

Attention, l'apport du projet Docker à la technologie des conteneurs ne se limite pas


aux concepts décrits dans ce paragraphe. Nous verrons par la suite, dans la seconde
partie de cet ouvrage, que Docker a aussi changé la donne grâce à ses outils et en
particulier grâce aux fameux Dockerfile.

1.3.1 La notion d'image

La n otion d'image dans le monde conteneur est pratiquement synon yme de Docker.
Comme n ous l'avons déjà vu, un conteneur est un ensemble de fichiers sur lequel
s'exécutent un ou plusieurs processus. O n peut alors se poser la question suivante :
mais d'où v iennent ces fichiers ?
Construire un conte neur pourrait se faire à la main, en reconstruisant dans une
partie du système de fichiers Linux une arborescen ce de fichiers : par exemple, un
réperto ire pourrait stocker les fichiers spécifiques au conteneur qui ne font pas partie
l:J
0
c du n oyau de l'OS. Mais cette p ratique serait fastidieuse et poserait le problème de la
::J
0 distribution e t de la réutilisation.
\.0
.-t
0 L'un des apports essentiels de Docker est d'avoir proposé une manière de condi-
N
tionner le contenu d'un con teneur en blocs réutilisables et échangeables : les images.
@
.......
..c: Ces images sont don c des archives qui peuvent être échangées entre plusieurs hôtes,
O'l
ï:::: mais aussi être réutilisées. C ette réutilisation est rendue possible par une seconde
>-
0..
0 innovation: l'organisation en couches.
u

1.3.2 Organisation en couches : union file system

Les contene urs Docker sont en fait des millefeuilles constitués de l'empilement
ordonné d'images. Chaque couche surcharge la précédente en y apportant éventuelle-
ment des ajouts e t des modifications.
1.3 Les apports de Docker: structure en couches, images, volumes et registry ---------a
En s'appuyant sur un type de système de fichiers Linux un peu particulier nommé
Union File System 1 , ces différentes couches s'agrègent en un tout cohérent : le
conteneur ou une image elle-même réutilisable.

L'application elle-même
Conteneur éventuellement associée à des
fichiers de ressources (images,
configuration, etc.)
Application
Des bibliothèques logicielles dont
i...J..--- - - - dépend l'application (Jar pour java,
Bibliothèques logicielles gems pour Ruby, etc.)

Packages OS additionnels Des packages ou applications


additionnelles requises par
l'application (par exemple: apache,
mysql, etc.)

li
L'image de base du conteneur
généralement fournie par Docker.
OS hôte Par exemple: CentOS 7.
Elle contient les packages
fondamentaux spécifiques de /'OS
du conteneur.

j Infrastructure

Hôte

Figure 1.7 - Structure d'un conteneur au sein d'un hôte

Admettons que nous construisions une application s'appuyant sur deux conteneurs
tournant sur le même hôte :
• un front-end basé sur une application JSP, tournant dans un serveur d'applica-
tions Tomcat2, exécuté par une machine virtuelle Java 1.8 sur un OS CentOS 7 ;
"'Cl
0
c ~
• un back-end constitué d'une base de données Cassandra3 s'exécutant elle aussi
:::i ,.,
0 "O sur Java 1.8 et CentOS 7.
[Link];
\.0
.-t ~
0
N
V
V Lorsque nous allons installer le front-end (nous verrons comment par la suite), le
'ii
@ ·c système va charger plusieurs couches successives qui sont autant de blocs réutilisables.
....... B
..c
:::;
CO Lors de l'installation du conteneur de base de données, le système n'aura pas à charger
O'l c
ï::::: 0
c l'image CentOS ou la machine virtuelle Java, mais uniquement les couches qui sont
>-
o. c
0 ·3ù spécifiques et encore absentes du cache de l'hôte.
u :::;
"O
0
....
c.
~
~
:::;
rS l. Nous verrons dans la suite de ce ch apitre qu'il existe plusieurs implémentations de ce type de
1
"O
0 système de fichiers.
c
8 2. [Link] [Link]/
(Ç) 3. [Link]
8------------------- Chapitre 1. Les conteneurs et le cos Docker

Conteneur « front-end » Conteneur « base de données »

Application Java (.war) Fichiers de configuration

Tomcat 7.0.68 Cassandra 3.3

OpenJDK 1.8

1 Infrastructure 1

Hôte

Figure 1.8 - Exemple d'application à plusieurs conteneurs

Par la suite, les modifications de l'application front,end, si elles se cantonnent


à la modification de pages JSP, n e nécessiteront qu'un redéploiement de la couche
supérieure.
Le gain de temps, de bande passante réseau et d'espace disque (par rapport à une
machine v irtuelle complète par exemple ) est évident.

Attention la représentation donnée des couches d'images dans la figure 1.8 est très
simplifiée. En réalité, une image de base CentOS 7 est, par exemple, constituée
"'Cl
0
de quatre couches. Mais le principe exposé d'empilement et d'agrégation de ces
c couches par l'intermédiaire d'un union file system reste le même.
:::i
0
\.0
.-t
0
N
@ 1.3.3 Docker Hub et registry
.......
..c
O'l
ï:::::
Dans le paragraphe précédent, nous avons exposé les fondements de la structure d'un
>-
0. conteneur. Nous avons notamment évoqué la manière dont l'hôte pouvait charger des
0
u blocs d'images constituant les conteneurs.
Mais à partir d'où un hôte Docker va+il charger ces blocs?
C'est le rôle d'un autre composant essentiel de l'architecture Docker: le registry.
Le registry est l'annuaire et le centre de stockage des images réutilisables. Sa
principale instanciation est le Docker Hub public et accessible v ia l'URL [Link]
[Link]/.
1.3 Les apports de Docker : structure en couches, images, volumes et registry ----------a
..... Oashboard f xplorr Organ11at1ons Q rrr>atr • pycloux

pycloux M Repositories * Stars Ci!' Contnbuted Private Repositories Using 0 of 1 Get more

Repositories Create Reposrtory +

Docker Trusted
Registry
pycloux/test
public
0 0 > Need an on-premise
registry? Gel a 30-day
STARS PULLS ::TAL
free tnal

Figure 1.9 - Compte sur le Docker Hub

Il est possible, à tout à chacun, de se créer un compte gratuit sur ce registry


pour publier une image. Il faudra débourser quelques dollars pour pouvoir en stocker
d'autres.
C e registry est public et héberge les images de base des principaux systèmes
d'explo itation dérivés de Linux (Ubuntu, CentOS, etc.) et de nombreux logiciels
courants (bases de données, serveurs d'application, bus de messages, etc.). Celles~ci,
appelées images de base sont gérées par Docker lnc. et les organisations qui produisent
ces logiciels.

OFFICIAL REPOSITORY

centos {::[

Repo lnfo Tags

l:J
0
c
::J
~
,., Short Description Docker Pull Command

"O
0 c::; The official build or centos. docker pull centos
\.0
.-t
0
.,.,
~

N
'~ Full Description
@ ·c
....... B::;
..c: CO
Ol
ï:::: 0
c
c
Supported tags and respective
>- c
o..
u
0 ·3
<.)
Dockerfile links
::;
"O • latest centos7 , 7 (docker/Dockerfrle)
0
..... centos6 , 6 (docker/Dockerfile)
c. •
~ • centos5 , 5 (docker!Dockerfî/q)
~ • centos7. 2 .1511 7. 2 .1511 (docker/Dockerfîle)
::;
rS
1
"O
0
Figure 1. 1 0 - Image de base CentOS
c
8
(Ç)
8------------------- Chapitre 1. Les conteneurs et le cos Docker

Mais il faut comprendre que le Docke r Hub n'est qu'une instanciatio n publique
d'un registry. Il est tout à fait possible à une entreprise d'installer un registry privé 1
pour y gérer ses propres images.

Les autres offres de registry cloud : une féroce compétition


Si le Docker Hub reste la plus connue et la plus populaire des offres de registry cloud
(notamment dans le monde open source}, les grandes manœuvres ont commencé.
Tour à tour, Google2 et Amazon3 ont annoncé leurs propres implémentations de
registries privés, ce qui concurrence de fait celui du Docker Hub (source principale de
revenus pour Docker lnc. à l'heure actuelle}.

Comment fonctionne le registry en lien avec le Docker Engine ?

Cache local
Repository X

Image locale

Docker engine
Registry
Hôte

Figure 1.11 - Installation et publication d'images

Le registry va être au cho ix :


l:l
0
c • le lieu de stockage d'images créées sur un hôte (par exemple par un développeur).
0
:::i
Le registry sert alors de lieu de publication et d'annuaire. O n parle alors de push
\.0
.-t
(via la commande docke r push );
0
N • la source d 'images à installer sur un ou plusieurs h ôtes et n otamment, dans le
@ cas du Docker Hub, des images de base. O n parle alors de pull (via la commande
.......
..c docker pull ) .
O'l
'i:
>-
0.
0 C ertaines images peuvent aussi rester privées et ne pas être publiées via un registry.
u Dans ce cas, ces images restent au niveau du cache de l'hôte qui les a créées.

l. Docker propose d'ailleurs un logiciel nommé Docker Trusted Registry pour les clients qui souhaitent
mettre en place leur propre instance.
2. [Link] er-registry/
3. h ttps://[Link]/fr/ecr/
1.3 Les apports de Docker : structure en couches, images, volumes et registry ---------a
La réutilisation des images se produit donc de deux man ières:
• à l'éch elle d'un hôte, par l'intermédiaire du cach e local qui permet d'économiser
des téléch argements d'images déjà présentes ;
• à l'échelle du registry, en offran t un moyen de partage d'images à destination de
plusieurs h ôtes.

1.3.4 Copy on write, persistance et volumes


Nous savon s mainten ant qu'un con teneur est construit à partir d'une image au même
t itre qu'une machine v irtue lle physique.
À un certain moment, cette image va être mise en route. Le conten eur va
exécuter des processus qui alloueront de la mémo ire, con sommeront des ressources
et vont évidemment écrire des don nées sur le système de fichiers. La quest ion
est don c ma inten ant de comprendre comment ces données sont produites et sont
éventuellement sauvegardées entre deux exécution s d'un conten eur (et partagées
en tre plusieurs conten eurs).

Le container layer
Intuitivement, on comprend que ces données sont produites dans une couch e au~dessus
de toutes les autres, qui va être spécifique au conten eur en cours d'exécution. Cette
couch e se n omme la couche de conten eur (ou con tainer layer ).

Une couche de conteneur est allouée


à chaque instance de conteneur.
Elle est en lecture I écriture.

r----- -----,
I_ Couche
1 du conteneur A I1L
___________ 1 Couche du conteneur B- 1
__________ 1

l:J
0 Cl5aceaa7:e96a
c
::J
~
,.,
"O
0 c::; Les couches de l'image
\.0 atfüoa9 ~ 63c9t5 à partir de laquelle le
.-t
0
.,.,
~
conteneur est «créé».
N Ces couches ne sont
'~
@ ·c e55 ~~ 5l:lc2~f pas modifiables, elles
....... B
::;
..c: CO
sont en «lecture seule».
Ol c
0
ï:::: c a33f3c9e c
>- c
o..
u
0 ·3
<.) lmageXYZ
::;
"O
0
.....
c.
~
~
Figure 1. 1 2 - Couches d'images et couches de conteneurs
::;
rS
1
"O
0
C ette couch e de conten eur est modifiable contrairement aux couch es d 'images
c
8 qui n e le sont pas. Dans le cas contraire, faire tourner un conten eur reviendrait à
(Ç) altérer poten t iellement l'image sur laquelle il est construit, ce qui n'aurait aucun sen s,
8 -------------------- Chapitre 1. Les conteneurs et le cos Docker

puisque le but d'une image est justement de pouvoir créer autant de conteneurs que
l'on souhaite, à partir du même moule.
Soit, mais imaginons que nous construisions un conteneur à partir d'une image de
base CentOS. Imaginons encore que nous souhaitions modifier la configuration de
ce système de base, par exemple /etc/bashrc, qui configure l'env ironnement du shell
UNIX bash . Si l'image de base n'est pas modifiable, comment allons,nous pouvoir
procéder ?

Le concept de copy on write


C 'est là qu'entre en jeu un concept très puissant, nommé copy on write (souven t abrégé
par COW) ou copie sur écriture.

11 1
Couche du conteneur A 11
Couche du conteneur B 1
1: ~ 1 La version «modifiée• du
:1 /etc/bashrc ~ fichier« /etc/bashrc» qui
: devient la version courante
______________1 1
- _ _ _ _ _ _ _ _ _ _ _ _ _ pour le conteneur B.

La version originale du
fichier « /etclbashrcit qui est
--------1-1- initialement commune à
tous les conteneurs et reste
la version en place pour le
conteneur A

l:J
0 Image XYZ
c
::J
0
\.0
.-t
0 Figure 1. 1 3 - Concept de copy on wtite <COW>
N
@
.......
..c:
O'l
ï::::
En réalité, l'image n'est pas altérée, mais lorsqu'une modification est demandée sur
>-
0.. un élément d 'une image, le fichier original est copié et la nouvelle version surcharge
0
u la version originale. C'est le principe du copy on write. Tant que les accès ne se font
qu'en lecture, c'est la version initiale (issue de l'image) qui est employée. Le COW
n 'est appliqué que lors d'une modification, ce qui optimise de fait la taille de la couche
du conteneur qui ne comprend que le différentiel par rapport à l'image.
Le principe est le même pour les effacements de fichiers de l'image. La couche
conteneur enregistre cette modification et masque le fich ier initial.
1.3 Les apports de Docker: structure en couches, images, volumes et registry --------a
En réalité, l'explication ci,dessus est quelque peu simplifiée. La manière de gérer
l'union des couches et le copy on write dépend du pilote de stockage (storage driver)
associé à Docker. Certains travaillent au niveau du fichier, d'autres au niveau de
blocs plus petits. Mais le principe reste identique.

Différents pilotes de stockage


Docker peut fonctionner avec différentes implémentations de gestion de stockage. Il
en existe plusieurs qui sont associées à des caractéristiques différentes ; citons, par
exemple, devicemopper, AUFS, OverloyFS, etc. En général, Docker est livré avec un
driver par défaut adapté au système d'exploitation (par exemple, devicemopper pour
les systèmes à base de Fedora, comme RedHat ou CentOS).

Persistance et volumes
Que se passe't'il quand un conteneur s'arrête ?
La couche de conteneur est tout simplement perdue. Si cette couche comprend
des données à conserver entre deux lancements de conteneurs ou bien à partager entre
plusieurs conteneurs, il faut utiliser un volume (ou data volume).
r-----------~r-----------,

1_ Couche
1 du conteneur A 1I 1L Couche
___________ du conteneur B 1
___________ 1 Un volume (monté dans les
conteneurs sous la forme
/opUshared d'un répertoire) qui va
,.........;=======================~ stocker les données sur
l'hôte ou sur d'autres
systèmes de persistance.

l:J
0
c
::J
~
,.,
"O
0 c::;
\.0 lmage XYZ
.-t
0
.,.,
~

N
'~
@ ·c
....... B::;
Figure 1.14 - Volumes
..c: CO
Ol c
ï:::: 0
>- c Les volumes sont des espaces de données qui court,circuitent le système d'union file
o.. c
u
0 ·3
<.)
que nous avons évoqué précédemment. Ils sont modifiés directement et les données
::;
"O
0
.....
qui y sont inscrites surv ivent à l'arrêt du conteneur. Ce sont des systèmes de fichiers
c.
~ montés dans le conteneur qui, selon les implémentations, reposent :
~
::;
rS • sur un espace disque de l'hôte gere par Docker (stocké sous
"O
1
/var/lib/docker/volumes/ mais pas modifiables directement) ;
0
c
8 • sur un répertoire de l'hôte directement monté dans le conteneur et qui permet
(Ç) de créer un pont entre l'hô te et le conteneur ;
El------------------- Chapitre 1. Les conteneurs et le cos Docker

• sur un large panel de systèmes tiers qui imposent l'usage d'une extension (volume
plugin) particulière 1•

Les volumes sont un concept important dans le domaine des conteneurs Docker.
Nous les aborderons en détail au cours de nos d ifférents exemples pratiques dans la
suite de cet ouvrage.

..
1.4 LES OUTILS DE L'ECOSYSTEME DES CONTENEURS :
DOCKER ET LES AUTRES
Nous avons vu précédemment ce qu'était un conteneur, comment il é tait structuré
(du moins dans le cas de Docker) et comment il était distribué.
N ous allons maintenan t fournir une vue générale des outils qui gravitent autour de
la technologie des conteneurs. Nous souhaitons ici montrer les logiciels qui permettent
d 'exécuter des con teneurs sur une mach ine ou sur plusieurs machines en réseau.
N ous ne nous limiterons pas au cas des outils de la société Docker lnc., mais nous
présenterons aussi d 'autres acteurs. L'objectif pour le lecteur est d 'arriver à se repérer
dans ce foisonnement de produits et d 'en comprendre les position nements respectifs.

1.4.1 Les moteurs

Créer ou exécuter un conteneur implique de coordonner différents éléments du


système d'explo itation (comme CGroups ou Namespaces). Comme n ous l'avons vu,
ces différentes briques de base sont open source et communes aux implémentations de
conteneurs Linux. Ce n'est donc pas à ce niveau qu'il faut chercher la différenciation
entre les différents moteurs de conteneurs.
Le moteur d 'exécution de conteneur (par exemple, Docker Engine dans le cas de
Docker) offre en fa it d'autres fonctionnalités de plus haut niveau, au~dessus de ces
"'Cl
0 briques de base comme :
c
:::i
0 • une ligne de commande ;
\.0
.-t
0
• des API ;
N
@
• la capacité de nommer, découvrir et gérer le cycle de v ie des conteneurs ;
.......
..c • la capacité à créer des conteneurs à partir d'images ou de modèles;
O'l
ï::::: • etc.
>-
0.
0
u

1. C itons notamment Flocker ([Link] qui permet de créer des


volumes en faisan t abstraction de leur localisation phys ique.
1.4 Les outils de l'écosysteme des conteneurs: Docker et les autres ------------[!!]

Docker et Docker Engine


Comme nous l'avons déjà exposé dans l'avant-propos de ce livre, Docker est à la
fois le nom d'une entreprise et celui d'un écosystème logiciel constitué de plusieurs
outils (fournis par Docker lnc. ou aussi par d'autres entreprises). Le Docker Engine
est le logiciel qui gère les conteneurs sur une machine : le moteur. Le lecteur nous
pardonnera d'utiliser souvent le terme « Docker» quand nous parlerons du « Docker
Engine »dans la suite de cet ouvrage. Quand nous évoquerons d'autres éléments de
la suite Docker <comme la solution de clustering Swarm) nous serons plus spécifiques
dans leur dénomination.

S'il existe plusieurs moteurs ou interfaces de gestion de conteneurs, il ne fait aucun


doute que celle de Docker est de lo in la plus conviviale et la plus aboutie (et de ce fait
la plus populaire).
Citons néanmoins les principales offres alternatives :
• LXC 1 (Linux Containers), dont la première version date d'août 2008, est
historiquement la première implémentation de la v irtualisation de l'OS au
niveau du n oyau Linux. Docker s'appuyait initialement sur LXC avant de
réécrire sa propre bibliothèque de bas niveau, la fameuse libcontainer.
• Rkt2 est un logiciel open source édité par le projet/entreprise C oreOS (qui
produit d'autres composants tels etcd) qui implémente la spécification App
Container (appc) 3 , l'une des tentatives de standardiser le monde des conteneurs.
Rtk adopte une approche similaire à runC, dans le sens où il n'impose pas de
recourir à un démon (à l'inverse de Docker, comme nous le verrons par la suite)
pour contrôler centralement le cycle de v ie du conteneur.
• RunC 4 est une implémentation open source supportée par un large nombre
d'acte urs de l'industrie dont Docker. RunC s'appuie sur la spécification Open
Container lnitiative5 . RunC doit plutôt être considéré comme un composant
de bas niveau destiné à s'intégrer dans des moteurs de plus haut niveau.
• OpenVZ6 , qui représente le moteur open source de la solution de gestion
"'Cl
0 d'infrastructure virtualisée Virtuozzo 7 . OpenVZ ne s'appuie pas sur un démon
c ~
,.,
:::i
"O
comme Rkt et positionne plutôt la v irtualisation à base de conteneurs comme
0 [Link];
\.0 une alternative plus légère à la virtualisation matérielle. Cette position a changé
.-t ~
0 V
V
progressivement avec le support de Docker et de ses images.
N
'ii
@ ·c
....... [Link];
..c CO
O'l c
0
ï::::: c
>-
o. c
u
0 ·3ù
:::;
"O
0 1. [Link]
....
c. 2. [Link]
~
~ 3. [Link]
:::;
rS 4. [Link]
1
"O
0 5. [Link]
c
8 6. h t tps://[Link]/Main_Page
(Ç) 7. [Link] [Link]/
El------------------- Chapitre 1. Les conteneurs et le cos Docker

Nous noterons que toutes ces implémentations (et il en existe d'autres plus
confidentielles) sont compatibles avec le format d'image Docker.

1.4.2 Les OS spécialisés


Les conteneurs réutilisent le noyau du système d'exploitation de l'hôte sur lequel ils
tournent. En théorie, dans le monde Linux, toute distribution récente est capable
de supporter l'exécution de conteneurs. Certains éditeurs ou communautés open
source ont cependant commencé à travailler sur des OS spécialisés dans l'exécution
de conteneurs. L'objectif est de produire des OS simplifiés, plus performants et moins
exposés aux risques de sécurité ou d'instabilité.
Citons notamment :
• Boot2Docker est la distribution spécialisée par défaut que Docker installe en
local lorsqu'on utilise Docker machine (que nous aborderons dans le chapitre 7)
ou le Docker ToolBox. Il s'agit d'une distribution Linux très compacte, basée
sur le Tiny Core Linux. Notons que pour les installations distantes (c'est-à-dire
pour les serveurs) Docker propose d'autres distributions Linux et notamment,
par défaut, une distribution Ubuntu.
• CoreOS 1, qui est aussi l'éditeur de Rkt précédemment cité (et d'autres outils
d'infrastructure que nous allons présenter par la suite).
• Atomic 2 , le sous-projet de Fedora (la distribution de base qui sert à RedHat
ou CentOS). Atomic tente aussi d'imposer la spécification Nulecule comme
une norme de composition et de conditionnement de conteneurs (c'est-à-dire
une sorte de Docker compose standardisé). Nous verrons en pratique comment
installer une instance atomic dans le chapitre 4.
• Windows Nano Server3 est un système Windows réduit à sa plus simple
expression et dédié aux applications cloud. Il n'est pas uniquement dédié à
l'exécution de conteneurs (qui s'appuiera sur le moteur Windows Container
Host) , mais relève de cette même démarche de spécialisation.
l:l
0
c
:::i
0
\.0
1.4.3 Les outils d'orchestration : composition et clustering
.-t
0
N Bien qu'il soit possible d'exécuter sur un même conteneur plusieurs processus, les
@
....... bonnes pratiques en matière d'architecture consistent plutôt à distribuer ces processus
..c
O'l dans plusieurs conteneurs. Une application sera donc presque nécessairement répartie
ï:::::
>-
0.
sur plusieurs conteneurs. Comme ceux-ci vont dépendre les uns des autres, il est
0
u nécessaire de les associer.
Cette association que l'on nomme composition consiste :

1. [Link]
2. [Link]
3. h ttps://[Link] ped [Link]/wiki/Wi ndows_Server_2016
1.4 Les outils de l'écosystem e des conteneurs : Docker et les autres ------------[!!]
• à définir un ordre de démarrage (directement ou indirectement) ;
• à définir les systèmes de fichiers persistants (les volumes) ;
• à définir les liens réseau que les conteneurs vont entretenir entre eux (ou du
moins à assurer une communication transparente entre les processus).

Hôte

Descripteur \ Conteneur A

1 û .. .___ o_ut-il_d_e___
composition
Moteur de
conteneur
- - -----.\ Conteneur 8

Exemple: Exemple: Exemple: \ Conteneur C


fichierYAML Docker Compose DockerEngine
"Compose"

Figure 1. 1 5 - Composition de conteneurs

Il est bien évidemment possible de démarrer les conteneurs à la main à l'aide d'un
script exécutant des séries de docke r run .
Mais cette solut ion peut rapidement deven ir complexe. En effet, il faut aussi tenir
compte de l'éventuel besoin de distribuer la charge sur plusieurs nœuds du réseau et
plusieurs machines. Il faut donc que la composition puisse s'effectuer en collaboration
avec des o utils de clustering réseau q ui vont abolir les frontières e ntre les d iffé rents
hôtes. On parle alors d'orchestration .

r Hôte 1 ~

l:J
Exemple:
Docker Swarm ' ----7\ Conteneur A """
0 Outil de Moteur de
c ~
,., clustering
-\ Conteneur B
::J conteneur

..
"O
0 c::;
\.0 Descripteur t Exemple: ~\ Conteneur C
.-t
0
.,.,
~
DockerEngine
N
@
.......
..c:
Ol
·;::
'~
·c
B

0
::;
CO
c
c
i
Exemple:
Outil de
compos ition
Exemple:
\...

'
Hôte2
./

"""

- ..
>- c fichier YAML Docker Compose ----7\ Conteneur A
o.. "Compose"
u
0 ·3
<.)
::; Moteur de :;..\ Conteneur B
"O
0
..... conteneur
c.
~
~
Exemple: ~\ Conteneur C
::;
DockerEngine
rS \..
"O
0
1
\... ~
c
8 Figure 1. 16 - Clustering + composition = orchestration
(Ç)
El-------------------- Chapitre 1. Les conteneurs et le cos Docker

La composition et le clustering sont donc deux fonctions qui sont la plupart du


temps liées au sein de solutions de plus haut niveau. Certains parlent de système
d'exploitation de centre de calcul ou DCOS (Data Center Operating System).
Ces produits logiciels complexes sont aujourd'hui, même s'ils sont pour l'essentiel
open source, l'objet d'une compétition féroce. Nous allons décrire les principaux
acteurs de cette lutte pour la prééminence dans le proch ain chapitre en abordant la
notion de C aaS : Container As A Service.

En résumé
Dans ce chapitre, nous avons appris ce qu'est un conteneur, sur quelles briques
fondamentales les conteneurs Linux sont basés, commen t ils sont structurés dans le
cas de Docker et comment ils sont distribués.
Nous avons ensuite abordé les différents outils assurant leur exécution: moteurs de
conteneurs, systèmes d'exploitation spécialisés, outils de composition et d'orchestra-
tion.
Il est maintenant temps d'étudier l'apport de ces outils aux techniques d'automatisa-
tion de l'explo itation d'une infrastructure d'applications. Notre prochain chapitre
va montrer comment ces briques de base s'agrègent aujourd'hui dans divers types de
solutions industrielles.
Nous expliquerons aussi comment ces solutions à base de conteneurs se positionnent
par rapport à des solutions de gestion de configuration comme Puppet, A nsible ou
Chief.

l:J
0
c
::J
0
\.0
.-t
0
N
@
.......
..c:
O'l
·;::
>-
0..
0
u
2
Conteneurs et infrastructures

L'automatisation de 1'exploitation
L'objectif de ce ch apitre est de montrer comment les conteneurs se positionnent
comme une nouvelle opportunité pour automatiser le déploiement et l'exécution des
applications dans les entreprises. Nous allons aborder la notion de CaaS (Container as
a Service ) mais aussi t enter d e positionner la technologie des con ten eurs par rapport
à d'autres solutions d'automatisation de la gestion de configuration , comme Puppet
ou Ansible.

2.1 AUTOMATISER LA GESTION DE


l:J L'INFRASTRUCTURE : DU IAAS AU CAAS
0
c
::J
~
,.,
"O
0 c::; La virtualisation de l'infrastructure n 'est pas nouvelle et le cloud computing fait
\.0
.-t
0
.,.,
~ aujourd'hui partie du paysage standard de tout système d'information. Nous allons,
N
'~ dans un premier temps, expliquer ce que les conteneurs apportent par rapport aux
@ ·c
....... B::;
solutions de virtualisations d'infrastructures actuelles ou laaS (pour Infrastructure as a
..c: CO
Ol
0
c Service ).
ï:::: c
>- c
o..
u
0 ·3
<.)
::;
"O
2.1.1 Virtualiser l'infrastrud ure
0
.....
c.
~ L'infrastructure est un service !
~
::;
rS En pratique, cette affirmation est déjà partiellement vraie. La v irtualisation
1
"O
0
matérielle a permis l'émergence d 'offres cloud privées ou publiq ues qui ont abstrait la
c
8 n otion de centre de calcul à un tel niveau que, pour certains usages, la nature réelle
(Ç) de l'h ôte et sa localisation géographique sont devenues secondaires.
8 -------------------- Chapitre 2. Conteneurs et infrastructures

Dans le cas des infrastructures privées, diverses solutions commerciales ( vCenter


de VMWare) ou open source (OpenStack) automatisent la gestion de cette puissance
de calcul (mais aussi de stockage, de communication réseau, etc.) virtualisée au-dessus
d'une infrastructure physique de nature variable.

Pour ce qui est des infrastructures publiques CAmazonEC2, Google, Windows Azure,
Heroku, Digital Ocean, etc.) le principe est identique, si ce n'est que les solutions sont
propriétaires, tout en étant ouvertes via des services web documentés.

Concrètement, les solutions IaaS offrent aux applications conditionnées sous la


forme d'images de machines virtuelles (par exemple, les AMI pour Amazon ) des
services d'infrastructure, comme :
• de la puissance de calcul, via un environnement d'exécution pour une machine
virtuelle basée sur un hyperviseur : VMWare, Xen, KVM, etc. ;
• du stockage qui peut se présenter sous différentes formes selon les niveaux de
performance et de résilience requis ;
• des services réseau : DHCP, pare-feu, fail-over, etc. ;
• des services de sécurité : authentification, gestion des mo ts de passe et autres
secrets.

[in,age de machine 1
L virtuelle

~
Services d'infrastructure

Réseau

Stockage Sécurité

l:J
0 Ressources physiques
c
::J (machines. disques. routeurs. etc.)
0
\.0
.-t
0
N Figure 2.1 - Services d'infrastructure d'une solution laaS
@
.......
..c:
O'l
·;::
>- Pour peu qu'une application soit conditionnée sous la forme d'une ou plusieurs
0..
0 machines virtuelles, elle bénéficie des ressources dont elle a besoin sans avoir à se
u
soucier de la gestion de la qualité de service liée à l'infrastructure.
En effet, les solut ions laaS vont détecter les failles matérielles (voire les anticiper)
et s'assurer que l'environnement d 'exécut ion est toujours actif. S i une machine
ph ysique casse, les machines v irtuelles qu'e lle exécute à un instant donné peuvent
être transférées de manière quasi transparente sur un autre hôte.
Mais alors que vont apporter les conteneurs aux solutions laaS ?
2.1 Automatiser la gestion de l'infrastructure : du laaS au CaaS - - - - - - - - - - - - - a
2.1 .2 Le conteneur n'est-il qu'un nouveau niveau de virtualisation ?
Les conteneurs, et Docker en particulier, sont donc au centre d'une nouvelle gamme
de solutions que certains nomment CaaS pour Container as a Service qui fait écho à
l'laaS que nous avons évoqué précédemment.
En quoi l'utilisation de conteneurs change-t-elle la donne ?
Pratiquement, les conteneurs ne changent pas les solutions laaS qui conservent
leurs avantages propres, mais ils peuvent s'appuyer sur elles pour les étendre et offrir
de nouvelles opportunités.
Nous avons vu dans le chapitre 1 ce que pouvait apporter la virtualisation à base de
conteneurs par rapport à la virtualisation matérielle. Il ne s'agit pas d'une alternative
technologique, mais bien d'une autre manière de concevoir le lien entre le développeur
et l'exploitant.
Pour comprendre, analysons le processus de préparation d'en vironnement, puis le
processus de déploiement d'une application dans un en vironnement laaS.

Préparation de /'environnement en mode /aaS


La phase d'installation de l'infrastructure consiste pour le développeur à spécifier ses
besoins en matière d'environnement d'exécution (ou runtime). Il s'agit par exemple
de fournir:
• la version de Java utilisée ;
• le serveur d'application, la base de données et les autres middlewares requis ;
• d'éventuels besoins de bibliothèques additionnelles de niveau OS ;
• certaines caractéristiques non fonctionnelles de l'application (besoin en sto-
ckage, niveau de performance, besoin en backup, niveau de résilience ou de
sécurité, etc.).

l:J
0
c
::J
~
,., exploitant
"O
0 c::;
\.0
.-t
0
.,.,
~ laaS
N
'~
@ ·c
....... B::;
..c: CO
Ol c
ï:::: 0
>- c
o.. c
u
0 ·3
<.)
Runtime
::;
"O
0
.....
c.
~
~
::;
développeur
rS
1
"O
0
c Figure 2.2 - Préparation de lenvironnement
8
(Ç)
El-------------------- Chapitre 2. Conteneurs et infrastructures

Cette phase impose un dialogue poussé entre le développeur et l'explo itant. Il


faut d'une part que le développeur spécifie ses besoins, mais aussi que l'exploitant les
interprète par rapport à la capacité disponible, aux règles de sécurité ou d'architectures
prédéfinies, etc.
Certains types d'organisation, comme le modèle OevOps, visent à optimiser ce
dialogue (qui est en fait récurrent, puisque l'architecture évolue au fil du temps), mais
cette phase reste sensible et complexe à réussir. Il est clair qu'une part significative
des incidents de production de toute application est souvent le résultat de problèmes
d'alignement entre la vision du développeur et celle de l'explo itant.

Déploiement d'applications en mode laaS


Entre chaque phase d'adaptation de l'environnement, on va trouver une série de
déploiements, plus ou moins fréquents, de paquets logiciels correspondant à une
nouvelle version de l'application.

Techniquement, le paquet logiciel peut être un zip, un tar, un msi (dans le monde
Microsoft), un rpm (dans le monde Linux Fedora), le choix étant vaste. À ce ou ces
paquets sont souvent associés des scripts de déploiement plus ou moins normalisés
qui sont souvent écrits par l'exploitant (en collaboration plus ou moins étroite avec
l'équipe de développemenù.

Il s'agit pour le développeur de produire son code, de le conditionner (on parle


de build et de packaging) sous une forme qui puisse être transmise à l'explo itant. En
pratique, cette phase peut être évidemment automatisée (c'est le cas notamment
lorsque l'équipe fonctionne en déplo iement continu) , mais il ne reste pas moins que
les caractéristiques du paquet logiciel doivent rester cohérentes avec le processus de
déploiement e t l'architecture de la solution.

--111 1 111~
Code Paquet
Build
source logiciel
l:J
0 développeur
c
::J
0
\.0
.-t
0
N
exploitant
@
.......
..c:
O'l
·;::
déploiement
>-
) @
[=·r
0..
0
u

Figure 2.3 - Déploiement d'applications

L'exploitant doit se contenter de comprendre le fonctionnement de l'application


(pour préparer l'environnement), mais doit aussi comprendre comment elle est
conditionnée pour la déployer.
2.1 Automatiser la gestion de l'infrastructure : du laaS au CaaS - - - - - - - - - - - - - a
La gestion de la solution de déplo iement est en effet bien souvent de la responsabi-
lité de l'exploitant.
Certaines solutions, comme Ansible ou Puppet, permettent d'automatiser les
deux phases (préparation de l'environnement et déploiement), mais pour des raisons
évidentes, l'environnement n'est généralement pas reconstruit à chaque déploiement.
Tout d'abord parce que cette phase peut être lourde, longue et coûteuse ; ensuite parce
que l'application ne peut pas nécessairement s'accommoder d'une reconstruction
complète à chaque déploiement (disponibilité).

Attention, nous ne disons pas qu'il est impossible d'adopter une approche visant à la
reconstruction systématique de l'environnement d'exécution. L'usage de templates
d'application et d'outils automatisés de gestion de configuration (tel que Vagrant
parmi d'autres déjà cités) rend possible ce type de modèle avec des machines
virtuelles classiques. Mais reconnaissons que ce type de cas est rare dans un
environnement de production. La plupart du temps, il y a une différence claire
entre la construction de l'environnement (ou sa modification) et le déploiement
d'applications.

Les limites du modèle laaS


La virtualisation de l'infrastructure proposée par le modèle IaaS constitue un progrès
énorme dans le commissionnement et la préparation d'un environnement applicatif.
L'laaS va faciliter le provisionnement de l'infrastructure et sa gestion :
• en l'automatisant : tout se passe par configuration, pour peu que la capacité
disponible soit suffisante ;
• en offrant une manière simple de gérer la montée en charge, pour peu que
l'application le permette (par la possibilité de redimensionner l'environnement
en ajoutant de la CPU, de la RAM ou du stockage par exemple).
l:J
0
c
::J
~
,., À l'inverse, l'IaaS n'apporte aucune solution pour traiter deux questions fonda-
"O
0 c::; mentales:
\.0
.-t
0
.,.,
~

N • le déploiement des applications ;


'~
@ ·c
B • la description formelle des caractéristiques d'évolutivité et de résilience de
....... ::;
..c: CO
l'application par le développeur, leur transmission (sans perte d'information) à
Ol c
ï:::: 0
>- c l'exploitant et leur exécution en production.
o.. c
u
0 ·3
<.)
::;
"O
0
.....
c.
~
~
2.1 .3 L'apport du modèle de déploiement CaaS
::;
rS
"O
1
Les approches C aaS visent à aborder en premier lieu la problématique du déploiement
0
c d'applications. La problématique de la virtualisation des ressources matérielles est en
8 fait secondaire.
(Ç)
El-------------------- Chapitre 2. Conteneurs et infrastructures

Déployer une infrastructure à chaque version d'application


Dan s un modèle C aaS, les phases de préparation de l'en v ironnement et de déplo ie-
ment semblent indistinctes. La raison tient tout d 'abord au fait qu'une image de
conteneur Docker inclut l'en vironnement d'exécution ou runtime en même temps que
le code de l'application. Le flux 4 de la figure 2.4 est donc inexistant. L'infrastructure
est totalement banalisée et se limite à un moteur de conteneurs.
Ensuite, dans le cas d 'un développement sur la base de Docker, le paquet logi-
ciel, grâce au principe d'image évoqué dans le précédent chapitre, correspond très
exacteme nt à ce qui va être déployé par l'explo itant.

image Règles

développeur
d) 1__s_~0_u~-c~_I @ ~ Build +
de
gestion

@
l
exploitant

Figure 2.4 - Construction et déploiement d'une application en mode CaaS

Il n'y a pas de retraitement de l'image par une solution tie rce.


C omme un conteneur multimodal ph ysique, le conteneur logiciel est scellé.
L'explo itant joue le rôle de tran sporteur. Il cho isit la manière dont le conteneur va
être exécuté sans l'altérer.

l:J
Enfin, les solutions C aaS associent au déplo iement des règles de gestion. C elles-ci
0 peuvent prendre la forme d'un fichier YAML ou JSON, selon les solutions. C elui-ci
c
:J
0 peut être produit par l'équipe de développement ou être élaboré en collaboration avec
\.0
.-t l'exploitant. C ette configuration va spécifier d'une manière totalement formelle les
0
N caractéristiques non-fonctionnelles de l'architecture :
@
....... • n ombre d'instances de chaque type de conteneur ;
..c:
O'l
·;:: • liens entre les con teneurs ;
>-
0..
0 • règles de montée en c harge ;
u
• règles de répartit ion de ch arge ;
• volumes persistants ;
• etc.

Il ne s'agit ni plus ni mo ins que de programmer l'infrastructure. Vous trouverez ci-


dessous un exemple de ce type de fichier de configuration (de la solution Kubernetes) :
2.1 Automatiser la gestion de l'infrastructure : du laaS au CaaS - - - - - - - - - - - - - a
apiVersion : extensions/vl
ki nd : Deployment
( ... )
spec :
re pl i cas : 4
se l ector :
mat ch l abels :
run: he l lo -node
st rategy :
rolli ngUpdate :
maxSu rge : 1
maxUnavailable : 1
type: RollingUpdat e
template:
met ad ata :
creati onTi mest amp: nu ll
la bels :
r un : he ll o-node
spec :
containe rs :
- image : gcr. io/ PROJ ECT_IO/hello -node :vl
i magePullPo l i cy : IfNotPresent
name : hello- node
ports :
- cont ai ner Port : 8080
protocol : TCP
resources : {}
te rminat i onMessagePath : /dev/ t ermi nat ion -l og
dns Policy : Cl us t er Fi rs t
restartpol i cy : Always
secu rityCon t ext : {l
t ermi nationGracePeriodSeconds : 30

Sans entrer dans le détail, on n ote que le fichier va spécifier des informations
concernant :
• les règles de déploieme nt (par exemple ro 11 i ng Update qui explique que les
l:J
0 différents nœ uds de l'application doiven t être mis à jour les uns après les autres) ;
c ~
,.,
0
::J
"O • les caractéristiques de l'architecture en termes de nombre d'instances ( repli cas )
c::;
\.0 et de politique de redémarrage ( res t a rtpo l i cy ).
.-t
0
.,.,
~

N
'~
@ ·c N ous allons expliquer le mode de fonctionnement dynamique des solutions C aaS
....... B
..c:
::;
CO sur la base de ce type de règles de gestion dans la section suivante .
Ol c
ï:::: 0
>- c
o.. c
0 ·3 À première vue, cette programmabilité complète de l'infrastructure semble séduisante.
u <.)
::; Elle a cependant un coût : l'application doit être conçue dès son origine pour
"O
0
.....
c. fonctionner dans un mode conteneur ou micro-services. Ce sera l'objet des chapitres
~
~
suivants d'expliquer la manière de concevoir une image Docker et comment celle-ci
::;
rS peut être assemblée à d'autres images pour produire une application container-ready.
1
"O
0
c
8
(Ç)
El-------------------- Chapitre 2. Conteneurs et infrastructures

Conclusion sur le lien entre CaaS et laaS


Le modèle CaaS présuppose que des machines sont mises à disposition avec la
puissance de calcul appropriée et une solution CaaS spécialisée dont nous verrons
plusieurs exemples dans la suite de ce chapitre.
L'apport de l'IaaS dans la mise en place d'une abstraction des caractéristiques
physiques de l'infrastructure offre un intérêt certain. Néanmoins, ce lien entre CaaS
et laaS n'est pas obligatoire. Il est parfaitement possible d'adopter une approche CaaS
sur une infrastructure physique (sans couche de virtualisation additionnelle). Le choix
de l'une ou de l'autre option dépend avant tout de choix stratégiques d'entreprise
plutôt que d'une nécessité technique.

2.1.4 L'architecture générique d'une solution CaaS

Les solutions CaaS ont un certain nombre de caractéristiques communes qu'il est bon
de connaître :
• e lles incluent presque toutes Docker (en dehors de celle de CoreOS qui lui
préfère Rkt) en tant que moteur de conteneurs;
• elles fournissent des fonctions de clustering et d'orchestration (décrites dans
le chapitre précédent et qui seront abordées en pratique dans la suite de cet
ouvrage);
• e lles s'appuient sur un principe de gestion automatisée de l'infrastructure que
nous qualifierons d'ho méostatique.

Une régulation homéostatique


L'hémostasie est un concept décrit par le grand biologiste français Claude Bernard au
x1xe siècle et qui se définit de la manière suivante :
L'homéostasie est un phénomène par lequel un facteur clé (par exemple, la
température) est maintenu autour d'une valeur bénéfique pour le système
l:J
0 considéré, grâce à un processus de régulation.
c
:J
0 Les exemples courants sont :
\.0
.-t
0
N
• la régulation de la température corpore lle ;
@ • la régulation du taux de glucose dans le sang ;
.......
..c: • etc.
O'l
·;::
>-
0..
0 Par processus de régulation, o n entend la possibilité de capter l'état du système
u et de conditionner la réaction, l'intervention correctrice suite à un déséquilibre,
à ce feedback. Certains auront reconnu des notions qui sont aussi à la base de la
cybernétique.
Les outils CaaS s'appuient sur ce principe dans le sens où leur objectif n'est pas de
simplement fournir une interface de commande pilotée par un administrateur, mais
plutôt de maintenir un état stable par l'intermédiaire de processus automatiques.
Toutes les solutions CaaS ont a insi des composants en commun. Ils peuvent se
nommer de manière diverse, ma is ont en réalité le même rôle :
2. 1 Automatiser la gestion de l'infrastructure : du laaS au CaaS - - - - - - - - - - - - - a
• surveiller l'état du systè me;
• détecter les écarts par rapport aux règles de gestion programmées ;
• prendre des mesures pour ramener le système à l'équilibre ;
• prévenir l'explo itant en cas d'échec.

La gestion automatisée de l'infrastructure


Le système de régulation s'appuie généralement sur :
• un contrôleur qui va analyser l'état de l'infrastructure par l'intermédiaire
des données re montées par des agents installés sur les différents n œ uds de
l'architecture et, en fonction des règles préprogrammées, donner des ordres aux
agents ;
• des agents qui collectent des informations sur l'état des n œ uds sur lesquels ils
sont installés (offrant ainsi le feedbacl<. nécessaire au contrô leur) et , la plupart
du temps, servant de relais au contrôleur pour exécuter des actions correctrices
(le plus souvent des commandes docker) ;
• une interface d'entrée de règles de gestion qui se présente gén éralement sous
la forme d'une ligne de commande (C U) pouvant accepter des commandes
individuelles ou des fich iers de description . C ette interface est en général basée
sur des services web REST dont la ligne de commande constitue un client
particulier.

La figure ci-dessous présente une architecture générique de type CaaS .

l:J
0
c ~
,.,
R
g Règlesde
gestion
Contrôleur ....
::J
"O
0
\.0
c::; . . . . 1 Agent
.-t
0
.,.,
~

N
'~
@ ·c Les règles de gestion décrivent Un contrôleur central va
....... B::;
..c: CO l'état souhaité pour le système: surveiller l'état des différents
Ol c
ï:::: 0
c
• nombre d'instances de nœuds du système et
>- c chaque type de conteneur déclencher des actions
o..
u
0 ·3
<.) règles de gestion de charge automatiques pour s'assurer
::;
"O
0
..... • Etc. que la réalité rejoigne à chaque
c.
~ instance la description
~ «programmée».
::;
rS
1
"O
0
c Figure 2.5 - Principe de fonctionnement des CaaS
8
(Ç)
8-------------------- Chapitre 2. Conteneurs et infrastructures

Évidemment, aux composants ci-dessous, s'ajoutent le moteur de conteneurs


(Docker la plupart du temps) et, éventuellement, un registry d'image privé (cf.
chapitre 1). La plupart des solutions offrent aussi une interface graphique qui permet
une visualisation synthétique de l'état de l'infrastructure.

L'exploitant (souvent sur la base de propositions du développeur) programme les


règles de gestion et le système prendra des décisions en fonction de la puissance des
ressources disponibles : puissance de calcul, caractéristiques de l'architecture ou de
bien d'autres critères formulés sur la base de divers types de métadonnées (par exemple,
le mécanisme des labels et filtres chez Kubernetes).
Il est aussi important de comprendre que ces règles de gestion vont persister
pendant tout le cycle de l'application. En clair, le système va s'assurer que ces règles
restent toujours vraies.
Par exemple, si le configurateur a déclaré vouloir cinq instances d'un certain type
de conteneur mais qu'un agent, à un instant donné, ne détecte que quatre instances,
le contrôleur, ainsi informé, va automatiquement déclencher une nouvelle création,
sans aucune intervention humaine.

Les règles expriment des exigences, l'état cible souhaité et le système s'assure au
travers d'actions déclenchées automatiquement que cet état soit atteint et maintenu
autant que possible. D'autres solutions que nous aborderons dans la dernière section,
comme Ansible, fonctionnent sur le même principe.

Solutions CaaS et DCOS


On commence à voir émerger le terme de système d'exploitation d'infrastructure (ou
DCOS pour Data Center Operating System).
Le système d'exploitation (Windows, Linux, Mac OS) offre des services de haut
niveau qui permettent aux applications de disposer des ressources d'une machine sans
"'Cl en connaître les caractéristiques techniques intimes. L'objectif de ces solutions est
0
c identique, mais à l'échelle d'un centre de calcul. Ils offrent des services de haut niveau
:::i
0 pour résoudre la plupart des problèmes de gestion de déploiement et de charge sur la
\.0
.-t base de modèles standardisés (patterns) et éprouvés .
0
N
@ Les conteneurs et les solutions CaaS sont au cœur de ces DCOS mais n'en sont
.......
..c probablement que l'une des composantes. En effet, toutes les applications n e sont
O'l
'i: pas encore container-ready, c'est-à-dire architecturées pour être compatibles avec une
>-
0. approche à base de micro-services. Les DCOS se doivent donc d'être capables de gérer
0
u différents types de ressources (et pas uniquement des conteneurs).
N ous présenterons dans ce chapitre la solution Apache Mesos 1, qui constitue un
exemple de DCOS, pour expliquer comment les moteurs CaaS s'intègrent dans ce
type de produit.

1. h ttp://[Link] [Link]/
2.2 Les solutions CooS --------------------------8
2.2 LES SOLUTIONS CAAS
N ous allons maintenant aborder quelques-unes des solutions emblématiques de ce
phénomène C aaS. Attention, il est important de bien intégrer le fait que ce nouveau
marché est en pleine construction. Aucune des solutions décrites ne recouvre
complètement les autres d'un point de vue des fonctionnalités offertes. C ertaines
affichent même la possibilité de collaborer ou de s'intégrer avec d 'autres. Mais, ne
nous y trompons pas, la compétition est féroce et c'est à une course de v itesse que se
livrent les principaux acteurs de ce marché.

2.2.1 Docker Datacenter : vers une suite intégrée

O utre le Docker Engine, la société Docker lnc. édite d'autres logiciels. Certains ont
été développés en interne, tandis que d'autres ont été rachetés à d 'autres sociétés
(comme Compose ou Tutum, par exemple ).
Docker travaille activement à la consolidation de ces différents outils en une suite
cohérente : Docker Datacen ter.

Docker Datacenter vs. Tutum


Actuellement, Docker offre en fait deux suites différentes : une offre public cloud
construite autour de Tutum et le Docker Hub (registry public>, et une offre derrière le
firewall que nous allons décrire ci-dessous, et qui s'appuie sur UCP (Universol Contrai
Plane). Cette situation est sans aucun doute transitoire. Les fonctionnalités de la version
cloud <historiquement apportées par Tutum> vont sans aucun doute être fusionnées
avec UCP pour ne faire qu'une seule suite avec deux instanciations : une offre cloud
et une offre on premise pour les clients souhaitant installer ces logiciels au sein de leur
infrastructure privée.

Les briques de base


"'Cl
0 La suite de Docker est constituée de plusieurs produits qui aujourd'hui sont toujours
c
:::i
~
,., disponibles indépendamment :
"O
0 [Link];
\.0
.-t ~
• Docker Compose 1 est certainement l'outil de composition de conteneurs le plus
connu et la norme de facto . Il s'appuie sur un descripteur YAML2 qui spécifie les
0 V
N V
'ii
@ ·c conteneurs, leurs dépendances et un certain nombre d 'autres paramètres utiles
....... [Link];
..c
O'l
CO
c
à la description de l'architecture. Docke r Compose travaille de concert avec
ï::::: 0
>- c Docker Swarm pour former une solution d'orchestration complète.
o. c
u
0 ·3ù
:::;
"O
0
....
c.
~
~
:::;
rS
1
"O
0
c
8 1. [Link]
(Ç) 2. h t tp://[Link]/
8 --------------------- Chapitre 2. Conteneurs et infrastructures

En réalité, Docker Compose ne fait aujourd'hui pas partie du produit Docker


Datacenter. Néanmoins, son intégration native avec Swarm en fait le choix
quasi automatique pour la composition et le déploieme nt d'architectures multi-
conteneurs. Nul ne doute que dans les versions ultérieures de la suite de Docker,
Docker Compose (au même titre que N otary ou le Docker Trusted Registry) sera
de plus en plus intégré pour progressivement constituer une solution homogène.

• Docker Swarm 1 est l'outil de clustering de Docker. En pratique, Docker Swarm


transforme plusieurs machines en un seul hôte Docker. L'A PI proposée est
exactement la même que pour un seul et unique hôte. Swarm y ajoute des
fonctions de plus haut niveau qui virtualisent le réseau et permettent d'exécuter
en ligne de commande des opérations de déploiement ou de gestion de charge.
• Docker Trusted Registry2 permet de stocker les images de conteneurs de
manière privée, derrière le fi rewall du client. La commun ication avec ce registry
est sécurisée par Docker Notary3 qui gère la signature des images et leur
vérification.
• Docker UCP (Universal Control Plane) 4 est le centre de contrôle du DataC en-
ter. C ette inte rface graphique permet de v isualiser ses conteneurs répartis sur
plusieurs hôtes et d'effectuer diverses opérations de superv ision, d'administration
ou de configuration.

L'objectif de Docker est de proposer une suite supportant d 'un bout à l'autre le
cycle de développement, déplo iement et opération.

BUILD SHIP RUN

Universal contrai ••
~I
D plane

Docker compose 1
.
....

Docker Docker Trusted

~~
l:J Toolbox Registry
0
c
:i
0

~~-~I
Les développeurs Les images sont publiées
\.0
.-t construisent les images sur sur le registry privé de
0 leur environnement local
N l'entreprise. Les transferts
@ d'images sont sécurisés par
....... des mécanismes de
..c signature supportés par Docker Swarrn
en
·c Docker Notary.
Grace à l'UCP et la suite
>-
0. Docker, les opérations
0
u gèrent l'infrastructure
d'exécution des conteneurs.

Figure 2.6 - Chaîne de livraison de Docker

l. h ttps://[Link]/producrs/docker-swarm
2. [Link]
3. [Link]
4. [Link]
2.2 Les solutions CooS --------------------------8
Comment ça marche ?
Chaque hôte de l'architecture exécute un agent Swarm. C et hôte constitue alors
un Swarm node. L'agent offre une interface de contrôle (et de surveillance) au point
central de pilotage du cluster swarm : le manager.
Le manager est le service qui expose l' API de contrôle du cluster. Il peut être
télécommandé en ligne de commande (Docker CU) ou bien via le Docker UCP (une
interface web).

Notez qu'en production on aura généralement plusieurs master nodes <pour des
raisons de haute disponibilité). Dans ce cas, plusieurs managers sont installés et la
résilience de l'ensemble est assurée par la réplication de l'état de ces managers, par
exemple au travers d' etcd.

Une fois l'ensemble installé, Swarm va offrir différents algorithmes de gestion


automatisée de conteneurs. Dans la terminologie Swarm, on parle de filtres et de
stratégies. N ous aborderons en détail et par la pratique ces concepts dans le chapitre 11,
mais nous pouvons ici illustrer notre propos par quelques exemples.

Universal control
DockerCLI
plane

~~---------- ---------~,

I
~
Hôte 3
''
I Swarm manager S\varrn master \
node

..
Swarm Swarm Swarm

l:J

0
0
c
::J
~
.
.,
"O
c::;
....
agent

-~
......
agent

-~ -~
agent

~
\.0
.-t
0
.,.,
~

N Hôte 1 Hôte2 Hôte 3


·~ S\varrn node 1
@ ·c Swarm node 2 S\varm node 3
....... B::; \ I
..c: CO
Ol c ' , Swarm cluster ,, /
ï:::: 0
>-
o..
c
c '--------------------~'
u
0 ·3
<.)
::; Figure 2. 7 - Architecture Swarm
"O
0
.....
c.
~
~ L'une des stratégies de Swarm se nomme spread. C elle,ci, lorsqu'un administrateur
::;
rS (via l'UC P ou en ligne de commande) va demander la création d'un certain nombre
1
"O
0
de conteneurs, va automatiquement s'assurer que ces créations sont uniformément
c
8 distribuées sur chaque nœ ud du cluster. D'autres algorithmes tenteront d'optimiser
(Ç) le déploiement en fonction de la ch arge des machines (CPU et RAM, par exemple).
8--------------------- Chapitre 2. Conteneurs et infrastructures

Il est aussi possible de déclarer des relations d'affinité plus ou moins complexes. Par
exemple, vous pouvez vous assurer que les conteneurs base de données ne sont créés
que sur les nœuds qui possèdent des disques SSD haute performance.
Grâce à cette bibliothèque de règles (qui va probablement s'enrichir au fil du temps)
Swarm offre la possibilité de configurer un large panel d'architectures applicatives et
de stratégie de gestion de charge.

UCP, le centre de pilotage central


Le pilotage d'un cluster Swarm se fait par défaut par l'intermédiaire de la ligne de
commande Docker. Pour compléter son offre, Docker a néanmoins mis à la disposition
de ses clients une interface de gestion graphique : l'UCP (pour Universal Control
Plane).
L'UCP propose une visualisation synthétique de l'état du cluster de conteneurs
Docker. Il permet aussi de défi nir différents niveaux de profils d'administration associés
à des niveaux de droits différents.

W Dock:N Un vN<,al <or•rol Pl1nt' adm1n ~

A Dashboard Dashboard

Overvfew

Applications
111§5
Nodes

Volumes
1 24 41 2
Networks
Resources
Images

~p'
Users & Teams

Settings

l:J

0
0
c
::J

\.0
.-t
0
N
@
Cluster Controllers

ml
""
hrtpsl/17 314101"443 tcp://172.31 .4 101 :2376 etCd'.1/172.31.4. 101 :12379

.......
..c:
O'l
·;:: Figure 2.8 - UCP, le cockpit graphique de l'écosystème Docker
>-
0..
0
u
2.2 Les solutions CooS --------------------------8
Certains auront peut,être entendu parler du projet open source Shipyard 1 qui
propose aussi une interface d'administration graphique pour les outils Docker.
Aujourd'hui, Shipyard offre une alternative vraiment intéressante à UCP pour
les petits budgets. Néanmoins, au fil des nouvelles versions, il est probable que
Docker enrichisse son offre de fonctionnalités plus avancées et moins ouvertes
(UCP n 'est en effet pas un projet open source).

La suite CaaS de Docker n'est pas la seule sur le marché. D'autres solutions offrent
des fonctionnalités similaires, tout en s'appuyant néanmo ins presque systématique,
ment sur le moteur de Docker.

2.2.2 Kubernetes : 1'expérience de Google offerte à la communauté

Kubernetes 2 est un projet open source initié par G oogle. Contrairement à ce qui est
souvent écrit, G oogle n'utilise pas Kubernetes en interne, mais un autre système
nommé Borg. N éanmoins, Kubernetes a clairement bénéficié de l'expérience de
Google dans la gestion de centres de calculs et d'applications distribuées hautement
disponibles. Notons que G oogle utilise des conteneurs depuis près de dix ans, ce qui
explique pourquoi la plupart des technologies de base des conteneurs (notamment
CGroups et Namespaces) ont été élaborées par des ingénieurs de Google.
Kubernetes s'appuie sur le moteur de Docker pour la gestion des conteneurs3 . Par
contre, il se positionne comme une alternative à Docker Swarm et Docker C ompose
pour la gest ion du clustering et de l'orchestration.
Dans les faits, G oogle ne souhaite probablement pas concurrencer Docker sur le
terrain de l'édition de logiciels, mais utilise Kubernetes pour promouvoir son offre
Cloud CaaS, nommée Google container engine4. C e produit, qui s'intègre dans son offre
de cloud public (certainement la plus riche du marché après celle d'Amazon), est
justement basé sur Kubernetes, sa ligne de commande et son format de descripteur.

"'Cl
0 L'architecture de Kubernetes
c
:::i
~
,.,
"O
0 [Link]; La figure ci,dessous présente une architecture synthétique de Kubernetes. On y
\.0
.-t ~ distingue notamment les deux composantes habituelles des CaaS :
0 V
N V
'ii
@ ·c • un contrôleur central, chef d'orchestre du système, ici nommé kubemetes control
....... B
..c
:::;
CO plane qui, comme pour Swarm, peut stocker sa configuration dan s un cluster
O'l c
ï::::: 0
c etcd;
>-
o. c
u
0 ·3ù
:::;
"O
0
....
c.
~
~ 1. [Link]
:::;
rS 2. h t tp://[Link]/
1
"O
0 3. Kubernetes a aussi pour objectif de s'ouvrir à d'autres moteurs, n otamment RKT, le moteur de
c
8 conteneurs de CoreOS.
(Ç) 4. [Link] .[Link]/containeHngine/
El--------------------- Chapitre 2. Conteneurs et infrastructures

• un ou plusieurs nœ uds (ou node) qui hébergent les agents Kubem etes, que l'on
nomme également kubelets, et évidemment, les conteneurs organisés en pods 1•

Node

Kubelet

Kubectl (CLI) Kube-proxy

Authentification

API server

Controller
Scheduler
Manager

Kubernetes Control Plane

Stockage de
configuration ..
~~
Pod
..
Pod

(1•
- (\
Oockerengo~

Figure 2.9 - Architecture de Kubernetes

Les kubelets sont les agents qui contrôlent les conteneurs qui sont regroupés en pod
l:J
dont n ous allons évoquer les caractéristiques un peu plus bas. Ces kubelets contrôlent le
0
c cycle de vie des conteneurs et surveillent leur état (en utilisant notamment cAdvisor2
:i
0 en lien avec le moteur Docker). On trouve aussi sur chaque nœud un autre composant
\.0
.-t important: le kube~proxy.
0
N
Le kube~proxy est un proxy répartiteur de charge (load balancer) qui gère les règles
@
....... d'accès aux services (la plupart du temps des interfaces http/https) offerts par les pods,
..c
en
'i:
mais à l'intérieur du cluster Kubemetes uniquement. Ce dernier point est important
>- et nous y reviendrons dans la prochaine section.
0.
0
u Les kube,proxies sont mis à jour chaque fois qu'un service Kubernetes est mis à
jour (qu'il soit créé ou que son implémentation ait changé de place) et ils permettent

1. Pod, que l'on pourrait traduire en français par réceptacle ou enveloppe, désigne un groupe
de conteneurs qui collaborent étroitement pour fourn ir un service donné. Ils vont donc, dans
l'arch itecture Kubernetes, pouvoir communiquer entre eux sans intermédiaires.
2. [Link]
2.2 Les solutions CooS --------------------------8
aux conteneurs de s'abstraire de la localisation réelle des autres conteneurs dont ils
pourraient avoir besoin.
On n otera que le Kubem etes Control Plane est en fait constitué de plusieurs sous-
composants :
• un serveur d'API REST « API server », qui est notamment utilisé par Kubectl,
la ligne de commande Kubem etes qui permet de piloter tous les composants de
l'architecture ;
• le sch eduler, qui est utilisé pour provisionner sur différents nœ uds (node) de
nouveaux pools de conteneurs en fonction de la topologie, de l'usage des
ressources ou de règles d 'affinité plus ou mo ins complexes (sur le modèle des
stratégies Swarm que nous avons évoquées précédemment). Dans le futur,
Kubem etes affirme vouloir s'ouvrir à différentes implémentations, v ia un
mécanisme de plugins, probablement pour prendre en compte des règles de
plus en plus sophistiquées ;
• le controller manager, qui exécute les boucles de contrôle du système ou controllers
(à une fréquence déterminée) pour vérifier que les règles de gestion programmées
sont respectées (no mbre d'instances de certains conteneurs, par exemple).

Node, pod et conteneurs


Kubernetes organise les applications à base de conteneurs selon une structure et un
modèle réseau propre auxquels il faut se soumettre.
Nous avons déjà vu q ue les nœ uds ou node (correspondant gén éralement à un
h ôte physique ou virtuel) h ébergent un ou plusieurs pods. Un pod est un groupe de
conteneurs qui seront toujours co-localisés et provisionnés ensemble. C e sont des
conteneurs qui sont liés et qui offrent une fonction (une instance de micro-serv ice). À
ce titre, tous les conteneurs d'un pod vont se trouver dans une sorte de même machine
logique :
• ils partagent les mêmes volumes (stockage partagé) ;
l:J
0 • ils peuvent interagir en utilisant le nom de domaine localhost, ce qui simplifie
c
::J
~
.
., les interactions entre conteneurs à l'intérieur d'un même pod.
"O
0 c::;
\.0
.-t
0
.,.,
~

N
·~ Modèle réseau Kubernetes
@ ·c
B
.......
..c:
::;
CO
En réalité, le modèle réseau de Kubernetes va encore plus loin. Chaque pod est
Ol c associé à une adresse IP unique. De plus, l'espace d'adressage à l'intérieur d'un cluster
ï:::: 0
>- c
o.. c Kubernetes est plat, c'est-à-dire que tous les pods peuvent se parler en utilisant ladresse
u
0 ·3
<.)
::; IP qui leur a été allouée sans avoir recours à de la translation d'adresse <NAT ou
"O
0
.....
c.
Network Adress Translation).
~
~
Cette pratique facilite l'implémentation de clusters multi-hôtes, mais diffère notablement
::;
rS du modèle réseau par défaut de Docker qu'il est néanmoins possible de changer. C est
"O
1
d'ailleurs ce qu'offre Swarm en créant un moteur Docker au travers de plusieurs hôtes.
0
c
8
(Ç) S i un pod est une instan ce de micro-service, alors qu'est-ce qu'un micro-service ?
a Chapitre 2. Conteneurs et infrastructures

Service Service
front - end back-end

Node1

Kube-proxy

Pod
front - end
Pod
back-end

External
HTIPIHTIPS
load balancer
Node2

Kube-proxy

Pod Pod
front-end back- end

Figure 2. 1 0 - Topologie, services et load balancing

Kubernetes définit un service (ou micro-service) comme un ensemble de pods


associés à des règles d'accès, de réplication e t de répartition de charge spécifiques.
Le service est une abstraction (grâce notamment aux kube~proxies ) qui permet à un
consommateur (à l'intérieur du cluster) de ne pas avoir à connaître la localisation ou
même le no mbre des pods qui produisent la fonctio nnalité consommée.
Attention néanmo ins, la n otion de service est interne au cluster Kubernetes.
En effet, le kube~proxy (figure 2.10) permet, par exemple, à un pod front~end de
l:J trouver un pod back~end. Pour ce faire, il demande à accéder au service back-end
0
c
::J
(auto matique ment déclaré sur tous les kube~proxy du cluster) et le kube~proxy de son
0 node va le router automatiquement vers une instance de pod back-end en utilisant une
\.0
.--t
0
règle simple de type round robin 1 • Grâce à ce mécanisme, le front-end n'a pas besoin
N
de savoir où se trouve le back-end et à combien d'exemplaires il existe.
@
.......
..c:
O'l
·;:: External food balancer
>-
0..
0 Par contre si un utilisateur extérieur souhaite accéder au front~end, il est nécessaire
u
d'utiliser un extemal load balancer, c'est-à-dire un répartiteur de charge externe au
cluster qui va être associé à une IP publique et offrir les fonctions habituelles :
• chiffrement SSL ;

1. Round robin est un algorithme de répartition de traitement dans lequel les processus participants
sont sollicités à tour de rôle.
2.2 Les solutions CooS --------------------------[!!]
• load balancing de niveau 7 ;
• affinité de session ;
• etc.

La configuration de ce type de service (car il s'agit bien d'un service) dépend du


fournisseur de l'implémentation de Kubernetes. Dans le cas de Google Container
Engine, l'offre cloud de Google, l'implémentation de cet external load balancer est
basée sur le Google Compute Engine network load balancer1•

Depuis sa version 1.2, Kubernetes a même introduit un nouveau type de contrôleur,


lngress controller, pour provisionner dynamiquement ce type de composant externe
(nommé de ce fait Ingress load balancer, qui pourrait se traduire par « load balancer
entrant » ). L'objectif est de s'intégrer à différentes solutions (reverse proxy, load
balancer, [Link]), mais, à cette date, la seule implémentation disponible (à l'état
de beta) est basée sur HAProxy2•

Avec Kubernetes, Google tente de s'imposer comme l'implémentation de référence


du CaaS. Kubernetes, par rapport à l'offre de Docker, est plus intégré, si bien que sa
présence n'est pas étonnante dans d'autres solutions, notamment:
• Mesos (ou DCOS3 sa déclinaison commerciale) dont Kubernetes constitue un
framework, au même titre que Marathon (que nous présentons dans la suite de
ce chapitre) ;
• OpenShift4 , la solution PaaS de RedHat ;
• OpenStack, la solution open source de référence pour la gestion de laaS
publiques et privées.

N otons enfin un projet comme Ubernetes5 qui étudie la possibilité de proposer un


modèle CaaS multi-cluster pour gérer plusieurs data centers et donc éventuellement
plusieurs fournisseurs de cloud privés ou publics. Ainsi, une entreprise pourrait choisir
de répartir ses applications de manière transparente entre son infrastructure interne
"'Cl
0 et Google Container Engine.
c
:::i
~
,.,
"O
0 [Link];
\.0
.-t
0
~
V 2.2.3 DCOS : le cas Apache Mesos et Marathon
N V
'ii
@ ·c
....... [Link];
Apache Mesos est à l'origine même du concept de système d'exploitation de centre
..c CO
de calcul (ou DCOS pour Data Center Operating System qui est d'ailleurs le nom de la
O'l c
0
ï::::: c
>- c version commerciale de Mesos) que nous avons déjà évoqué précédemment.
o.
u
0 ·3ù
:::;
"O
0
....
c.
~ 1. [Link]
~ 2. [Link] site de HA Proxy et imp lémentation au sein de Kubemetes [Link]
:::;
rS com/kubemetes/contrib/tree/master/service-loadbalancer
1
"O
0 3 . [Link]
c
8 4. [Link] [Link]/
(Ç) 5. [Link]/ubernetes
El-------------------- Chapitre 2. Conteneurs et infrastructures

Mesos a été développé dans le cas d'un projet de recherche de l'université


américaine de Berkeley. Il est notamment utilisé pour la gestion de l'infrastructure de
Twitter ou d'AirBnb.

Figure 2.11 - Interface graphique de contrôle de Marathon

Mesos a une vocation plus large qu'un CaaS classique, dans la mesure où il est
apparu avant la vague Docker. Mesos offre n otamment un concept de framework qui
lui permet de se brancher sur diverses solutions de contrôle, notamment Kubernetes,
mais aussi Marathon, la solution maison de gestion de con teneurs.
En pratique, on retrouve exactement la même architecture conceptuelle :
• un mesas master (éventuellement répliqué dans le cadre d'une architecture à
haute disponibilité) ;
• des mesos slave qui hébergent les agents qui vont exécuter les ordres émis depuis
le master et fournir des informations en temps réel sur l'état des hôtes.
l:J
0
c Tout comme les solutions précédemment étudiées, Mesas/Marathon va utiliser
:J
0 divers algorithmes pour mettre en correspondance les ressources ( CPU, RA M ou
\.0
.-t autre) disponibles dans l'infrastructure et les demandes d'exécution s d'applications
0
N (synchrone ou batch) .
@
.......
..c: À l'inverse des solutions pure C aaS, comme Kubernetes ou Swarm, Mesos peut
O'l
·;:: aussi utiliser d'autres technologies de déploiement et d 'exécution. En plus des
>-
0.. framework Marathon ou Kubernetes, Mesas peut utiliser:
0
u
• des schedulers classiques, comme Jenkins ou Chronos (qui peuven t donc exécuter
n'importe quel type de commande) ;
• des solutions Bigdata, comme H adoop ;
• des solutions de stockage de données, comme Cassendra.
2.2 Les solutions CooS --------------------------[!!]
2.2.4 Fleet + Rkt + Etcd : la solution de CoreOS
La solution de CoreOS est présentée très sommairement au travers de la figure 2.12.
C elle-ci, quo ique complète et open source, est probablement plus confidentielle que
celles que nous avons citées précédemment.

Système d'exploitation
spécialisé pour les hôtes de
conteneurs
Solution de clustering
Équivalent: Boot2dockerou
Atomic .J Équivalent: Swarm

0 CoreOS "GJ rkt


t
Moteur de conteneur
Équivalent: Dockerengine
'
fleet

Figure 2. 1 2 - Offre de gestion CaaS de CoreOS

La suite de CoreOS ressemble à celle de Docker, dans la mesure où elle est


constituée de produits indépendants organisés en une suite plus ou moins intégrée.
N otons qu'etcd, qui est un projet de la société CoreOS, est utilisé pour assurer la
haute disponibilité d'autres solutions dont Docker Swarm et Kubernetes.

2.2.5 Les offres cloud de container se1Vice


Les trois grands acteurs du monde cloud offrent aujourd'hui des solutions CaaS à base
de conteneurs. S i ces solutions sont encore peu utilisées, on constate qu'il s'agit pour
tous d'un axe de développement majeur.

l:J
0 Google Container Engine
c
:i
~
,.,
"1:l
0 c;:; Il y a peu de chose à ajouter sur cette offre lancée par G oogle en novembre 2014, si
\.0
.-t
0
~
V
ce n'est qu'elle s'appuie évidemment sur Kubernetes, projet open source financé et
N V
'& promu par le géant californien.
@ ·c
....... B;:;
..c CO
en
ï:::::
c
0
Amazon ECS, l'autre offre cloud
>- c
o. c
0 ·3 Amazon a lancé son offre Amazon EC2 Container Service (ou ECS) en novembre 2014.
u <.)
;:;
C ette offre ne s'appuie ni sur Kubernetes, n i sur la suite de Docker. Amazon a tout
"1:l
0
.....
c.
~
simplement fabriqué sa propre solution .
2:l;:;
Celle-ci s'appuie sur un agent open source 1 , mais sur un contrôleur qui, lui, ne
rS
1 l'est évidemment pas, puisqu'il est uniquement implémenté par Amazon EC2 (dans
"1:l
0
c
8
(Ç) 1. h ttps://gi [Link]/aws/a mazon-ecs-agent
El-------------------- Chapitre 2. Conteneurs et infrastructures

le cloud). Le ch o ix de mettre le code de l'agent ECS en open source est peut,être


motivé par l'idée de proposer des offres hybrides public/privé à des sociétés qui y
trouveraient leur intérêt. On pourrait en effet envisager une société qui s'appuierait
sur un front,end hébergé dans le cloud Amazon et un back,end privé, hébergé dans
un cloud d'entreprise, l'ensemble étant géré par un contrôleur fourni... par Amazon.

Azure Container Setvice


Microsoft est sans aucun doute le dernier arrivé dans la course, tant sur la technologie
Docker que pour la fourniture d'un CaaS complet.
Comme nous l'avons évoqué en début de chapitre, le lien étroit entre conteneur
et Linux (ou du mo ins Unix) est probablement la raison de ce retard.
Aujourd'hui, Azure Container Service s'appuie sur la virtualisation matérielle
maison HyperV et propose deux déclinaisons de CaaS basées sur:
• Mesos et Marathon ;
• Docker Swarm.

Gageons que la sortie de Windows 2016 et de son implémentation native de


Docker (évoquée en début de chapitre) apportera son lot de nouveautés, la proximité
entre la firme de Redmond et la startup de San Francisco ne pouvant qu'engendrer
des synergies intéressantes.

2.3 ANSIBLE, CHEF ET PUPPET : OBJET ET LIEN AVEC


DOCKER ET CAAS
Les solutions CaaS sont clairement des nouveautés sur le marché de la gestion d'infra,
structures (configuration et déploiement). La plupart des départements informatiques
doivent composer avec un existant constitué d'un large panel de techno logies. Il est
donc probable que ces systèmes ne soient mis en œuvre que pour des applications
l:J
0
c
nouvelles ou, plus certainement, par des startups ayant la chance de pouvoir s'offrir
0
:J un greenfield 1 •
\.0
.-t La technologie des conteneurs (et plus spécifiquement Docker) a néanmoins
0
N rapidement percolé au sein de solutions d'administration de systèmes existantes. Ces
@
.......
solutions ont simplement ajouté à leur portefeuille la gestion des conteneurs, en raison
..c:
O'l des avantages qu'ils offrent pour le conditionnement d'applications.
·;::
>-
0..
0
u 2.3.1 Obiectif de ces solutions
À partir de 2005, plusieurs solutions sont apparues visant à unifier la gestion de
configuration d'infrastructures informatiques. Citons par exemple Puppet (sortie en
2005), Chef (sortie en 2009) ou Ansible (qui date de 2012).

l. Littéralement un «ch amp vert » qui symbolise l'absence d'existant, aussi appelé legacy.
2.3 Ansible, Chef et Puppet: obiet et lien avec Docker et CaaS _ _ _ _ _ _ _ _ _ _ _ _ _ _ EJ
Ces solutions se basent sur des DSL 1 (Domain Specific Language ) qui permettent de
déclarer la configuration cible à atteindre pour des systèmes éventuellement distribués.
Cette configuration peut recouvrir :
• la configuration de l'OS ;
• l'installation et la configuration de logiciels standards ou personnalisés;
• la gestion de services (démarrage, redémarrage);
• l'exécution de commandes distantes.

Le but de ces outils est de remplacer les nombreux scripts (shell, python, perl, etc.)
couramment utilisés pour les tâches courantes de configuration et de déplo iement par
une bibliothèque d'actions standardisée utilisant un seul langage, une seule solution.

,- ..\

Fichier 'r'
1/ I
JSON / YAML
Orchestrateur et Il I

,,,
1 I
configurateur

Commandes de
configuration native pour
le host ciblé

Figure 2.13 - Principe des DSL de configuration

Outre l'uniformisation de l'outillage, ces solutions facilitent les transferts de


l:J
0
connaissance et permettent de s'abstraire (dans une certaine mesure ) des évolutions
c
::J
~
,., technologiques. En effet, les personnels n'ont plus besoin de connaître tous les détails
"O
0 c::;
\.0
et spécificités des systèmes opérés. Ils peuvent aussi communiquer plus simplement les
.-t
0
.,.,
~
uns avec les autres.
N
'~
@ ·c Enfin, ces outils permettent de simplifier l'élaboration de procédures de configura-
....... B::;
..c: CO tion indépendantes des environnements. Elles sont donc particuliè rement adaptées
Ol c
0
ï::::
>- c aux approches de type intégration continue ou déploiement continu. Un seul ensemble
o.. c
0 ·3 de scripts peut ainsi être utilisé pour déployer sur les différents en v ironnements
u <.)
::;
"O
0
applicatifs : développement, qualification, pré-production et production.
.....
c.
~
~
::;
rS
1
"O
0 l. Un DSL est un langage « spécialisé » , c'est-à-dire qu'il vise à un usage particulier (comme le
c
8 langage Dockerfile qui vise à construire des images de conteneurs). Le DSL se définit par opposition
(Ç) aux langages universels, comme Java, C, Python, etc.
El-------------------- Chapitre 2. Conteneurs et infrastructures

2.3.2 Un exemple : Ansible

Nous allons prendre, à titre d'exemple, le cas d'Ansible ([Link]


Nous verrons par la suite que les principes de fonctionnement sont relativement
similaires pour les différentes solutions.
Ansible est une solution appartenant à Red Hat Software (l'éditeur de la distri~
bution Linux éponyme ) et disponible en version open source depuis 2012. Ansible
s'appuie sur une bibliothèque de modules permettant de définir des descripteurs de
configuration appelés playbooks. Ansible s'appuie sur une très large bibliothèque de
modules couvrant la grande majorité des action s les plus courantes : copie de fichier,
installation de logiciels, gestion de services, etc.

Contrairement à d'autres solutions, Ansible est une solution dite agentless. Cela
signifie qu'il n'impose pas l'installation d'un agent sur l'hôte qui doit être configuré.
La seule exigence est de disposer d'un accès SSH et que Python (2.x) soit installé
sur cette machine distante.

La notion d'inventaire
Une fois Ansible installé sur la machine de contrôle (celle qui va configurer les autres),
une lign e de commande va permettre de prendre le contrôle des h ôtes ciblés. Ces h ôtes
cibles sont organisés dans ce qu'Ansible nomme un inventory. Celui~ci, par défaut, se
trouve dans le fichier /etc/ansible/hosts dont voici un exemple :

[ frori leri d ]
feül .examp l e . com
fe02 .example . com
fe03 .[Link]

[backend]
beül .example . com
be02. exampl e . com
l:l
0
c Ces machines (qui peuvent être virtuelles grâce à des connecteurs pour diverses
:::i
0 solutions cloud comme AWS) sont organisées en groupes. Ces groupes vont permettre
\.0
.-t de lancer des actions de masse. On peut vouloir, par exemple, mettre à jour tous les
0
N serveurs web ou bien faire un ping sur toutes les machines de l'inventaire, comme
@
.......
ci~dessous :
..c
O'l
'i:
>-
0. $ ansi bl e al l ·m ping
0
u feü l .example . com 1 SUCCESS => {
"changed" : f al se ,
"pin g" : "pong "
}
fe02 . examp l e . com 1 SUCCESS => {
"changed ": fa l se .
"pin g" : "pong"
)
2.3 Ansible, Chef et Puppet: obiet et lien avec Docker et CaaS _ _ _ _ _ _ _ _ _ _ _ _ _ EJ
Dans le cas ci,dessus le a 11 signifie « toutes les machines de l'inventaire » qui,
dans ce cas, n'est constitué que d'un seul et unique hôte. Si l'inventaire correspondait
à l'exemple de fichier /etc/ansible/hosts listé plus h aut, alors la commande suivante
serait aussi valide :

1 $ ansible backe nd -m ping


Cette commande appliquerait la commande ping aux hôtes [Link] et
[Link].

Un exemple de playbook
Un playbook Ansible va décrire l'état cible souhaité pour un ou plusieurs hôtes.
L'exemple ci,dessous (stocké dans un fichie r install_apache.yml) v ise à installer le
serveur web apache :

$ cat i nstal l_apac he .yml

- hosts : al l
user : ma f
become : yes
become_user : root
tasks :
- name : in sta l l er l a derni ère version d' apache
yum : name=htt pd st ate=la test
- name : con f i gurer apac he pour se lan cer au démarrage du système
service : name=httpd state=started enabled=yes

Il s'agit d'un exemple de descripteur Ansible au format YAML.

Nous n'entrerons pas dans le détail de l'usage d'Ansible, mais sachez que le fichier
ci-dessous suppose un certain nombre de choses concernant l'hôte cible. Nous voyons
notamment qu'un utilisateur « maf » doit exister sur cet hôte et que celui-ci doit être
l:J pourvu des droits sudo, afin de pouvoir fonctionner en mode root. Il est aussi nécessaire
0
c
::J
~
.
., d'avoir fait un échange de clefs SSH entre le contrôleur et l'hôte à configurer.
"O
0 c::;
\.0
.-t
0
.,.,
~
Ansible va se connecter à l'hôte (via SSH) et :
N
·~
@ ·c • vérifier qu'Apache est bien installé et qu'il s'agit de la dernière version dispo,
....... B::;
..c: CO nible ;
Ol c
ï:::: 0
>- c • que celui,ci est bien installé pour démarrer au boot de l'hôte.
o.. c
u
0 ·3
<.)
::;
"O
0
..... Une description, pas un script impératif
c.
~
~
::;
Il est important de comprendre que le descripteur ci,dessus n'est pas une séquence de
rS commandes impératives. Il s'agit de la description d'un état souhaité pour l'hôte.
1
"O
0
c Lançons la commande une première fois sur un h ôte sur lequel Apache n'est pas
8 installé :
(Ç)
Chapitre 2. Conteneurs et infrastructures

$ ansi bl e-playboo k instal l_apache .yml


PLAY
***************************************************************************

TASK [set up]


*******************************************************************
ok : [10 .0.2.4]

TAS K [ensu re apache is at th e la test version]


**********************************
changed : [10 .0. 2.4]

TASK [ensu re apache is r unning (a nd enable it at boot)J


************************
cha nged : [10 .0. 2. 4]

PLAY RECAP
*********************************************************************
10 .0. 2.4 : ok=3 changed=2 unreac hab l e=O f ailed=O

La séquence se conclut par le message changed 2 qui fait référence aux deux
actions opérées par Ansible :
• installer Apache avec sa dernière version ;
• faire en sorte qu'il démarre au boot de la machine.

Si nous lançons la commande une seconde fois:

$ ans ibl e-playbook instal l_apache .yml

PLAY
***************************************************************************

TAS K [set up]


*******************************************************************
l:J ok : [10 .0. 2.4]
0
c
::J
0 TASK [ensure apache is at the la t est vers i on]
\.0 **********************************
.-t
0 ok : [10.0.2 .4]
N
@
.......
TAS K [ens ure apache is r unn ing (and enable it at boot)J
..c: ************************
O'l
·;:: ok: [10 .0.2. 4]
>-
0..
0
u PLAY RECAP
*********************************************************************
10 .0. 2.4 : ok=3 changed=O unreacha ble=O fai led=O

Le résultat est différent: change d=O


En effet, Ansible collecte, avant d'effectuer des actions, des informations relatives
à l'environnement de la machine (on parle de facts). Ensuite Ansible analyse la
2.3 Ansible, Chef et Puppet: obiet et lien avec Docker et CaaS -------------[!!]
différence entre cette configuration et la configuration souhaitée. Les actions requises
(pas nécessairement toutes) sont ensuite lancées pour atteindre la configuration cible.
Lorsque nous avons lancé la commande une seconde fo is, comme le système était
déjà dans l'état cible, aucune action n'a été lancée.
La configuration actuelle collectée par Ansible est v isualisable par la commande
suivante (dont seul un court extrait du résultat est affiché) :

$ ans ibl e all -m set up


10 . 0. 2.4 [ SUCCESS => {
"ansible_facts ": 1
"ansible_all _i pv4_addresses ":
"192 .1 68. 122 . 1".
"10 .0 .2.4"
].
"ansibl e_all_ipv6_addresses ":
"fe80 : : a00 :27ff: fe78 : 602d "
].
"ansible_architect ure ": "x86_64 ",
"ansibl e_bios_date ": "12/01/2006",
"ansible_bios_version": "VirtualBox ",
"ansibl e_cmdl ine ": {
"BOOT_IMAGE ": "/vml i nuz -3. 10 . 0-327 . el7 . x86_64 ",
"LANG": "en_US . UTF-8 ",
"crashkernel ": "auto " .
"quiet ": tr ue.
( ... )

2.3.3 Le lien avec Docker et les solutions CaaS

Comme nous l'avons vu, Ansible présente une similarité conceptuelle avec les CaaS.
Le système fonctionne en comparant un état actuel avec l'état cible.
l:J
0 Chef ou Puppet fonctionnent selon le même principe, si ce n'est qu'à la différence
c ~
.
.,
::J
"O d'Ansible, ceux-ci requièrent l'installation d'un agent sur l'hôte.
0 c::;
\.0
.-t
0
.,.,
~

N La différence avec les solutions Kubem etes ou Swarm évoquées précédemment


·~
@ ·c est que cette comparaison d'état n'est pas permanente. Ansible vise à configurer un
....... B::;
..c: CO système, et non pas à le gérer en temps réel en analysant à ch aque instant si un
Ol c
ï:::: 0
c processus est ou n'est plus actif.
>- c
o..
u
0 ·3
<.) Les solutions CaaS et celles de gestion de configuration de type Ansible ne
::;
"O
0
..... sont donc pas, en pratique, des solutions concurrentes, mais complémentaires. En
c.
~ premier lieu, ces solutions peuvent prendre en charge l'installation et la configuration
~
::;
des agents CaaS (kubelets ou agent Swarm) sur les h ôtes. Ensuite, certaines de
rS
1 ces solutions de gestion de configuration disposent de modules pour agir sur des
"O
0
c environnements à base de conteneurs.
8
(Ç) Ansible dispose notamment d'un playbook Docker.
El--------------------- Chapitre 2. Conteneurs et infrastructures

Ainsi le playbook suivant va s'assurer qu'un conteneur nommé myserver, construit


à partir de l'image nginx (un serveur web que nous utiliserons fréquemment dans la
suite de cet ouvrage), est actif:

hasts : all
user : ma f
tasks :
name : fait en sorte qu' un cont ene ur web t ourne su r l a machine cibl e
docker :
name : myserver
ima ge: ng i nx
sta t e: started
ports: 8080 :80

Ansible va ainsi gérer tout le cycle de vie du conteneur, depuis le chargement de


l'image jusqu'à sa création et son démarrage (ou redémarrage au besoin). Autant de
commandes qu'il n'est plus nécessaire de lancer manuellement une par une.

2.3.4 Controller Kubernetes avec Puppet ou Chef


Pour conclure sur ce sujet de la complémentarité des solutions, notons que Puppet
ou Chef disposent aujourd'hui de modules (on parle de cookbook pour Chef, mais la
notion est similaire) pour gérer les déploiements sur Kubemetes ou Swarm.
Dans ce type de cas, Puppet va directement (ou en s'appuyant sur le package
manager I lelm 1 ) déployer une application sur un cluster Kubernetes.
On note dans ce cas que le cluster Kubemetes est considéré comme un hôte, ce
qui correspond exactement au niveau d'abstraction qu'un CaaS cherche à atteindre.

"'Cl
En résumé
0
c Dans ce chapitre, nous avons vu la manière dont les conteneurs, et plus spécifique-
:::i
0
\.0
ment Docker, étaient en train de coloniser les solutions de gestion d'infrastructures.
.-t
0 Nous avons étudié les solutions CaaS dédiées aux architectures applicatives exclu-
N
sivement à base de conteneur. Nous nous sommes aussi attardés sur les solutions de
@
....... gestion de configuration, comme Ansible, Puppet ou Chef qui s'intègrent aussi à
..c
O'l
'i:
Docker ou des solutions CaaS, comme Kubemetes.
>-
0.
0
u

1. Helm ([Link] est un package manager dédié à Kubemetes. Il se pose en équivalent de


« yum » ou « apt » non plus pour un h ôte mais à l'échelle d'un cluster Kubernetes.
....
DEUXIEME PARTIE

Docker en pratique ••
les outils de base

Cette seconde partie constitue une prise en main de Docker et des outils de base de
son écosystème.
Le premier chapitre décrit l'installation des outils Docker e t de l'environnement
qui sera ensuite utilisé pour les d ifférents exemples pratiques de cet ouvrage. Ce
chapitre nous perme t aussi d'aborder les bases du fonctionnement du démon et du
client Docker.

l:J
Le deuxième chapitre est consacré spécifiquement à deux exemples significatifs
0
c ~
.
., d'installation et de configuration d'hôtes Docker. Nous y abordons aussi des questions
::J
0 "O
c::; relatives à la configuration du stockage Docker pour les OS de type Fedora.
\.0
.-t
0
.,.,
~
Le dernier chapitre aborde la création et le cycle de vie des conteneurs au travers
N
·~ d'un exemple pratique. À ce titre, nous verrons pour la première fois quelques exemples
@ ·c
B
.......
..c:
::;
CO
de commandes Docker.
Ol c
ï:::: 0
>- c
o.. c
u
0 ·3
<.)
::;
"O
0
.....
c.
~
~
::;
rS
1
"O
0
c
8
(Ç)
"'O
0
c:
:::i
0
\.0
r-1
0
N
@
......,
..c:
en
·;::
>-
0..
0
u
3
Prise en main

Installer et configurer Docker


L'objectif de ce chapitre est d'installer Docker sur votre ordinateur et de démarrer
votre premier conteneur. Sous Microsoft Windows (abrégé par la suite en Windows)
ou Mac OS X, nous verrons comment, au moyen d'une machine virtuelle Linux,
nous pouvons jouer avec Docker.
À l'issue de ce chapitre vous aurez un système prêt pour la suite des exercices et cas
pratiques présentés dans cet ouvrage et vous aurez compris comment interagir avec
le démon Docker.

l:J
0 3.1 INSTALLATION DE DOCKER
c
::J
~
,.,
"O
0 c::;
\.0 L'installation de Docker est en général simple et rapide à effectuer sur une distribution
.-t
0
.,.,
~

N Linux. On peut bien sûr aussi l'utiliser à travers un environnement virtualisé sous
'~
@ ·c
B
Windows et Mac OS X, Prochainement, grâce aux implémentations natives en
....... ::;
..c: CO préparation (s'appuyant sur une VM xhyve sous Mac OS X et Hyper~V sous Windows),
Ol c
0
ï::::
>- c il sera aussi possible d'installer Docker directement sous Windows ou Mac OS X.
o.. c
u
0 ·3
<.)
::;
"O
0
.....
~
c. 3.1 .1 Docker Toolbox : la solution rapide pour Windows et Mac OS X
~
::;
rS Le plus simple pour démarrer rapidement et efficacement Docker sous Windows ou
1
"O
0
Mac OS X est d'utiliser Docker ToolBox. C e dernier est un programme d'installation
c
8 élaboré par Docker lnc., qui contient tous les logiciels nécessaires pour l'utilisation de
(Ç) Docker sur un environnement autre que Linux :
El-------------------------- Chapitre 3. Prise en main

• Oracle VirtualBox, logiciel de virtualisatio n open source 1 ;


• Docker Machine, qui permet de créer un hôte Docker (nous l'aborderons en
détail dans un prochain chapitre) ;
• Docker Engine, le démon et le client Docker ;
• Docker Kitematic, une interface graphique pour Docker ;
• Docker Compose, outil simplifiant l'interconnexion de conteneurs Docker,
disponible uniquement sous Mac OS X.

Docker ToolBox utilise Docker Machine pour créer une machine virtuelle (VM)
Linux minimale tournant sous Windows ou Mac OS X, grâce à VirtualBox. Cette
VM fait tourner le démon Docker qui peut ensuite être contrôlé depuis votre système
d 'explo itatio n de différentes façons :
• via Kitematic ;
• via le client Docker ;
• en direct grâce à des requêtes HTTP (n'oublions pas que le démon Docker
expose son API en REST2 ).

Pour pouvoir installer Docker Toolbox, votre machine doit disposer de Windows 7 ou
supérieur, ou Mac OS X 10.8 ou supérieur.

Le processus d'installation est relativement simple :


• allez sur la page de Docker ToolBox3 et téléchargez l'installeur correspondant à
votre système d'exploitation ;
• lancez l'installeur en double-cliquant dessus.

Setup - Docker Toolbox


1 i1J
Welcome to the Docker Toolbox
Setup Wîzard
lHs wlÎ'151a10odœrTocb>xvenion i.a.o~c l on Y<U
computer,
l:J
0 lt 1S recoomended that yoo dos<! al other aiiplications beftlfe
c contninQ.
:i
0 Click Next ID controue, or Ca>cel ID exrt Se114>.
\.0
.-t
0
N
@
.......
..c
en
'i:
>-
0.
0 ["N!"xt > 1 Cancel
u

Figure 3. 1 - Installation de Docker Toolbox sous Windows

1. Remplacé prochainement par xhyve sous Mac OS X et Hyper-V sous Windows.


2. h ttps://[Link]/wiki/Representation al_State_Transfer
3. [Link]
3.1 Installation de Docker -------------------------8
U ne fois l'installation terminée, lancez le Docker CU (sous Windows) ou le Docker
Quickstart Terminal (sous Mac OS X) , puis :
• ouvrez un terminal ;
• créez une machine v irtuelle, qui sera nommée default si elle n'existe pas, e t
démarrez-la. C'est une VM légère (environ 24 Mo ) qui tourne uniquement en
RAM;
• faites po inter le client Docker vers le démon Docker tournant sur la machine
virtuelle et sécurisez-le avec des certificats TLS.

Bien comprendre la différence avec une installation native sous Linux


Lors d'une installation de Docker sous Linux, tous les composants Docker (client,
démon, conteneur) tournent directement sur votre localhost. Les conteneurs sont donc
directement atteignables via un adressage local, par exemple localhost:8000.
Dans le cas de Windows ou Mac OS X, vos conteneurs tournent à l'intérieur d'une
VM Linux. Il faut donc utiliser l'adresse IP de la VM pour les atteindre. L'adresse IP
s'obtient facilement avec la commande :
$ docker-mac hine ip defau l t
192 . 168 . 99 . 100
Il suffit ensuite d'utiliser cette adresse au lieu de localhost : [Link]:8000

L'utilisation de Docker Toolbox, bien que pratique, a néanmo ins ses limites dès
que l'on commence à utiliser les data volumes car la machine virtuelle et la machine
h ôte n e p;:irn:igent p;:is le même système de fi chiers. H eureusement, il existe une
autre méthode, utilisant les capacités de partage de fichiers entre hôte et invité de
VirtualBox (nommée shared folders), qui permet de s'affran chir de ces problèmes, mais
au prix de performan ces relativement médiocres.

Soyons clairs, la Docker Toolbox est essentiellement un démonstrateur, un outil de


prise en main, ou éventuellement un outil de développement monoposte. Il n'est
"'Cl
0 évidemment pas question de l'utiliser sur un serveur et encore moins en production.
c
:::i
~
,.,
"O
0 [Link];
\.0
.-t
0
~
V
3.1.2 Linux sous VirtualBox
N V
'ii
@ ·c
B L'idée est d'installer une distribution Linux, de type C entOS ou Ubuntu, sur une VM
....... :::;
..c CO
dans VirtualBox et d 'installer ensuite Docker de manière standard .
O'l c
0
ï::::: c
>-
o. c Pour simplifier cette étape, n ous vous proposons d'utiliser Vagran t 1•
u
0 ·3ù
:::;
"O
0
.... Vagrant est « un outil pour fabriquer des environnements de développement ». Il
c.
~ permet de créer une box (un package Vagrant) et de la rendre ensuite disponible
~
:::; à d'autres utilisateurs pour créer simplement une machine virtuelle VirtualBox ou
rS
1
"O
0
c
8
(Ç) 1. [Link]
Chapitre 3. Prise en main

VMWare. L'environnement est décrit via un fichier de configuration qui en spécifie


toutes les caractéristiques.

V VAGRANT """"... ..

Create and configure lightweight, reproducible.


and portable development env1ronments

OOWNLOAO GET STARTEO

Figure 3.2 - Vagrant, le configurateur de machine virtuelle

Une VM Linux CentOS


Nous avons préparé une box Vagrant, basée sur un CentOS 7 1, avec un environnement
graphique qui vous permettra de mettre en œuvre les différents exemples et cas
pratiques de ce livre.
Il vous faut pour cela :
• installer Virtua1Box2 ;
• installer Vagrant3 ;
• exécuter dans un terminal les commandes suivantes :

l:J
0
c $ vagrant i nit dunod -docker/centos7
:i
0 A 'Vagran tfi l e' has been pl aced in this di recto ry . You are now
\.0
.-t ready t o · vagrant up· your f i rs t vi rtua l env i ronment ! Pl ease read
0
N t he comments i n t he Vagrantf il e as wel l as documentation on
@ 'vagrant [Link]' for more information on using Vagrant .
.......
..c
en Vagrant va télécharger la box et ensuite créer une machine virtuelle automatique-
·c
>-
0. ment.
0
u

1. [Link] [Link]/dunod-docker/boxes/centos 7
2. [Link] (version utilisée dans ce livre 5.1.14)
3. [Link] (version utilisée dans ce livre l. 7.4)
3. 1 Installation de Docker ---------------------------8
$ vagrant up -- provider vi rtualbox
Bringing machine 'defa ult ' up wi t h 'vi rt ualbox ' prov ider .. .
==> default : Importi ng base box ' dunod -docker /centos7' .. .
==> default : Matching MAC address for NAT networking .. .
==> default : Checking i f box ' dunod -docker/centos7 ' is up
to date ...
==> defau l t : Setting t he name of the VM : VM_defau l t 1462554217727_87155
==> default : Clearing any previously set networ k interfaces ...
==> defau l t : Preparing networ k i nterfaces based on con fi gurat ion . ..
defau l t : Adapter 1: nat
==> default : Forwarding ports ...
default : 22 => 2222 (adapter 1)
==> default : Booting VM ...
==> defau l t : Wa i ting for machine to boat . This may take a few minutes ...
defau l t : SSH address : 127 .0.0. 1:2222
default : SSH username : vagrant
defau l t : SSH auth method : private key
default : Warning : Connect i on ti meout. Retry i ng .. .
default : Warning : Remote connection disc onnect. Ret rying ...
default :
default : Vagrant i nsecure key detected . Vagra nt wi l l automatica l ly replace
defaul t : th i s wi t h a newly generated keypa i r for better security .
default :
default : Inserti ng generated public key with i n guest ...
default : Removing i nsecure key fr om the guest if it 's present . . .
def aul t : Key i nserted! Di sconnecti ng and reconnecting us i ng new SSH key ...
==> def ault : Machine booted and ready !
==> def au l t : Chec ki ng f or guest additions i n VM . . .
==> def au l t : Mounti ng shared fo l ders ...
default : /vagrant => C: /Users/dunod/Document s /VM

Une fois l'image créée, ouvrez VirtualBox et sélectionnez la machine virtuelle


nouvellement créée pour en afficher l'interface graphique.

"' G Oracle VM VirtualBox - Gestionnaire de machi~


Fichier M achine Aide
l:J
0
c
::J
~
,., 0 0
"O
0 c::; ~ Général ~ PriWualiAHo<I
\.0 Ctrl+S 542tm7_87155
.-t
0
.,.,
~
Cloner... Ctrl•O
N
'~ Supprimer... Ctrl+R
@ ·c Groupe-r Ctrl+U
....... B::;
..c: CO ~ Afficher inbri~, PfiE./tfX. , Paravi"tuaisation
Ol c aa Pause
ï:::: 0
>- c @) Redémarrage
o.. c
'V Fermu

u
0 ·3
<.)
::; Oublier l'etat sauvegarde... Ctrl+J
"O
0 ~ Afficher le journal... [Link]+l
.....
c. l:!J Actualiser
~
~
ITII Afficher dans l'explorat,ur de fichittS \
::; ~ Créer un raccourci sur le bureau
rS ,._===-=' Ri! Trier
1
"O
0
c
8 Figure 3.3 - Accès à l'image Vagrant pour se connecter
(Ç)
El------------------------- Chapitre 3. Prise en main

Vous pouvez ensuite vous connecter sur cette machine virtuelle avec l'utilisateur
vagrant (mot de passe vagrant).

Figure 3.4 - Page de login Cent057 de notre VM

Mise à ;our des guest additions Virtua/Box


Par défaut, la VM ainsi créée est isolée de l'hôte sur lequel vous avez installé
VirtualBox. Il n'y a pas de possibilité de copier/coller, ni de transfert de fic hiers. La
chose peut être relativement pénible.
Heureusement, VirtualBox offre une fonctionnalité très utile, nommée guest
additions, qui facilite la communication entre l'hôte et l'invité (la machine virtuelle
que vous venez de créer).
L'image Vagrant que nous livrons est installée avec les guest additions pour la version
5.10.14 de VirtualBox. S i vous disposez d'une version plus récente de VirtualBox, il
vous faudra les mettre à jour (VirtualBox vous y incitera sans doute par des messages
répétés ou le fera même automatiquement lors de la création de la VM).
Voici comment procéder :
• arrêtez votre VM ;
• ajoutez un CDROM à votre VM (allez dans Configuration, Stockage, puis
ajouter un lecteur optique que vous laisserez vide) ;
l:J
0
c • redémarrez votre VM ;
::J
0 • demandez l'installation de la dernière version des guest additions (ceci se fait en
\.0
.-t
0
cliquant sur le menu Périphériques, puis Insérer l'image CD des Additions Invité ...
N dans l'interface de VirtualBox, comme cela est illustré à la figure 3.5 ).
@
.......
..c:
O'l
Le programme d'installation des guest additions vous demande de redémarrer votre
·;::
>- VM. Arrêtez cette dernière et lisez le paragraphe suivant avant de la lancer à
0..
0 nouveau.
u
Activation du partage de fichiers avec l'hôte
Maintenant que vous disposez de guest additions à jour, il est possible d'activer le
partage de fichiers entre l'h ôte et l'invité. C eci sera utile à plusieurs reprises pour
échanger des fichiers entre la VM et le système sur lequel vous avez installé VirtualBox.
Pour ce faire, rendez-vous dans le panneau de confi guration de votre VM (désor-
mais arrêtée) puis sélectionnez Dossiers partagés. Un lien existe déjà. Double-cliquez
sur ce lien et sélectionnez (co mme indiqué sur la figure 3.6) Montage automatique.
3.1 Installation de Docker -----------------------------8

« V60XADDITIONS_5.0.14-105127 1t contient un logictel

privu pour être land autom•ttquement. Souhaite2-vous le


ltoncer?

Figure 3.5 - Mise à jour des guest additions

' Ci) VM_default_l4625542ln27_87155 ·Paramètre>

~ G'-néral 1 Dossiers partagés

Système ~œdesdoSSM:rs ---------------~

~ Affichagf! © Modifie:r un [Link] partag~ 1 ~ l...[Link] 1tage automatiqu Acc6

~ Stockage °'"""" du dossior : C:'fjsers~y.. .unents'jjook\VM . Plein

~ Son Nomdudo~: vaçrant

l/J Réseau
El lecture ..U.
0 Montage ..,tcmatique
~ Portss~ries

1 OK 11 ..........
~
1
Dossiers partagés

~ Interface utilisateur

OK J [ "'1ntJer J [ Aide

Figure 3.6 - Auto-montage du partage de fichiers

Au démarrage de votre VM, un lien sera créé entre le répertoire dans lequel vous
avez lancé la commande vag r ant up et le chemin /media/sf_vagrant dans votre VM.
l:J
0
c
::J
~
,.,
0 "O
c::;
Attention cependant, depuis l'intérieur de la VM, le chemin /media/sf_vagrant ne
\.0 sera accessible qu'à partir de l'utilisateur root ou d'un utilisateur disposant des droits
.-t
0
.,.,
~

N
'~
sudo, ce qui est le cas de notre utilisateur vagrant .
@ ·c
....... B::;
..c: CO
Ol
0
c Maintenant que nous disposons d'une machine virtuelle Linux, il ne nous reste
ï:::: c
>- c plus qu'à installer le Docker Engine.
o..
u
0 ·3
<.)
::;
"O
0
.....
c.
Installation de Docker dans notre VM
~
~ Docker est disponible via les différents gestionnaires de packages des distributions
::;
rS Linux (aptitude pour Ubuntu/Debian, yum pour RedHat/CentOS, dnf pour Fedora)
1
"O
0
c Pour obtenir la dernière version de Docker, il est généralement conseillé d'utiliser
8 le dépôt de packages proposé par Docker.
(Ç)
El------------------------- Chapitre 3. Prise en main

Vous souhaitez une installation particulière de Docker ou tout simplement plus


d'information ? N'hésitez pas à consulter la documentation d'installation fournie
par Docker:
[Link]

La distribution Linux sur laquelle vous voulez installer Docker do it remplir les
prérequis suivants pour être prise en charge :
• une architecture 64 bits, Docker n'étant pas supporté en 32 bits;
• un kemel Linux récent (au moins en version 3.1 0), même s'il est possible de
trouver des versions depuis la version 2.6 sur lesquelles Docker fonctionne.

C'est évidemment le cas de notre VM CentOS 7.


L'installatio n de Docker se fait simplement via le gestionnaire de package yum :
• connectez,vous sur votre machine avec un user qui dispose des droits sudo ou
directement avec root. Dans n otre VM, l'utilisateur vagrant disposant des droits
sudo, il suffit donc de saisir la commande suivante pour disposer des droits root :

1 $ sudo su
• rajoutez le dépôt docker pour yum (cela permet d'obtenir la dernière version de
docker, étant donné que le dépôt central CentOS met du temps à être mis à
jour) :

$ tee /etc/yum . repos .d/docker . repo <<- 'EOF'


[dockerrepo]
name=Docker Repository
baseu rl=https : //yum .dockerproject .org/repo/main/centos/7/
enabled=l
"'Cl
gpgch eck=l
0
c
gpgkey=https : //yum .doc kerproject .org/gpg
:::i EO F
0
\.0
.-t • installez le package Docker :
0
N
@
.......
..c
O'l
1 $ yum i nstal l docker -eng i ne -1. 11. 2
'i:
>-
0.
0
u Si vous omettez le numéro de version, la version la plus récente de Docker sera
installée, mais il est possible que certains exemples ne fonctionnent plus. Nous
ind iquerons sur le site du livre pour chaque version ultérieure de Docker les
différences éventuelles dont il faudra tenir compte.

Il ne reste plus qu'à démarrer le démon Docker :


3.1 Installation de Docker -------------------------[!!]
1 $ sys t emct l st art doc ker 1

Pour faire en sorte que Docker démarre automatiquement au démarrage de la VM,


il suffit de lancer la commande suivante :

1 $ systemct l enab l e docker

Vous pouvez maintenant vérifier que tout fon ctionne correctement grâce au
conteneur de test hello,wo rld :

$ docker ru n he l l o-world
Unabl e to find ima ge ' hello -world : l atest ' l oca ll y
l at es t : Pull ing from library/ hel lo -wor l d b90l d36b6f2f :
Pu l l compl et e Oa6 ba66e537a:
Pu 11 comp l et e
Diges t : sha256 :8be990ef2aeb16dbcb92 71 ddfe2610fa6658d l 3f6df b8bc72074cc l ca36966a 7
St atus : Downl oaded newer i mage for hel lo -wor l d: latest

Hel l o from Docker. Thi s message shows t hat you r i ns t al l ati on appears t o be
working correctl y.

Finaleme nt, pour éviter de devoir préfixer toutes les commandes Docker par un
sudo , il est possible de créer un groupe docker et d'y rajouter votre utilisateur (dans
notre cas, vagrant) :

1 $ usermod -ac docker vagra nt


Tous les utilisateurs du groupe docker bénéficient du droit de se con necter au
démon Docker tournant sur la machine.

Attention, le fait d'appartenir au groupe docker est hautement sensible. Docker


dispose des droits root sur l'hôte. Explo ité malicieusement, le droit de lancer des
"'Cl
0 conteneurs Docker peut faire de très gros dégâts.
c
:::i
0
\.0
.-t Un redémarrage de la machine v irtuelle est nécessaire pour que la modification
0
N soit prise en compte (ou du mo ins un logout de l'utilisateur couran t ).
@
.......
..c Installation automatisée
O'l
'i:
>-
0. Docker propose aussi un script pour l'installation. Ce script détecte votre distribution
0
u Linux et réalise les opérations nécessaires à l'installation de la dernière version de
Docker :
cur l -sSL https : //get .docker . com/ J sh
Il ne reste ensuite plus qu'à démarrer le service Docker comme cela est expliqué
ci-dessus.

1. CentOS 7 ut ilise maintenant systemd comme système d'initialisation.


[Link] pour en savoir plus.
Chapitre 3. Prise en main

3.2 VOTRE PREMIER CONTENEUR


Maintenant que Docker est installé et fonctionnel, il est temps de démarrer nos
premiers conteneurs.
Il existe plusieurs façons d'interagir avec le démon Docker :
• via Kinematic (uniquement sous Windows et Mac OS X) ;
• via le client Docker, le cas le plus commun, que nous privilégierons dans la suite
de cet ouvrage ;
• directement avec des appels HTIP en utilisant l'API Docker Remote.

3.2.1 Kitematic
Kitematic est un logiciel fourni avec Docker ToolBox (donc disponible uniquement
sous Windows et Mac OS X) qui permet de gérer les conteneurs d'un démon Docker
local. Il permet d'appréhender Docker visuellement sans utiliser la ligne de commande.

Pour utiliser Kitematic, vous devez avoir un compte sur le Docker Hub 1 . Il n'y a pas
à proprement parler de raison technique à cette obligation. Il s'agit pour la société
Docker lnc. de promouvoir son Hub qui joue un rôle essentiel dans lécosystème
Docker.

• •• @-·
Containers AU Reoommencled My Repos

-
Recommended

h8'1o--world·nginx
A lghl·wtlQhl nQIRlt oontliMt
tt'll~•ths,....._of
ghost

_
..
Ghoet . . . fJM and open 80WCI
...
blogg~ [Link] .mtten ln

000 Ill '"' 225 oool ~ 1

""'"
redîs
..
rethinkdb
-~
minecraft
Red!• .. .,, open IMJUIÇ9 . , . . Reit*lkOBlaen~. The Mlneçrsft [Link] M'Wlf"
va.. ltor9 ttm blction• - • document cMtmu. tlwl ""*- il lllowstwoormoM~to
911SYtO bulkl and ICate ruàlml•.• play Minecratt togethef'
l:J
L J ~ L
-
0 c;:;i 1487 000 CREATE \) 151

-
34 000 CHA1T 1
c
:i
0 s oir e tasticsearch -postgres !
\.0 Sc*' .. the [Link]. blal;lng-1-t,
.-t open IOU'Ce entetptlu MIM:l't
pladonn blAt on Apache,_.
0
N
@
~ 65 000 CAERt.J
.......
..c
en
'i:
>-
0.
Il =
.
tu-upstart
. .......
Upàmt ls an -"'..baed

0 Figure 3.7 - Kitematic: Docker en mode graphique


u

Pour prendre en main Kitematic, cliquez sur le bouton Create de l'image hello~
world~nginx. Kitematic va alors télécharger l'image correspondante depuis le Docker
Hub, puis créer et démarrer un conteneur à partir de cette image.

l. [Link]
3.2 Votre premier conteneur --------------------------[!!]
• e• @ tu-tot v heHo-world-nginx ~

Containers
Home Setttngs

WEBPREV1EW 1~ I@
® en©
Voitàl Your nginx container i:s runningt

VOLUMES

/webslte_files

Figure 3.8 - Démarrage d'un conteneur Nginx dans Kitematic

Kitematic liste tous les conteneurs existants arrêtés ou actifs (ce qui est indiqué
par la marque « A » sur la figure 3.8). O n voit dans notre cas le conteneur que nous
venons de créer.

Kitematic assigne comme nom par défaut le nom de l'image. S'il y en a plusieurs,
elles sont suffixées par _ 1, _2 ...

Kitematic permet de visualiser directement les logs du conteneur (marque « B »


sur la figure 3.8). Nous verrons qu'il s'agit là d'une fonction standard d'un conteneur
Docker.
Si le conteneur expose un port web, tel que 80 ou 8000 (nous verrons plus tard ce
l:J
0 que cela signifie), Kitematic le rend disponible directement sur l'hôte. N'oubliez pas
c
::J
~
,., que le conteneur s'exécute dans une machine virtuelle Linux gérée par VirtualBox. En
"O
0 c::;
\.0 cliquant sur le lien web preview (marque« C »sur la figure 3.8), un navigateur s'ouvre
.-t
0
.,.,
~
et vous pouvez voir la page d'accueil de Nginx .
N
'~
@ ·c
....... B::;
..c: CO
Ol c
ï:::: 0
>- c
o.. c
u
0 ·3
<.)
::;
"O
0
.....
c.
~
Voilà! Your nglnx [Link] le runnlngf
~
::;
rS
1
"O
0
c Figure 3.9 - Page d'accueil de Nginx du conteneur hello-world-nginx
8
(Ç)
El------------------------- Chapitre 3. Prise en main

N ous en avons terminé avec cette introduction rapide à Kitematic et vous trouverez
des informations complémen taires dans le guide d'utilisateur de Docker 1•
Nous allons maintenant étudier l'utilisation du client Docker en ligne de com-
mande, qui reste la méthode principale d'interaction avec le démon Docker, du moins
dans un cadre p rofessionnel.

3.2.2 Le client Docker

Vous avez déjà utilisé le client Docker, peut-être sans le savoir, durant la phase
d 'installation, lorsque vous avez saisi la commande docker r un he l l o-wor l d.
Avant d'aller plus lo in dans l'explication de son utilisation , il est temps de regarder
un pe u plus en détail comment le démon Docker interagit avec le reste du monde.
Le démon Docker écoute sur un socket U nix 2 à l'adresse /var/run/[Link]. Le
clien t Docker utilise HTTP pour envoyer des commandes à ce socket qui sont ensuite
transmises au démon , aussi v ia HTTP.

localhost

HTTP HTTP

Client docker Démon d ocker

Figure 3.10 - Communication client/serveur Docker

Il est possible de matérialiser cette communication simplement en sniffan t le trafic


HTTP entre le client et le démon. Pour cela, nous allons utiliser Socat 3 .

l:J Socat est une boîte à outils qui permet de spécifier deux flux de données (des fichiers,
0
c
:i
des connexions .. .> et de transférer les données de l'un vers l'autre.
0
\.0
.-t La figure ci-contre permet de comprendre ce que nous allons faire. Nous insérons
0
N un socket proxy, qui va d'une part transférer les commandes du client au démon Docke r,
@ et d 'autre part, les afficher dans notre fenêtre de terminal.
.......
..c
en Installez socat à l'aide du gestionnaire de paquet yum:
'i:
>-
0.
0
u 1 $ sudo yum in sta ll -y socat

1. [Link] ic/userguide/
2. h ttps://fr. wikiped [Link]/wiki/Berkeley_sockets#Socket_un ix
3. h ttp://[Link]-unreach .org/socat/
3.2 Votre premier conteneur ------------------------8
localhost

Client docker

HTTP
/tmp/[Link] 1 /var/run/[Link] ~
HTTP

S_ GET 'V1 21

Démon docker

Figure 3.1 1 - Interception de communication avec socat

Lancez ensuite simplement la commande suivante:

$ socat -v UNIX-LISTEN : / t mp/socatproxy .sock,fork,re useaddr


1 UNIX-CO NNECT: /var/r un /docker . sock &
Et maintenant, utilisons le client Docker pour lister tous les conteneurs de notre
système:

$ docker -H unix : ///tmp/socatproxy . soc k ps -a


> 2016/01/10 10 :41 :53 .862867 l ength=114 from=O to=113
GET /vl . 21/conta i ne rs/ json?al l =l HTTP/ 1.1 \r
Host : /tm p/socatproxy . sock\r
User -Agent : Doc ker -Cl ient/ 1. 9. 1 (l i nux) \r
\r
l:J < 2016/01/10 10 :41 :53.864414 l engt h=477 f rom=O to=476
0
c ~
,., HTTP/1 .1 200 OK\r
::J
0 "O Content -Type : appl ication/json\r
c::; Se rver : Docker/1 . 9. 1 (lin ux)\r
\.0
.-t
0
.,.,
~
Date : Sun, 10 Jan 2016 09 :41 :53 GMT\r
N
'~ Content - Length : 338\r
@ ·c
B \r
....... ::;
..c: CO [ {"Id":"885d2f6583979e20b5b8a8f285ba0a459fda4dacf59a l c42790e53cd57c18f 7b "," Names ": [ "/ evi l_·
Ol c
ï:::: 0
c wor l d"," Ima geID":" Oa6ba66e537a53a5ea94f7c6a99c534c6adb12e3ed09326d4bf3b38f7c3ba4e7 " ,"Commat
>- c (0) 4 mi nutes ago "," HostConf ig" : {"NetworkMode ":" de f aul t "} }]
o..
u
0 ·3
<.) CONTAINER ID IMAGE COMMAND CREATED -- Répo
::;
"O
0
5d2f658397 hel l o-worl d "/ hel lo " 4 min ut es ago
.....
~
c. STATUS PORTS NAMES
~ Ex i t ed (0) 4 mi nut es ago evi l _fermat
::;
rS
1
"O
0
c
8
(Ç)
El------------------------- Chapitre 3. Prise en main

Regardons plus en détail :


Paramètres Description
docker -H unix:///tmp/[Link] ps -a Commande pour laquelle nous voulons voir
la requête et la réponse HTIP. Notez le
paramètre - H qui permet de préciser où
envoyer la requête, dans notre cas le socket
proxy socat.
GET /vl .21 /containers/json?all=l HTIP/1 .1 ... La première partie du log socat. Notre
commande est convertie en requête HTIP
par le client Docker (dans notre cas un appel
GET pour obtenir la liste des conteneurs).
HTIP/1.1 200 OK ... La seconde partie du log socat. Il s'agit de
[{" ld":"885d2f6583979e20b5b8a8f285ba0a459 la réponse HTIP retournée par le démon
fda4dacf59a1c42790e53cd57c18f7b", ... au format JSON.
CONTAINER ID IMAGE COMMAND CREATED La réponse interprétée en mode texte par
STATUS PORTS NAMES le client Docker.
885d2f658397 hello-world "/hello" 4 minutes ago Sans le socket socat, seul ce texte aurait été
Exited (Q} 4 minutes ago evil_fermat affiché.
Si le client Docker ne fait que des appels HTTP, pouvons~nous nous substituer à
lui et appeler le démon directement ?
Bien sûr l Et c'est exactement ce que nous allons faire dans le prochain chapitre.

Le groupe docker
Souvenez-vous, lors de l'installation de Docker, nous avions rajouté notre utilisateur
vogront dans un groupe docker.
Le client et le démon Docker ont besoin de tourner avec des droits de type root
(cela est nécessaire pour pouvoir, par exemple, monter des volumes). Si un groupe
docker existe, Docker va donner les permissions sur le socket /var/run/[Link] à
ce groupe. Tout utilisateur en faisant partie pourra donc ensuite utiliser Docker sans la
commande sudo.

"'Cl
0
3.2.3 API Docker Remote
c
:::i
0 Le démon Docker expose l'intégralité de ses méthodes à travers l'API Docker Remote 1 •
\.0
.-t C'est une API de type REST qu'il est possible d'appeler avec des outils tels que curl
0
N ou wget, à partir du moment où la configuration le permet.
@
.......
..c
O'l Docker info avec curl
'i:
>-
0.
0 Rappelons que Docker n 'écoute que sur un socket Unix à l'adresse
u /var/run/[Link], comme nous l'avons vu précédemment. Pour pouvoir appeler
l'API directement avec un client HTTP, il faut que nous définissions un autre socket
de connexion de type TCP.
Pour cela, arrêtons le démo n :

1. h ttps://[Link] m/engine/ reference/api/docker_remote_api/


3.2 Votre premier conteneur ------------------------8
1 $ sudo systemct l stop docker

Et redémarrons-le à la main (c'est-à-dire sans utiliser systemd) en précisant l'IP et


le port sur lequel celui-ci doit désormais écouter :

$ sudo docker daemon -H t cp : //0 .0.0.0: 2375 &


[l ] 15360
[vag rant@l ocalhos t docker .service .ci] $ WARN[OOOOJ /!\ DON'T BIND ON ANY IP
ADDR ESS WITHOUT setti ng -t lsverify IF YOU DO N'T KNOW WHAT YOU' RE DO ING / ! \
INFO[OOOO] API l i st en on [ ::]: 2375
WARN[OOOOJ Usage of l oopback dev i ces i s strongl y discouraged for production
use . Please use · --storage -opt [Link] i npooldev' or use 'man doc ker' to refer t o
dm .t hi npooldev section.
INFO[OOOOJ [graphdriver] using prior storage driver "devicemapper "
INFO[OOOOJ Fi rewalld runn i ng : fa lse
INFO[OOOO] De f au lt br idge (doc kerO) is ass i gned wi t h an IP address
172 . 17 .0. 1/16 . Daemon opt i on -- bi p ca n be used to set a preferred IP address
INFO[OOOO] Load i ng containers : st art.

IN FO[OOOOJ Load i ng containers : done .


INFO[OOOOJ Daemon ha s comp l eted init i al i zation
INFO[OOOO] Docker daemon commit=a34a l d5 execdriver=na ti ve -0.2
graphdr i ver=devicemapper version=l .9. 1

Regardons maintenant en détail le résultat :


Paramètre Description
sudo docker daemon -H tcp://[Link]:2375 & Démarre le démon Docker et le lie à toutes les
adresses IP de notre machine hôte <[Link]> en
utilisant le port 2375.
WARN[QOOOJ /!\ DONT BIND ON ANY IP Docker nous prévient que cette connexion n'est
ADDRESS WITHOUT setting -tlsverify IF VOU pas sécurisée. N'importe qui peut donc appeler
DONT KNOW WHAT YOU'RE DOING /!\ Docker depuis une machine distante. Dans le
cas d'un déploiement réel, il serait nécessaire
l:J de sécuriser laccès à cette interface à laide de
0 SSL et d'un moyen d'authentification.
c
::J
~
,.,
0 "O WARN[QOOOJ Usage of loopback devices is Il s'agit d'un message d'avertissement de
c::;
\.0 strongly discouraged for production use. Please Docker qui nous signale que le démon est
.-t
0
.,.,
~
use '-storage-opt [Link]' or use 'man notamment lié à l'interface réseau loopback du
N
'~ docker' to refer to [Link] section. serveur et qu'il s'agit, en général, d'une très
@ ·c
....... B::;
mauvaise idée pour un serveur de production.
..c: CO
Nous nous en accommoderons à ce stade de
Ol c
0
ï:::: c l'ouvrage.
>- c
o.. INFO[QOOOJ [graphdriverl using prior storage Nous utilisons le device storage devicemapper.
u
0 ·3
<.)
::;
"O
driver "devicemapper" Il s'agit là, comme nous l'avons expliqué dans
0
.....
c.
le chapitre 1, du gestionnaire de persistance
~ utilisé par Docker (dans le cas de CentOS>.
~
::;
rS Nous pouvons vérifier maintenant que Docker n'est plus accessible sur le socket
"O
1
Unix /var/run/[Link] (qui n'est d'ailleurs pas créé) :
0
c
8
(Ç)
El------------------------- Chapitre 3. Prise en main

$ gre p -f /var/run/doc ker .soc k


grep : /var/run/docke r.s oc k: Auc un f ich ier ou dossier de ce type
$ docker ps
Ca nn at connect to the Docker daemon . Is the docker daemon running on t hi s
host ?

Pour se connecter à notre démon, il faut maintenant passer l'adresse que nous
venons de définir avec le paramètre - H :

$ docker -H [Link]:2375 i nfo


INF0 [4403] GET /vl .21/ i nfo
Containers : 1
Images : 2 Server
Version : 1. 9.l
Storage Driver : devicemapper
Pool Name : docker -253 :0-69821582 -pool
Pool Bloc ksize : 65 . 54 kB
Base Device Size : 107 .4 GB

1 2 7 .0.0.1 vs o.o.o.o
Nous sommes tous plus ou moins familiers avec l'IP [Link] : c'est l'adresse IP de
loopback, aussi connue sous le nom de localhost. Cette adresse est associée à une
interface réseau virtuelle qui ne permet de communiquer qu'avec l'hôte lui-même (elle
n'a donc de sens que pour les processus tournant sur cet hôte et n'est pas accessible
depuis l'extérieur).
L'adresse [Link] est une autre adresse standard. Elle signifie« toutes les adresses 1Pv4
de la machine » (incluant donc 1 2 [Link], d'où le message d'alerte faisant référence
au loopback qui s'est affiché lorsque nous avons démarré le démon). Le démon ainsi
associé à l'adresse 0 .0.0.0 est donc accessible depuis n'importe quelle adresse <ce qui
n'est généralement pas le cas dans un environnement sécurisé de production).

"'Cl Si nous ne voulons pas avoir à spécifier à chaque appel le paramètre - H, il suffit
0
c
:::i
de définir la variable d'environnement DOCKER_HOST et ainsi le client Docker
0 l'utilisera automatiquement :
\.0
.-t
0
N
@ 1 $ export DOCKER_HOST="tcp: //0 .0.0.0:2375 "
.......
..c
O'l
'i:
Utilisons maintenant curl pour appeler directement le démon Docker. Pour rendre
>-
0. la réponse ]SON plus lisible, nous allons employer jq 1 , et il faut donc installer le
0
u paquet nécessaire :

1 sudo yum i nstall -y jq

l. jq est un processeur de JSON en lign e de commande. Plus d'info à [Link]


3.2 Votre premier conteneur ------------------------a
Maintenant que l'utilitaire est installé, lançons la commande docker i nfo à l'aide
de curl:

$ curl http : // l ocalhost :2375/ i nfo ljq


% Total % Received % Xferd Average Speed Ti me Time Ti me Current
Dload Upload Total Spent Left Speed 0 0 0 0 0 0
0 0 -- :--:-- -- :--:-- -- :--: -- OINFO [l260 ] GET /info
100 1859 100 1859 0 0 11776 0 --:--:-- -- : -- : -- --·-- ·- - 11840
{ "IO ": "MO LV: VVHJ :GMI P: VRXK :OOVB : 7FQS : 27NJ :YRR3 : 5B4V :WOAV :U6IX : KSF N",
"Cont ainers ": 1, "I mages ": 2, "Driver ": "devicemapper ", "Dri verStatus ":
[ [ "Poo l Name ", "docker -253 :0-69821582 -pool " J, ...

Nous vous conseillons de redémarrer votre VM si vous avez réalisé l'exercice


précédent pour n e pas créer de conflit avec les exercices qui suivent. Sinon, vous
pouvez aussi appliquer la commande unix ki 11 sur un processus créé par sudo
docke r daemon -H tcp : // 0. 0. 0. 0: 2375 &.

Modifier la configuration du démon Docker


Au prochain redémarrage de votre machine , Docker va reprendre son ancienne
configuration. Il n'écoutera don c plus sur le socket TCP et le port que nous avons défini.
Pour rendre ce paramétrage permanent, il est possible de modifier la configuration du
démon au moyen du fichier /etc/docker/[Link].
C e fichier de configuration permet de modifier les paramètres de démarrage du
démon san s être contraint de le lancer ma nuellement. Nous pouvons, par exemple,
créer un fichier /etc/docker/[Link] avec pour contenu :

$ sudo tee /etc/docker /daemon.j son <<- ' EOF '


{
"hasts " : [ "fd : // ","tcp : //0 . 0.0. 0:2375"]
}
l:J EOF
0
c
::J
~
,.,
0 "O
c::; Notre démon écoutera maintenant sur deux sockets :
\.0
.-t
0
.,.,
~
• le socket standard (/var/run/[Link]) ;
N
'~
@ ·c • le socket tep que nous avons configuré ci-dessus.
....... B::;
..c: CO
Ol c Ma lheureusement, sous CentOS (ou plus exactement sous un système utilisant
ï:::: 0
>- c
o.. c systemd), une petite manipulation additionnelle est nécessaire. À l'heure où nous
u
0 ·3
<.)
::; écrivon s ces lign es, sous CentOS, la configuration de démarrage de Docker (présente
"O
0
.....
c. dans le fichier /usr/lib/systemd/system/[Link]) s'appuie sur l'instruction:
~
~
::;
rS
1
1 ExecStart=/usr/bi n/docker daemon -H fd : //
"O
0
c
8 Or il n'est pas possible de configurer le même paramètre à la fois via le fichier de
(Ç) configuration [Link] et par l'intermédiaire d'un flag ( -H dans ce cas). Il est donc
El-------------------------- Chapitre 3. Prise en main

nécessaire de modifier l'instruction de démarrage par défaut du démon Docker via les
instructions suivantes:

$ sudo mkdir /et c/sys t emd/system/doc ker. service .d


$ sudo t ee /etc/syst emd/system/docker .serv i ce .d/start up .conf <<- 'EDF'
[Service]
Exec St art=
ExecStart=/ usr/bin/doc ker daemon
EDF

Le lecteur curieux pourra se reporter à la documentation Docker 1 relative à systemd


qui aborde cette problématique en détail.

On recharge la configuration du service Docker et on démarre le démon :

$ sudo systemct l daemon -re l oad


1 $ sudo syst emct l st art doc ker

Nous disposons maintenant d'une d'installation du Docker Engine totalement


fonctionnelle et prête à être expérimentée.

En résumé
Dans ce chapitre nous avons appris à installer Docker sur une machine de bureau.
Nous avons appris à interagir avec le démon Docker au travers de divers outils pour
lancer des commandes et créer des con teneurs. Dans notre prochain chapitre, nous
allons nous intéresser à l'installation de Docker sur un hôte serveur de manière plus
professionnelle.

"'Cl
0
c
:::i
0
\.0
.-t
0
N
@
.......
..c
O'l
'i:
>-
0.
0
u

1. h ttps://[Link]/engine/ad mi n/systemd
4
Docker sur un serveur

Installer Docker sur un hôte


Avant d'entamer la mise en pratique de Docker, nous avons trouvé utile d'aborder la
question de la création des hôtes Docker. Dans le chapitre 3, nous avons vu comment
installer Docker sur une machine de bureau (afin d'apprendre et d'expérimenter),
et l'objectif de ce chapitre est de voir comment installer Docker sur une machine
de type serveur. Nous utiliserons pour ce faire différents types d'outils et modes
d'installation.

L'installation de Docker peut se faire de plusieurs manières :


l:J
0
• utiliser Docker Machine proposé par Docker Inc. que nous avons déjà expé-
c
::J
~
,., rimenté (sans vraiment le savoir) dans le précédent chapitre avec Docker
"O
0 c::;
\.0
ToolBox;
.-t
0
.,.,
~
• utiliser des distributions Linux spécialisées (déjà évoquées dans le ch apitre 1)
N
'~
@ ·c qui permettent de créer simplement des images Docker « ready » ;
....... B::;
..c: CO • finalement, on peut s'appuyer sur des offres cloud de type CaaS (présentées dans
Ol c
ï:::: 0
>- c le ch apitre 2) qui rendent transparentes la configuration et même la nature
o.. c
0 ·3 physique de l'hôte.
u <.)
::;
"O
0
.....
~
c. Dans ce chapitre, nous allons aborder deux exemples d 'installation :
~
::;
• Docker Machine, qui permet de construire des hôtes Docker sur un très large
rS
"O
1 panel d'en vironneme nts et de configurations ;
0
c • A tomic H ost , une distribution spécialisée (au même titre que CoreOS ou
8 Boot2Docker) élaborée par le projet Fedora.
(Ç)
El----------------------- Chapitre 4. Docker sur un se1Veur

4.1 DOCKER MACHINE


Docker Machine permet d'installer et de configurer le Docker Engine sur des machines
virtuelles (existantes ou non) aussi bien sur votre ordinateur (Windows ou Mac ) que
sur des fournisseurs cloud, comme Amazon AWS ou Microsoft Azure. Vous pourrez
ensuite piloter ces h ôtes de manière très simple, directement avec la commande
docker-machine.

4.1.1 Installation de Docker Machine

Avant tout, Docker Machine requiert que le Docker Engine soit installé sur votre ordi-
nateur. Docker Machine est l'un des composants de la Docker Toolbox. Vous pouvez
vous reporter au ch apitre précédent pour plus de déta ils con cernant l'installation de
cette boîte à outils.
Il est aussi possible de télécharger le bina ire de Docker Machine manuellement et
de l'extraire en adaptant les permissions pour le rendre exécutable :

# Sous Mac OS X ou Li nux - nécessite des droits root


$ curl -L htt ps : //g i t hub . com/docker/machine/re l eases/downloa d/vü .6.0/docker-
mach i ne- ' uname -s'- ' uname -m' > /usr/local/bi n/doc ker-mach ine &&
\
chmod +x / usr/ l oca l / bi n/doc ker-machine

#Sous Windows (nécess i te gi t bas h1 )


if [[ ! -d "$HOM E/b i n" ]]; then mkdir -p "$ HOME/bin "; f i && \
curl -L https : //gi t hub .com/docker/mac hi ne/re l eases/download/v0 .6.0/docker -
machine -Windows -x86_64 .exe > "$HOME/b i n/docker -machine .exe " &&
\
chmod +x "$HOME/bin/docker -machine .exe "

Nous avons installé ici la dernière version disponible de Docker Machine <0.6.Q)
au moment de l'écriture de ce livre. Vérifiez et utilisez toujours la dernière version
"'Cl
0 disponible en mettant à jour l'URL d'installation dans les commandes ci-dessus.
c
:::i
0
\.0
Vérifion s fina lement que l'installation s'est bien déroulée en affichant la version
.-t
0 de Docker Machine :
N
@
.......
..c $ docker -machi ne version
O'l
ï:::::
>-
1 docker -mach i ne version 0.6.0, build e27fb87
0.
0
u Explorons maintenant les capacités de Docker Machine pour bien comprendre son
fonctionnement.

l. [Link] [Link]. io/


4.1 Docker Machine ---------------------------8
Script Bash completion de Docker machine
Les commandes de Docker Machine requièrent en général de nombreux paramètres
et sont globalement longues à saisir. Pour simplifier leur utilisation, il existe un ensemble
de scripts bash qui permettent, à la façon d'une ligne de commande, de compléter les
commandes Docker Machine. Leur installation est simple et si vous avez une utilisation
intensive, nous ne pouvons que vous encourager à les utiliser1 .

4.1.2 Prise en main de Docker Machine

Il faut vraiment voir Docker Machine comme un outil de pilotage distant d'hôtes avec
Docker, que ce soit en local, dans votre cloud d'entreprise ou sur un fournisseur cloud
(comme Amazon AWS ou Microsoft Azure).

Amazon EC2

Window5Azure-

vmware-
..
openstack
, ,

Figure 4 . 1 - Les différents drivers de Docker Machine

Docker Machine repose pour cela sur un mécanisme de drivers. Chaque driver est
spécifique d'un type d'installation et vous permet de créer une machine Docker pour
un environnement spécifique.
l:J
0
c ~
,., Dans la suite de ce chapitre, nous utiliserons de manière interchangeable le terme
:i
0 "1:l
c;:;
machine et hôte, une machine n'étant finalement qu'un hôte sur lequel tourne un
\.0 démon Docker.
.-t ~
0 V
N V
'&
@ ·c On peut catégoriser ces drivers de la manière suivante:
....... B
;:;
..c CO
• ceux qui permettent de créer une machine localement sur votre poste de travail.
en c
0
ï::::: c
>- c
Dans ce cas, Docker Machine interagit directement avec le programme de
o.
u
0 ·3
<.)
virtualisation, tel qu'Oracle VirtualBox, M icrosoft Hyper-V ou VMware Fusion ;
;:;
"1:l
0
..... • ceux qui gèrent des machines sur une infrastructure privée d'entreprise :
c.
~ OpenStack ou VMware vSphere par exemple;
2:l;:;
rS • et ceux qui utilisent des infrastructures cloud, telles que Digital Ocean, G oogle
1
"1:l
Co mpute Engine ou Microsoft Azure.
0
c
8
(Ç) 1. h ttps://gi thu [Link]/docker/mach ine/tree/master/con trib/completion/bash
El----------------------- Chapitre 4. Docker sur un se1Veur

La liste des d rivers officiellement supportés par Docker Mac hine évoluant régu-
lièrement, il est plus simple de se référer au site de Docker pour disposer de la liste
exhaustive. L'a rchitecture modulaire de Docker Machine a aussi permis à des tierces
parties de créer des drivers supplémentaires (tel KVM 1 ) dont la liste se trouve sur le
dépôt GitHub de Docker Machine2 .
Regardons maintenant plus en détail la commande doc ker- machine creat e.

4.1.3 La commande docker-machine create

Comme son nom l'indique, la commande docker -mac hi ne create permet de créer
des machines avec un Docker Engine et de configurer directement ce de rnier. Elle
nécessite pour cela au mo ins deux paramètres :
• - -dri ver : comme nous l'avons vu précédemment, c'est le nom du driver qui
sera utilisé, par exemple virtualbox ou digitalocean ;
• le nom de la machine, à donner généralement en fin de commande.

Il y a bien sûr de nombreux autres paramètres que l'on peut lister avec la commande
suivante :

1 $ doc ke r-machi ne create -help

De plus, pour obtenir de l'aide sur un driver particulier, il suffit de rajouter son
nom, par exemple, pour le driver Virtualbox :

1 $ doc ker-machi ne crea t e --dri ver vi rtual box -- help

Ces paramètres peuvent être regroupés en trois catégories :


• C eux commençant par - -eng i ne : ils permettent de configurer directement le
Docker Engine lors de la création de la machine. Par exemple, le paramètre
"'Cl engi ne -i nsecu re - regi stry configure un registre Docker privé que le Docker
0
c Engine pourra utiliser.
::i
0
\.0
• C eux commençant par - - swa rm: comme nous le verrons dans la troisième partie
.-t
0 de cet ouvrage, il est possible de créer et de configurer directement un cluster
N
@
Swarm avec Docker Machine. Par exemple, le paramètre - -swarm- di scov ery
.......
..c
configure le service de découverte du cluster Swarm (typiquement l'URL d'un
O'l
ï::::: registre Consul ou etcd).
>-
0.
0
• Ceux qui sont spécifiques à chaque driver : ils sont préfixés par le nom du driver
u (virtualbox ou amazonec2, par exemple). Nous verrons dans le chapitre suivant
comment les utiliser dans le cas d'une machine Amazon AWS.

Docker Machine utilise pour certains de ces paramètres des valeurs par défaut. Par
exemple, si vous créez une machine sur le cloud Microsoft Azure, la valeur par défaut
du paramètre azure -si ze, qui définit la taille de la machine, est Smalt.

1. [Link]
2. [Link] r/mach ine/blob/master/docs/AVAILA BLE_DRIVER_PLUGINS.md
4. 1 Docker Machine

Nous en savons maintenant assez pour créer nos premières machines. Commençons
par une machine sur le cloud d' Amazon AWS.

4.1.4 Installation de Docker avec Docker Machine sur Amazon AWS

Avant tout, il faut évidemment que vous disposiez d\m compte Amazon AWS.
S i ce n'est pas le cas, rendez~vous sur [Link] pour en créer un.
Vous disposez automatiquement de l'offre AWS Free Tier qui inclut une machine
virtuelle avec un abonnement [Link] pour une durée d'un an qui vous permettra
d'expérimenter Docker Machine.

Attention, l'offre AWS Free Tiers n'inclut pas une adresse IP statique pour la machine
virtuelle, ce qui signifie que l'adresse IP va changer et que les certificats TLS générés
par Docker Machine pour sécuriser le Docker Engine ne seront plus valables. La
solution est d'activer une Elastic IP qui permet ainsi d'obtenir une adresse IP statique,
mais il vous en coûtera un peu d'argent.

Le driver Docker Machine Amazon attend deux paramètres obligatoires pour la


création de machines virtuelles EC2 :
• un AWS Access Key ID ;
• un AWS Secret Access Key.

Pour obtenir ces deux valeurs, il faut se connecter à la console Amazon AWS.

Les prérequis
Nous allons tout d'abord créer un groupe avec des droits d'administration, puis un
utilisateur de ce groupe. Finalement, nous créerons pour cet utilisateur les clés d'accès
"'Cl
0
requises par Docker Machine.
c
:::i
0
.-. AWS v Services v
\.0
.-t
0
N
Dashboard
+•§§i#ir!i!i GroupActions •

@ Search IAM

....... Rlter
..c Details
O'l
'i: 1 Groups
0 Group Name ; u..,,.
>-
0.
0 Users 0 docker-machine O

u Rotes

Policies

ldentity Providers

Accounl Settings

Credenlial Report

Encryption Keys

Figure 4.2 - Création d'un groupe de sécurité


Chapitre 4. Docker sur un sefVeur

Commençons par créer le group doclœr-machine :


• depuis le menu principal, sélectionnez Services puis IAM (ldentity and Access
Management) ;
• dans le menu de gauche, sélectionnez Groups puis Create New Group;
• choisissez docker-machine comme nom de groupe puis rajoutez-lui la permission
AdministratorAccess;
• confirmez finalement la création du groupe .

•-. AWS v Services v

Dashboard lAM > Users > docker-machine-user

[Link] IAM ' • Summary


UaerARN: am:aws:iam::7904S2392325:use<ldocket·machlne-user
Details Hn Pasaword: No

Groupa Groups ~or thl• use~:


Path:
1 Users
Creatlon Tme: 2016-03-01 10:07 VTC+0100
Rôles

Poticles

ldenl!ty Provlders Groupa Permlnlone Security Credendal1 Acce11 Advlsor

Acoount Settings This Vlew shows aJI groops the User bekmgs to: 1 Group
Crlldenlial Report

Group

Encryption Keys W dockeMnachine Remove from Group

Figure 4.3 - Association d'un utilisateur au groupe docker-machine

Ajoutons maintenant un utilisateur :


• dans le menu de gauche, sélectionnez Users, puis Create New Users;
• dans le champ 1, saisissez docker-machine-user et confirmez ;
• vous pouvez maintenant télécharger, v ia le bouton Download credentials, un
fichier qui contient l'ID et la clé dont nous aurons besoin avec Docker Machine.
l:J
0
c Gardez-le précieusement car c'est la seule fois où vous pouvez obtenir l'AWS Secret
::J
0
\.0
Access Key ! Si vous la perdez, vous ne pourrez plus vous servir de cette clé et vous
.-t
0 devrez en créer une autre .
N
@ Maintenant que nous d isposons de notre utilisateur, ajoutons-le dans le groupe
.......
..c: docker-machine que nous avons précédemment créé et attribuons-lui un mot de passe:
O'l
ï::::
>-
0..
• dans le menu de gauche, sélectionnez Users, puis l'utilisateur docker-machine-
u
0 user;
• allez dans l'onglet Groups et rajoutez-le au groupe docker-machine.

Il ne nous reste plus qu'à définir un mot de passe pour notre utilisateur :
• allez dans l'onglet Security Credentials et cliquez sur Manage Password;
• choisissez Assign a custom password, saisissez un mot de passe deux fois et
confirmez.
4. 1 Docker Machine

Création de la machine EC2


Nous disposons maintenant de tout ce dont n ous avons beso in pour créer notre
première Docker M achine aws-machine avec le driver amazonec2.
O uvrez un terminal et saisissez la commande suivante en remplaçant les paramètres
amazonec2-access- key et amazonec2- secret-key par ceux que vous avez obtenus lors
de la création de l'utilisateur docker-machine-user:

$ docker-machi ne create --dri ver amazonec2 --amazonec2-access- key AKIXXXX


-- ama zonec2 -secret - key YYYYYY aws -machine
Running pre -create checks ...
Creating machine ...
(aws -mac hi ne) La unchi ng in sta nce ...
Wait i ng f or machine to be r unning , t his may take a few minutes ...
Detecting operating system of created i nst ance ...
Wait i ng f or SSH to be ava i l ab l e ...
Detecting the provis i oner ...
Provisioni ng with ubuntu(systemd) ...
Insta l l i ng Docker ...
Copying certs to t he loca l mach i ne direct ory ...
Copying certs to t he remot e mach i ne . ..
Setting Docker confi gura tion on the remote daemon ...
Checking connection to Doc ker ...
Docker i s up and r un ni ng !
To see how t o connect your Docker Cl ient to the Docke r Engine r un ni ng on this
virtua l machine . ru n: doc ker -machine env aws -machi ne

Via la console AWS, nous pouvons voir qu'une n ouvelle machine virtuelle a bien
été créée:
.-. AWS - Servicoa "' Thomas [Link]!ot v ~ Vrq no;)• SJPOOrt •

4
Fi %%J1 if f. f Connoct Actionl v

Q. Fllter by tags in:!~- or-'*' by keywoid 0 1to1af1

[Link]:ro .. rurnng 2fldlecic.a ... Nol1tl ... . ec.2·52-23-201-101.c:o... [Link] ~


-""""""·
1 lnstancos
Q

Spot Requests
Reserwd Instances
l:J Scheduted lnstvices
0
c
::J
~
,.,
"O [Link]:« ll-t211b01e ([Link]) P\lblic; ONS: oc:2~-[Link]-1 ..[Link] !!ll!lc:I
0 c::;
\.0 Onc;riptlon stBtUS CMclcs Monitoring Tags
.-t
0
.,.,
~
- 6..ASTIC BLOCK STORE ec2-52-23-201-101 .~1..-[Link]

N ru"""9 PublclP ~.23.201.101

'~

..
[Link])'p9 [Link]
@ ·c [Link] lp-172-31-10-7 1. .::[Link]â

....... B::;
........, SecuritJ' 91"1M4>• dcx:ks-nw::hne. Ylawn-..
..c: CO
Bastlc!PI
[Link]• NQ~~

Ol c ubuntu-wlloj-15.1G-amd&4-181'Ver-20151118. 1 {9ml-2&05at4q

ï:::: 0
c KeyPaira
.....
........
~

>- c
Networkimlr'fM:. . eltlO
o.. Source/dut.. [Link] True

u
0 ·3
<.) EBS-optimldd Felse Laincti time Mllrcf1 1, 2018 at 1Ck2721 NJ. l1TC• 1 ~thaionehOll')
::;
"O
0
.....
c.
~ Figure 4 .4 - Machine virtuelle EC2 provisionnée par Docker Machine
~
::;
rS
1 Détaillon s un peu ce qui s'est passé :
"O
0
c
8 • Docker Machine s'est connecté à l'interface d'Amazon EC2 et a lancé la
(Ç) création d'une machine v irtuelle avec le nom aws-machine ;
El----------------------- Chapitre 4. Docker sur un se1Veur

• cette machine est localisée par défaut dans la région géographique us-east-1 que
nous aurions pu modifier, via le paramètre amazo nec 2- reg i on;
• cette machine est basée sur l'AMI (modèle de machine virtuelle Amazon) ami-
26d5af4c qui repose sur une Ubuntu 15.10. De nouveau, il s'agit d'une valeur
par défaut que nous aurions pu surch arger avec le paramètre amazon ec2 - ami en
utilisant, par exemple, une AMI personnalisée.

Si vous désirez en savoir plus, la liste des valeurs par défaut est disponible sur la page
de documentation du driver Amazon de Docker Machine1 .

En plus de créer la machine virtuelle EC2, Docker Machine a aussi configuré un


groupe de sécurité (security group ). Il s'agit tout simplement des règles de pare-feu
(firewall) qui ouvre les connexions suivantes:
• port 22/TCP pour les connexions SSH ;
• port 237 6/TCP pour exposer le démon Docker ;
• en option, le port 3376/TCP peut être ouvert si nous passons le paramètre
swarm- ma ster.

• l\ltll'lio'l(I 0 2/2cn.ô(s... HO/le ~.. te2"62·[Link]... $2.23.16'.218 ~ 1

l
N"tann:: 14211b011 (aws-mad11rwj Putllic DNS: K.2-5.2·23-164·[Link].-.com l!!!!l!!I

....._10 '"921 1b018 Publc ONS «i2·S2· 23-164-2 [Link].-[Link]


ll"tt~$[Link] ~ Public; JP ~.23. 1 64.218

[Link] [Link]
Prl't• DHS lp-172-31-10-71.-:[Link]
Pl'MlttolP9 172.31 .10.71

Secwtty Groups ai;50dat9d wfth l-9211b018

Pub Protocol Soun:e dackeHnac:htne


22 lep 00.0MJ ...
2376 tep 00000 ...

l:J
0
Figure 4.5 - Ports ouverts par Docker Machine
c
:i
0
\.0
.-t
0 Pour sécuriser la connexion SSH, Docker Machine génère une clé RSA. La partie
N
@ publique de la clé est ensuite copiée sur notre machine virtuelle (on la retrouve
.......
..c d'ailleurs via la console AWS sous le menu N etwork & Security, puis Key Pairs) .
en
ï:::::
>-
0.
0
Données de configuration locales
u
Lorsque vous utilisez Docke r Machine depuis un hôte, un certain nombre de fichiers
de configuration sont créés e t conservés.
Par exemple, dans le cas de notre machine EC2 :

l. [Link] ine/drivers/aws/
4.1 Docker Machine ---------------------------8
$cd -/ .docker/machine/machines/aws -mach i ne/
[aws-mach i ne ]$ l s -1
ca . pem
cert . pem
con fig .json
i d_rsa
id_rsa . pub
key . pem
server-key . pem
server . pem

O n retrouve :
• n otre clé SSH (id_ rsa et id_ [Link]) ;
• un [Link] [Link] qui contient les détails de la configuration de notre
machine ;
• et un ensemble de certificats.

Ces certificats sont utilisés pour sécuriser l'accès à l'interface HTTP du démon
Docker à l'aide de TLS, ce qui sera expliqué en détails dans le chapitre 8 sur la
sécurisation du démon Docker.

Partage de la configuration Docker Machine


Pour partager la gestion d'une machine entre plusieurs utilisateurs, il suffit théorique-
ment de transférer le contenu du répertoire Docker Machine d'un poste sur un autre.
Le souci est que le contenu du fichier configJson dépend de la configuration locale
du poste initial ; par exemple, les chemins vers les différents certificats sont absolus,
si bien que ce fichier est difficilement portable. Des discussions sont en cours sur le
dépôt GitHub de Docker Machine pour résoudre ce problème.

L'approch e de création de machines est relativemen t identique pour tous les


l:J
providers cloud, ch aque fournisseur ayant bien sûr des paramètres propres.
0
c
::J
~
,., Étud ions maintenant la création d'une machine locale à notre poste de travail à
"O
0 c::;
\.0
l'aide d'Oracle VirtualBox.
.-t
0
.,.,
~

N
'~
@ ·c
.......
..c:
B::;
CO
4.1.5 Installation de Docker avec Docker Machine et Oracle VirtualBox
Ol c
ï:::: 0
c
>-
o.. c La création d'une machine sur VirtualBox nécessite évidemment que VirtualBox soit
u
0 ·3
<.) installé sur votre poste de travail. C'est le cas si vous utilisez Docker ToolBox présenté
::;
"O
0
..... dans le chapitre précédent.
c.
~
~ Le processus de création est très similaire à celui que n ous venons de suivre pour
::;
rS A mazon AWS: c'est d'ailleurs là un point fort de Docker Machine. Le principe des
1
"O
0
drivers permet de masquer simplement l'hétérogénéité des processus d 'installation.
c
8 Créons donc n otre machine local~machine avec le driver v irtualbox :
(Ç)
Chapitre 4. Docker sur un se1Veur

$docker -machine create -- driver vi rtualbox loc al -mac hi ne


(loca l -machine) No defau lt Boot2Docker ISO fo und locally , down l oading t he
l atest re lea se ...
(loca l -machine) Latest re l ease for gi th [Link]/boot2doc ker/boot2docker is
vl.1 0.2
(loca l -ma ch ine) Down l oad in g / .docker/machine/cache/boot2docker . i so f rom
[Link] t hu b. com/boot2docker/boot2docker / releases/down l oad/vl .1 0. 2/boot2 doc ker .i so ...
(l oca l- machine)
0%.... 10%.. . . 20% .. . . 30% .... 40% .... 50% .. . . 60% ... . 70% .... 80% .... 90% .... 100%
Creati ng mach i ne .. .
(l oca l- machine) Copying / .docker/mach i ne/cache/boot2docker . iso t o
/ . docker/mach i ne/machines / local -mac hin e/boot2d ocker . iso .. .
(l ocal-machine) Creat i ng Vi rt ual Box VM ...
(l oca l- machine) Creating SSH key .. .
(l ocal-machine) Starti ng t he VM .. .
(l ocal-machine) Check network to re -crea t e if needed ...
(l oca l- machine) Wa i t ing for an IP ...
Waiting for machine to be runn i ng, this may ta ke a f ew mi nutes ...
Detec ti ng operatin g syst em of created i nsta nce ...
Waiting for SS H to be avai l able ...
Det ecting t he provisioner ...
Provis i on i ng wit h boot2docke r ...
Copy i ng certs to t he l ocal machine di rectory ...
Copy i ng certs to t he remote machi ne ...
Setting Doc ker configura ti on on the remote daemon...
Ch ecki ng connection t o Docker ...
Docker is up and r unni ng!
To see how t o connec t your Doc ke r Client to the Docker Engine r unning on t his
vi rt ua l mac hi ne . run : docker -machine env l ocal-machine

Docker Machine se base ici sur une image [Link], et non pas sur une
image Ubuntu, comme pour Amazon AWS. Cette image est copiée dans le répertoire
-/.docker/cache pour accélérer la création ultérieure d'autres machines locales. Elle est
ensuite copiée dans le répertoire de notre machine -/.docker/machine/machines/local~
machine.
À nouveau, Docker Machine utilise un ensemble de valeurs par défaut pour créer
"'Cl
0 notre machine, chacune pouvant être surchargée 1• Le reste du processus de création
c
:::i est identique à celui de notre machine Amazon EC2 :
0
\.0
.-t • génération d'une clé RSA pour nous connecter en SSH ;
0
N • copie des certificats nécessaires pour sécuriser avec TLS le démon Docker ;
@
....... • configuration du démon Docker avec des valeurs par défaut.
..c
O'l
'i:
>-
0.
0 4.1.6 Quelques autres commandes utiles
u
Nous pouvons lister toutes les machines administrables depuis le poste de travail
avec la commande docker-mac hi ne l s (l'utilisation du paramètre optionnel - -format
permet de personnaliser le détail des informations que nous voulons visualiser, dans
notre cas le nom de la machine, son driver, son URL et la version de Docker2 ) :

1. [Link]
2. [Link] ne/reference/ls/
4.1 Docker Machine ---------------------------[!!]
$docker -machine l s -- format "{{ . Name}} : {l. DriverName}} - {{. URL }} -
{( . DockerVersion}} "
aws-mach i ne : amazonec2 - tcp : //52 . 23 . 164 . 218:2376 - vl .1 0. 2
1 local -machine : virt ualbox - tc p: //192 . 168 .99 .1 01 :2376 - vl . 10 . 2

Nous retrouvons bien nos deux machines.


Pour obtenir plus d'information sur notre machine, nous disposons de la commande
doc ke r -machine i nspect (qui ne fait qu'imprimer le ficher [Link] que l'on retrouve
dans -/.docker/machine/machines/local-machine) :

$ docker -mach i ne inspect l oca l -machine


{
"Con f igVersion ": 3,
"Dr iver ": {
"IPAddress ": "192. 168 .99 . 101",
"Mach i neName ": "loca l -machi ne ",
"SSHUser" : "docker " .
"SSHPort ": 49793,

Nous disposons aussi d'autres commandes permettant d'obtenir rapidement des


informations sur notre machine :

$docker -mach i ne ip l ocal -mac hine# IP de notre machine


192 . 168.99. 101
$ docker -machine url local -ma chi ne# URL de l ·hôte
tc p: //192 . 168 .99 . 101 : 2376
$docker -mac hi ne status local-mach i ne# Ëta t de l a machine
Ru nning

Utilisons maintenant notre machine pour démarrer un conteneur. Pour cela, nous
devons avant tout définir un certain nombre de variables d'environnement pour
indiquer à notre client Docker sur quelle machine il doit se connecter. Nous disposons
l:J
0 pour cela de la co mmande suivante :
c
::J
0
\.0
.-t $docker -machine env local -machine
0
N
export DOCKER_TLS_VER IFY= "l "
@ export DOCKE R_HOST="t cp : // 192 .1 68 .99 .1 01: 2376 "
....... export DOCKE R_CE RT_PATH=" / Users/ t homas / .docker/mac hin e/mach i nes / l ocal -machine "
..c:
O'l expo r t DOCKER_MACHI NE_NAME= "loca l -machine "
·;::
>- # Run t his command t o conf i gure yo ur shell :
0..
0 # eva l $(docker-mach i ne env loca l -mach i ne)
u
Pour configurer votre environnement avec ces variables, utilisez la commande
proposée et vérifiez ensuite avec la commande docker-mach i ne active que notre
machine local-machine est bien celle qui sera utilisée par la suite.

$ eva l $(docker -mach i ne env loca l -mach i ne)


$ docker-machine act i ve
1 local -mac hi ne
El----------------------- Chapitre 4. Docker sur un sefVeur

Par défaut, la commande doc ker-mach in e env génère un résultat pour un terminal
Unix de type bash. Si vous utilisez Windows (Powershell ou cmd), il vous suffit
de rajouter le paramètre - - she 11 pour obtenir un résultat compatible avec votre
environne ment. Par exemple, pour Powershell :

$ docker -machi ne. exe env --s he ll powers hell loc al- machine
$Env:DOC KER_TLS_VE RIFY = "l "
$Env:DOCKER_HOST = "tcp : // 192 . 168 . 99 .101: 2376 " $Env :DOC KER_C ERT_PATH
"C: \Users\thomas\ .doc ker\machine\mach i nes\local -machine "
$Env:DOCKER_MACH INE_NAME = " loca l -mach i ne "
If Run t hi s comma nd to configure your shel l :
If docker -machine .exe env -- shel l=powers hel l local -machine Invoke - Express ion
1

Toutes les comma ndes de notre clie nt Docker utiliseront désormais le démon
Docker tournant sur notre machine local~machine.
Démarrons notre premier conteneur :

$doc ker r un busybox echo Je to urne sur l a machine loca l -mac hi ne


Unable t o f ind i mage 'busybox :l at est' locally
l atest : Pu l l ing from library/ busybox
f810322bba2c : Pull complete
a3ed95c aeb02 : Pull camp l ete
Digest :
sha256 :97473e34e3lle6c l b3f6lf2a72ld038dle5eef17d98d1353a 513007cf46ca6bd
Stat us : Downloaded newer i mage for busy box: l atest
Je to urne sur l a machine l ocal -machine
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREAT ED STATUS
PORTS NAMES
bdf68af495ea busybox "echo Je tou r ne sur 1" 35 seconds ago Exi ted
(0) 34 seconds ago bori ng_maha vira

N ous pouvons même nous connecter en SSH pour vérifier que notre conteneur a
l:J
0
bien été créé sur cette machine :
c
::J
0
\.0
.-t
$ doc ker -machine ssh l oca l -machine
0
N
1111
@ IfIf ffff IfIf
....... fl1f ff ff ffff ffff ffff
..c: ; 11 11 11111111111111111111 1111111111 \ / ===
O'l
ï::::
>- (-- ---- --- ---- --- - /
0.. \ 0 /
0
u \ \ /
\ \ /
- -
1- - 1 1-1- \ -1 1 -1 1 - --
_ \ I _ \ I _ \ I - 1 _ l I _ · JI _ \ I -1 Il I _ \ '-1
1- l 1 (_) 1 (_) 1 1- / _ / (-1 1 (_) 1 (_ 1 < _ / 1
_ ._! \ _ ! \_! \_1__ \_ ,J \ _ / '-1-1'-'-1-I
Boot2Doc ker version 1.10 . 2, buil d mast er : 61 1be10 - Mon Feb 22 22 :47: 06 UTC
2016
Docker version 1. 10 . 2, build c3959bl
4.2 Project Atomic : la distribution Docker de Fedora

docker@l ocal -mac hi ne :-$ doc ker ps -a


CONTAINER ID IMAGE COMMAN D CREATE D ST ATUS
PO RTS NAM ES
bd f68af495ea busybox "echo Je to ur ne sur l " 2 mi nutes aga Exited
(0) 2 min ute s aga bori ng_ma ha vi r a

Pour être complet , listons rapidement les commandes de Docke r Machine qui
permettent de gérer le démarrage, l'arrêt et la suppression d'une machine :
Commande Description
docker-machine start machine Démarre une machine.
docker- machine stop machine Arrête une machine« gentiment».
docker-machine kill machine Arrête une machine de manière« brutale » <selon
les drivers, cette commande est parfois iden-
tique à la commande stop, par exemple pour
OpenStack).
docker-machine restart machine Redémarre une machine (équivalent à la corn-
mande stop suivie de la commande starù.
docker-machine provision machi ne Relance la création d'une machine existante. Cette
commande est principalement utilisée dans le
cas où la commande docker-machine create a
partiellement échoué.
docker-machine regenerate-certs Régénère et recopie les certificats TLS utilisés pour
machine sécuriser le démon Docker.
N ous savons maintenant tout ce qu'il faut pour créer des machines Docker à l'aide
de l'outil Docker Machine.

4.2 PROJECT ATOMIC: LA DISTRIBUTION DOCKER DE


FEDORA
N ous l'avons évoqué dans le chapitre 1, il existe aujourd'hui des versions d'OS
spécialisées pour l'exécution de Docker. Parmi celles-ci, nous allons n ous intéresser à
-0
0
Project A to mic 1.
c
0
:::i C et OS est issu d'un groupe de travail du projet Fedora qui fournit la base Open
\.0 Source à plusieurs distributions bien connues, comme RedHat ou C entOS. L'intérêt
.-t
0
N
d'utiliser ce type de distribution est qu'il est associé à une configuration optimisée pour
@ Docker.
.......
..c Dans cette section, n ous allons installer un hôte Atomic Fedora (il existe aussi une
O'l
'i:
>- version A tomic C entOS ) dans une machine virtuelle VirtualBox. Notez qu'il existe
0.
u
0 une box Vagrant préconfigurée, mais nous avons cho isi ici une installation manuelle.

4.2.1 Préparer l'image


Le projet Atomic met à disposition des images toutes prêtes pour divers environne-
ments d'exécution (dont Vagrant ou A mazon). Pour notre part, nous opterons pour

l. [Link]
Chapitre 4. Docker sur un sefVeur

une image hast Fedora conditionnée pour OpenStack sous le format qcow2. Nous
devrons ensuite la convertir en [Link] VDI, le format d'image VirtualBox.

Attention : processus de préparation


La préparation de l'image nécessite plutôt une machine Linux. Il est en effet nécessaire
de recourir à des utilitaires (comme qemu-img ou cloud-init) qui existent sous
Windows, mais dont l'installation est relativement pénible.
Dans cette section, nous procéderons à la préparation de l'image sur la machine
virtuelle CentOS que nous avons préparée dans le chapitre précédent.
Afi.n que les étapes soient claires pour le lecteur, nous les avons résumées dans la
figure ci-dessous :

Votre machine

VirtualBox

VM centos (créée au chapitre 3)


(!) $ 9enisoilna9e -·
Fedora-Cloud-xxx .vdi
init..iso

~Atomic
[

l
Système de fichiers de votre machine

00.{
:_LJ ~edor~·Cloud xxx. vdi
1n1t.1so

Figure 4.6 - Étapes de création de notre VM Atomic

l:J
0
c
::J Les étapes décrites dans la figure 4.6 sont les suivantes:
0
\.0
.-t
1. Dans la VM de travail, nous allons créer l'image de notre VM Atomic à l'aide
0
N de divers utilitaires.
@
....... 2. Ensuite, nous transférerons les images créées (un fichier VDI et un fichier ISO)
..c:
Ol vers notre machine hôte (celle que vous utilisez et sur laquelle est installé
ï::::
>-
0..
VirtualBox).
0
u 3. Ce transfert est très simple car il est géré par VirtualBox et Vagrant (il s'agit du
partage de fichiers que nous avons activé dans le chapitre 3 ).
4. Ensuite, nous utiliserons VirtualBox pour créer une VM Atomic à partir des
fichiers VDI et ISO.
5. Enfin, nous pourrons nous connecter sur cette VM Atomic pour quelques
opérations additionnelles.
4.2 Project Atomic : la distribution Dock er de Fedora

Téléchargeons l'image
C onnectez-vous à notre VM de travail et téléchargez (à l'aide de Firefox qui est
installé) l'image depuis le site du projet Fedora:
[Link]

Atom ic Host Image


:!m 1mage Raw Image
This is Fedora 23 Cloud Atomic Host in a Qcow2- This is Fedora 23 Cloud Atomic Host in a compressed
formatted image for use with OpenStack. raw image format. If you're not sure what to use. try

- -
this.

6 4-blt 497MB Qc<N/2. Image 6 4-bt 363MB xz-Compressed Raw Image

Figure 4 .7 - Téléchargement de l'image host sur le site


[Link] h tm

Dans notre cas, nous allons utiliser l'image QCOW2.

Convertissons l'image au format VDI


La première étape du processus consiste à convertir l'image QCOW 2 au format VOi
qui est le format de d isque supporté par VirtualBox.
Pour ce faire, nous avons besoin de l'ut ilitaire qemu- img que nous allons installer :

1$ sudo yum i nsta l l -y qemu -i mg

C réez e nsuite dans votre répertoire courant un réperto ire nommé atomic, dans
lequel nous allons placer les d ifférents éléments dont nous aurons besoin :

$ mkdir at omic
$ cd at omi c
"'Cl $ pwd
0
c
:::i
~
,.,
"O
1 /home/vargra nt/ atomi c
0 [Link];
\.0
.-t ~
Placez dans ce répertoire le fichier QCOW 2 que vous venez de télécharger. Si vous
0 V
N V avez gardé le che min par défaut de Firefox, la commande suivan te devrait con venir :
'ii
@ ·c
B
.......
..c
O'l
ï:::::
:::;
CO
c
0
1 $ mv -/Téléchargements/* . qcow2 .
>- c
o. c
0 ·3ù Lançons maintenant la commande de conversion :
u :::;
"O
0
....
c.
~ $ qemu-img convert - f qcow2 Fedora -Cl oud-Atomic -23 -20160420 . x86_64.qcow2 -0
~
:::;
rS
1 vd i Fedora -Cloud-At omic -23 -20160420 . x86 64. vdi
1
"O
0
c Attention, la commande ci-dessus utilise une version donnée de l'image Fedora.
8 C elle-ci peut être différente dans votre cas.
(Ç)
Chapitre 4. Docker sur un se1Veur

Créons le fichier d'initialisation de J'image


Le projet Atomic utilise l'utilitaire cloud-init1 pour préparer l'image au démarrage de
la VM. Cet utilitaire fonctionne un peu à la manière de Vagrant. Il va, au démarrage,
configurer la machine v irtuelle en s'appuyant sur un fichier ISO qui sera inséré dans
le lecteur CD v irtuel de la machine VirtualBox.
Installons d'abord l'utilitaire nécessaire à cette opération :

1 $ sudo yum in sta ll geni so i mage

Nous devons ensuite préparer les fi chiers de configuration (ce sont les équivalents
du fichier VagrantFile de Vagrant). Ceux-ci permettent de nommer la machine qui
sera créée, mais aussi de définir le mot de passe de l'utilisateur par défaut.
Vous devez donc éditer deux fichiers : meta-data et user-data.

$ vi met a-data
instance -i d: atomic - host -sampl e
l ocal - hostn ame : at omic . samp l [Link]

$ vi user-data
#cl oud -conf ig
password : atomi c
ssh_pwaut h: True
chpasswd : ( expire : False }

Cutilisateur qui sera créé aura :


• pour log in fedora ;
• pour mot de passe atomic.

Lançons maintenant la commande de génération du fi chier [Link]:

l:l
$ gen i so i mage -output i ni t .i so -volid ci da t a -jol iet -rock user -da t a meta -da ta
0 !: -i nput -charset not specified, using utf- 8 (detected in l oca l e set ti ngs)
c
:::i Total t ra nsl at ion ta ble si ze : 0
0
\.0
Total rockridge attr i but es bytes : 331
.-t Tota l di rectory bytes : 0
0
N Pa th ta bl e size(bytes) : 10
@ Max brk space used 0
.......
..c 183 ext en t s written (0 MB)
O'l
ï:::::
>-
0. Et maintenant transférons ces fichiers sur notre h ôte pour passer à l'étape de
0
u création de la VM avec VirtualBox :

1 $ sudo mv *. vdi *. iso /media/sf_vagrant

Voilà ce que devrait contenir votre répertoire de travail Vagrant sur votre machine :

l. [Link]
4.2 Project Atomic : la distribution Docker de Fedora

.vagrant Fedora-Cloud-At [Link] Vagrantfile


omic-23-2016042
O.idl6_64.vdi

Figure 4 .8 - Fichiers images prêts à l'emploi

4.2.2 Création de la VM Atomic

À l'aide des fichiers VDI et ISO, la création de la machine virtuelle se fait en mode
graphique avec VirtualBox.

Une nouvelle machine vittuelle


Pour commencer, créez une nouvelle machine v irtuelle en entran t les paramètres
affichés sur la figure 4.9 :

y create Virtual Machine x

Name and operating system

Please choose a descriptive name for the new virtual


machine and select the type of operating system you
intend to install on it. The name you choose will be used
throughout VirtualBox to identify this machine.

N~me: 1Atomic host


JYpe: 1Linux

yersion: i):ëdora 164-iiiff--

l:J
0
c
::J
~
,.,
"O
0 c::;
\.0
.-t
0
.,.,
~
[ ~xpert Mode J < !!_ack !!ext > J[ Cancel
N
'~
@ ·c
....... B::;
..c: CO
Figure 4 .9 - Création d'une machine virtuelle
Ol c
ï:::: 0
>- c
o.. c
u
0 ·3
<.)
::;
"O Nous allons maintenant définir la mémoire disponible pour cette machine v irtuelle.
0
.....
c. N ous allouons ici 4 G o de RAM, mais vous êtes libre de laisser la valeur par défaut
~
~
::;
proposée par VirtualBox, car elle sera suffisante pour cet exercice.
rS
1
"O
0
c
8
(Ç)
Chapitre 4. Docker sur un sefVeur

y Create Virtual Machine x

Memory size

Select the amount of memory (RAM) in megabytes to be


allocated to the virtual machine.

The recommended memory size is 7611 MB.

~•.• ,, •• ,,,,,,,,,,,,,,,,_ [ 4096 f$j MB


4MB 32768 MB

< !!.ack 11 _tlext > 11 Cancel

Figure 4 .10 - Configuration de la mémoire

Nous arrivons maintenant à la création du disque de la mach ine (figure 4.11).


Choisissez un disque existant et sélectionnez le fichier VDI que nous avons précédem~
ment créé:
y Create Virtual Machine x

Hard disk

If you wish you can add a virtual hard disk to the new
machine. '!bu can either create a new hard disk file or
select one from the list or from another location using the
folder icon.

If you need a more complex storage set-up you can skip


this step and make the changes to the machine settings
once the machine is created.

The recommended size of the ha rd disk is [Link] GB.

( l Qo not add a virtual hard disk

çreate a virtual hard disk now

• yse an existing virtual hard disk file

l:J 1~-dor~:c:1oud:11tomi[Link] i~o4~o:xa6j4:~il ~ ] i:a


0
c
::J
0 < !!.ack 11 Create J I cancel
\.0
.-t
0
N
Figure 4 .11 - Ajout du fichier image Fedora Atomic <fichier V DD
@
.......
..c:
O'l
ï:::: Pour finir, il faut insérer le fichier in [Link] dans le lecteur C D virtuel de la machine
>-
0..
0
(figure 4-1 2) .
u
N ous pourrions démarrer la machine à ce stade, mais nous allons encore effectuer
deux opérations additionnelles:
• créer un disque additionnel de grande capacité (nous verrons qu'il nous
permettra d'aborder la problématique de la configuration de devicemapper, le
pilote de stockage de Docker déjà évoqué dans le ch apitre 1) ;
• configurer l'accès réseau de la machine afin de pouvoir s'y connecter en SSH
(et ainsi éviter les problèmes de clavier QWERTY).
4.2 Project Atomic : la distribution Docker de Fedora

0 Atomic host - Settings X

1 ~ G~eral ------i_ls_t_o_ra_g_e_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _~
System ~torage Tree Attributes

m Display ~ Controller. IDE !


Optical [Link]: 10E Secondary Master : J ~...

- ·l'fll~[Link]••••• !,ive CD/DVD

~
Information
fi:ii Fedora-Cloud-Atomic-23-201... Type: Image
rlfJ Networlc O Please choose a virtual optical disk file
!) Serial Ports

r; USB
Look in: J ~ /home/pyc/Development/Worlcspaces/atomic : I + + +!:.Hill
Il Computer
i;'.J Shared Folde
ln pyc
ILj User Interface

Figure 4.12 - Ajout du fichier [Link] dans le lecteur CD de la machine virtuelle

Ajout d'un disque dur


Toujours dans le menu Storage, sélectionnez le contrôleur SATA et ajoutez un disque
(en cliquan t sur l'icône correspondante ).
U ne première étape (figure 4 .13) vous demande de ch oisir entre un disque existan t
et un nouveau disque. C 'est cette seconde option que nous allons ch o isir.
Dans la suite des écrans, sélectionnez les options suivan tes :
• disque VDI ;
• disque de taille fixe ;
• taille de 20 G o.

0 Atomic host - Settings X

1 !!! General ~Is_ t_o_r a_ g_e_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ __


~ System ~torage ltee Attributes
l:J
0
c
1 m Display 1~ Controller: IDE !'.!•me: § TA
~pe: ~ HC_l_ _ _ _ _ _ _
, A- !~J
J
:J - [Link]
0
~ Audio
\.0
.-t
~ Network.
.A,. 'lbu are about to add a virtual hard disk to controller he
0 V SATA.
N
~ Serial Ports Would you lîke to create a new, e mpty file to hold the
@
.......
r; USB
disk contents or select an existing one?

..c: u:J Shared Folder.;


Ol Cancel 11 Ç,hoose existing disk 11 Create new disk
·;::
>- ru User Interface
o.
0
u
1 li] !!•lp 1 1 Qç.ncel JI . .QK 1

Figure 4.1 3 - Création d'un disque additionnel


Chapitre 4. Docker sur un sefVeur

Paramétrage du réseau
Nous vous proposons de configurer la VM pour qu'elle expose son port 22 sur l'hôte
via le port 9022. C eci nous permettra de nous connecter à cette VM à l'aide d'un
client SSH (et ainsi de ne pas souffrir des problèmes de clavier américain).
O Atomic host - Settings x

!!J General [ Network


~ System Adapter ! ...._............._.....,""""___..= ._._.__ _ _ _ _ _~
e!J Display ~nable Networ1< Adapter

-
Storage

~ Audio 1 ~ame:

9 A~vanced

î): Serial Ports


Adapter ]'fpe: ----------------..,
r; use Erom1scuous Mode:

li.:J Shared Folders


!1_AC Address:

./ çable Connected
!r'.j User Interface
1 Eort Forwarding

_J~------
[ Qçancei l [ . .QK [

Figure 4 . 14 - Configuration du réseau

Ouvrez le panneau de configuration du réseau (figure 4.14), puis sélectionnez Port


forwarding.
o'"l Port Forwarding Ru les x

Name Protocol Host IP Host Port Guest IP Guest Port ~

j ssHRule ITCP 19022 Tu2 i~

l:J
0
c
::J
0
\.0 1Q s;ancel 11 . ,QK
.--1
0
N
@
.......
Figure 4 . 1 5 - Association des ports réseau de l'hôte et de la VM
..c:
O'l
ï:::: Configurez les redirections de ports, comme cela est indiqué à la figure 4.15.
>-
0..
0
u Nous sommes maintenant prêts à nous connecter à notre VM Atomic.

4.2.l Lancement et configuration de devicemapper


Lan cez la machine virtuelle et connectez,vous à l'aide de SSH :

1 $ ss h · p 9022 fe dora@local ho st
4.2 Project Atomic : la distribution Dock er de Fedora

Sous Windows, vous pouvez utiliser un outil comme putty si vous ne disposez pas
d'une ligne de commande.

Une fois la machine lancée, vous pouvez constater que Docker est déj à installé en
lançant la commande docker i nfo dont nous verrons qu'elle donne des informations
sur l'installation du moteur de conteneurs:

$ sud o docker i nfo


Cont ai ner s : 0
Images : 0
Se rver Versi on: 1.9.1
St orage Dr i ver : devi cema pper
Pool Name : atomi cos -doc ker -- poo l
Pool Bl oc ks ize : 524.3 kB
Ba se Dev i ce Si ze: 107 .4 GB
Bac ki ng Filesy stem : xfs
Dat a f i l e :
Meta dat a fi l e:
Data Space Used: 62.39 MB
Data Space Total: 2. 147 GB
Data Space Available : 2.085 GB
Met adata Space Used : 40.96 kB
Met adat a Spa ce Total : 8.389 MB
Metadat a Space Avail abl e: 8.348 MB

Vous pouvez noter dans le listin g ci-dessus que l'espace alloué pour les données
Docker n'est que de 2 Go. Dans un environnement réel, cette taille est très rapidement
atteinte. C'est la raison pour laquelle nous avons créé un nouveau d isque de grande
capacité.
C eci va nous permettre d'aborder un sujet important: la configuration du stockage
de données Docker.

Petite digression sur devicemapper


"'Cl Nous l'avons déjà évoqué dans le chapitre 1, l'un des storage drivers (pilote de gestion
0
c
:::i
~
,., des images, conteneurs et volumes) de Docker les plus utilisés (spécifiquement dans
"O
0 [Link]; les environnements Fedora, mais aussi sous Ubuntu ou Debian) est devicemapper.
\.0
.-t ~
0
N
V
V Celui-ci est différent des autres storage drivers dans la mesure où il fonctionne
'ii
@ ·c avec une granularité inférieure au fichier. Il s'appuie sur un mécanisme de stockage
....... B
..c
:::;
CO basé sur des blocs de données.
O'l c
0
ï:::::
>- c
c Sans entrer dans le détail de ce mécanisme 1 , il est important de savoir que
o.
u
0 ·3ù l'installation par défaut de Docker pour ces environnements ne doit pas être u tilisée
:::;
"O
0
....
telle quelle en production . En effet, par défaut, le mécanisme de stockage s'appuie
c.
~ sur des fichiers (aussi nommés sparse fi les ou fichiers dynamiques). Ceci simplifie la
~
:::; configuration (l'utilisateur peut utiliser Docker immédiatement), mais ce n'est pas
rS
1
"O
0
c 1. Le lecteur intéressé pourra se reporter à l'article suivant:
8 [Link] [Link]/engine/userguide/storagedriver/device-mapper-driver/
(Ç)
El----------------------- Chapitre 4. Docker sur un sefVeur

approprié pour un système réel car c'est très consommateur de ressources, ce qui
dégrade les performances.
Heureusement, grâce à sa conception, Atomic est correctement préconfiguré avec
le mode de production (direct,lvm), bien que le disque image par défaut soit trop petit
(à peine 2 Go pour le stockage des blocs).
C 'est la raison pour laquelle nous avons créé un disque additionnel. Nous allons
maintenant étudier comment installer ce nouveau disque en créant un nouveau volume
group.

Étendre le pool de stockage Docker


La commande suivante va nous permettre d'identifier notre disque de 20 Go :

1 $ sudo fdis k -1

Le voici:

Dis k /dev/sdb : 20 GiB , 21474836480 bytes, 41943040 sect ors


Unit s : sect ors of 1 * 512 = 512 bytes
Sector si ze (log i cal/physica l ) : 512 bytes/ 512 bytes
1 1/0 size (mi nimum/optimal) : 512 bytes/ 512 bytes

À ce stade, le disque est accessible depuis l'OS, mais pas alloué à Docker qui
s'appuie sur un volume group par défaut nommé atomicos et de taille restreinte :

$ sudo vgdisp l ay
-- - Volume group
VG Name atomicos
System ID
Format l vm2

VG Size 5. 70 GiB
l:J PE Size 4 .00 MiB
0
c
::J
0 N ous allons donc en créer un nouveau en utilisant le disque que nous avons ajouté
\.0
.-t
à notre machine virtuelle lors de sa création.
0
N Pour ce faire, nous allons en premier lieu acquérir les droits root :
@
.......
..c:
O'l
ï:::: 1 $ sudo su
>-
0..
0 Ensuite, nous allons modifier le fichier de configuration de l'utilitaire docker,
u
storage,setup :

$ bash -4 . 2# vi /etc/sysconfig/docker -storage-setup


GROWPA RT=true
VG="myext ended pool "
STORAGE_DRIV ER=" dev i cemappe r"
DEVS="/dev/sdb "
4.2 Project Atomic : la distribution Dock er de Fedora

C e fich ier vous indique que :


• n ous utilisons le gestionnaire de stockage devicemapper ;
• nous allouons n otre disque physique de 20 Go (précédemment identifié comme
/dev/sdb);
• c'est le nouveau volume group 1 qui assurera le stockage des données pour Docker
(via le driver devicemapper).

Lançons maintenan t le script de reconfigurat ion docker-storage-setup :

bas h-4.3# doc ker-st or age -setup


Chec ki ng th at no-one is usin g this dis k ri ght now . . . OK

Di sk /dev/sd b: 20 GiB , 21474836480 byt es, 41943040 sectors


Unit s : sectors of 1 * 512 = 512 bytes
Sector si ze (l og i ca l / phys i call : 512 bytes/ 512 bytes
I/O size (mi nimum/optimal) : 512 bytes/ 512 bytes

>>> Scri pt heade r accept ed .


>>> Created a new DOS di skl abe l wi t h disk ident i fier Oxf3dl2669 .
Creat ed a new pa rt i t i on 1 of t ype 'Lin ux LVM' and of si ze 20 Gi B.
/dev/sdb2 :
New situa t i on :

Devi ce Boot Start End Sect ors Si ze Id Type


/dev/sdbl 2048 41943039 41940992 20G Se Linux LVM

The partit i on ta ble has been altered .


Ca l ling ioctl() to re -read partition tab le .
Synci ng disks .
Physica l vol ume "/dev/sd bl " successf ul ly crea t ed
Volume group "myextendedpool " successfully created
NOCHANGE : partit i on 2 i s size 11966464 . it cannot be grown
Physica l vo lume "/dev/s da2 " cha nged
1 physica l volume(s) res i zed / 0 physica l vol ume(s) not resized
Ro un di ng up size t o f ull phys i cal ext ent 24 .00 MiB
"'Cl Log i ca l volume "docker -poo lmeta" cre ated .
0
c ~
,., Log i cal volume "docker -poo l " crea t ed .
:::i
0 "O W ARN ING: Converti ng l og i cal vo l ume myext endedpoo l / docker-pool and
[Link];
\.0 myext endedpool /doc ker -poo lmeta to poo l 's data and met adat a volumes .
.-t ~
0 V THIS WI LL DEST ROY CONT ENT OF LOG ICAL VOLUM E (filesys t em et c. )
N V
'ii Converted myext endedpool /docker -pool to t hi n poo l .
@ ·c
....... B Logi cal vo l ume "docker -poo l " changed .
:::;
..c CO
O'l c
0
ï::::: c Nous pouvons maintenant redémarrer le démon Docker et regarder si le ch an ge-
>-
o. c
0 ·3ù ment de configuration a porté ses fruits :
u :::;
"O
0
....
c.
~
~
:::;
rS
1
"O
0
l. Pour plus d'explications relat ives à la gestion de volumes logiques sous Linux, reportez-vous à
c l'article W ikipédia suivant:
8 [Link] Volume_Manager_ %28Linux% 29
(Ç)
a Chapitre 4. Docker sur un se1Veur

bash -4.3# service docker restart


Red i rect i ng t o /bi n/systemctl restart [Link]
bas h-4 .3# docker i nfo
Containers : 0
Images : 0
Server Vers i on : 1. 9. 1
St orage Driver : devicemapper
Pool Name : myextendedpool -docker--poo l
Pool Bl ocks i ze : 524 .3 kB
Base Device Siz e: 107 .4 GB
Bac ki ng Filesystem : xfs
Data f ile :
Metadat a fi l e:
Data Space Used : 62 .39 MB
Data Space Tot al : 8. 577 GB
Data Space Availabl e: 8. 515 GB
Metada t a Space Used : 45.06 kB
Metada t a Space Total : 25 .17 MB
Metada t a Space Av ai la bl e : 25 .1 2 MB

Vous pouvez constater que le volume de stockage alloué aux données est mainte-
nant de 8,577 Go contre 2,085 Go. Sans entrer dans le détail du fonctionnement du
script docker-storage-setup, il s'agit par défaut de 40 % de l'espace disque physique qui
a été ajouté (nos 20 Go). Il est évidemment possible de modifier la configuration du
script pour obtenir d'autres résultats 1•

En résumé
Dans ce chapitre, nous avons appris comment installer Docker sur un hôte en
utilisant deux types de solutions différentes. Ceci nous a permis d'aborder l'usage de
l'un des outils de l'écosystème Docker (Docker Machine ). Nous nous sommes aussi
intéressés à la distribution Linux Atomic et, par l'intermédiaire de cet exemple, à
la configuration de devicemapper, un pilote de stockage (storage driver) majeur pour
l:l
0 Docker.
c
0
:::i Il est temps à présent de créer nos premiers conteneurs et de jouer avec la ligne de
\.0
.-t
commande Docker.
0
N
@
.......
..c
O'l
ï:::::
>-
0.
0
u

1. h ttps://gith [Link]/proj ectatom ic/docker-storage-setup


5
Conteneurs et images

Fabriquer une image et exécuter un conteneur


L'objectif de ce chapitre est de débuter la prise en main de Docker à l'aide de
l'en vironnement décrit dans le ch apitre 3. Pour ce faire, n ous allons étudier le cycle
de v ie d'un conten eur pas à pas, à partir d 'une image offic ie lle du Docker Hub.
Ensuite n ous montrerons comment construire une image originale pour fabrique nos
propres conteneurs.
L'objet de ce ch apitre n'est pas d'approfondir chaque con cept, mais d 'effectuer un
survol relativement complet des fonctionna lités du Docker Engine.
À l'issue de ce chapitre, vous saurez créer une image, un conteneur et vous maîtriserez
quelques commandes de base du client Docker.
l:J
0
c
::J
~
,.,
"O
0 c::;
\.0
.-t
0
.,.,
~
5.1 LE CYCLE DE VIE DU CONTENEUR
N
'~
@ ·c
....... B
..c:
::;
CO C omme nous l'avon s évoqué dans les deux précédents ch apitres, un conteneur Docker
Ol c
ï:::: 0
c est fabriqué à partir d'une image. Il peut ensuite adopter différents états que n ous
>- c
o.. allons maintenant présenter.
u
0 ·3
<.)
::;
"O
0
.....
c. Nous supposons que le lecteur a installé l'environnement recommandé dans le
~
~
chapitre 3 et s'est assuré que le service Docker est effectivement démarré.
::;
rS
1
"O
0
Le diagramme ci~dessous montre l'en semble des états possibles d 'un conten eur.
c
8 Vous n oterez qu'un conten eur peut être créé et démarré immédiatement (commande
(Ç) run ) ou créé dan s l'attente d'être démarré (commande cre at e). D'autres commandes,
Chapitre 5. Conteneurs et images

comme st op ou ki 11 , peuvent aussi sembler redondantes de prime abord. Nous en


expliquerons en temps voulu les subtilités.

run ~

/ R:ning ~
start ~ stop kill

Dock•"~•• ~ Stop( ed .,)__/


~ create / rm ~ ~
Destroyed

Figure 5.1 - Cycle de vie du conteneur Docker

5.1.1 Créer et démarrer un conteneur (commande run)

Créons un conten eur nginx 1 • Il s'agit d'un conteneur exécutant le serveur web open
source Nginx. Notez que l'image nginx est un official repository du Docker Hub, c'est-
à-dire une image certifiée par l'entreprise Docker lnc.

1 $ doc ke r r un -p 8000: 80 -d ngi nx

Sans entrer dans le détail à ce stade, vous noterez que n ous passons trois paramètres
à cette commande r un :

l:J
• -p 800 0 : 80 spécifie comment le port 80 du serveur web, ouvert à l'intérieur du
0
c conteneur, doit être exposé à l'extérieur (sur notre hôte ). N ous reviendron s par
:i
0 la suite sur ces problématiques de gestion du réseau. À ce stade, nous retiendrons
\.0
.-t que le port 80 du serveur web sera exposé sur le port 8000 de l'hôte .
0
N
• -d indique que le conteneur doit s'exécuter en mode démon, c'est-à-dire non
@
....... bloquant. Sans ce paramètre, la ligne de commande serait bloquée et affich erait
..c
en les logs du serveur web.
ï:::::
>- • ngi nx correspond au nom de l'image qui va ê tre utilisée pour instancier le
0.
0
u conteneur.

Si cette commande est exécutée pour la première fois, e lle va entraîner le


téléchargement de l'image Docker officielle nginx qui va servir de moule pour la
création de notre conteneur.

l. [Link]
S. 1 Le cycle de vie du conteneur a
Unable to find image 'nginx : l atest' l ocal l y
l at est : Pul l i ng fro m libr ary / nginx
9ee l 3ca3b908 : Pu l l complet e
23cb15b0f cec : Pull complete
62df5el7dafa : Pu ll compl ete
d65968claa44 : Pu l l compl ete
f5bbl dd dc876 : Pull comp l et e
1526247f349d : Pull compl ete
2e5 18e3d3fad : Pu ll complete
Oe07123e6531 : Pull compl et e
21656a3c1256 : Pu l l complete
f608475c6c65 : Pu ll compl ete
lb6c0a 20b353 : Pull compl ete
5328 f dfe 9b8e : Pu ll com plete
Digest :
sha256 : a79db4b83c0dbad9542d5442 00 2ea294aa77014a3df a67 160d8a5587 4a 55 20cc
Stat us : Downloaded newer i mage for ng i nx : latest
050e5c557d8a7a7ed37508c4cf35d260844ef75bf ae5 2f5bdd2302dac7b78806

Comme vous pourrez le constater par la suite, cette phase de téléchargement ne


sera plus nécessaire par la suite. L'image est en effet désormais stockée dans le registry
local de votre ordinateur.
Vérifions que le serveur web fonctionne correctement en faisant un simple appel
à sa home page, [Link] en utilisant le navigateur Firefox installé dans
notre image Linux de référence.

Welcome to nginx! - M ozilla Firefox D )(

J Wekome to n9inx !

~ 1 lt localhost 8000 .., <! 11 Q. Rechercher

Welcome to nginx!
~ you see this page, the nginx web server is successfully installed and working.
Further configuration is required.
For online documentation and support please refer to [Link].
Commercial support is available at [Link].

"'Cl Thank y ou for using nginx.


0
c
:::i
~
,.,
"O
0 [Link]; Figure 5.2 - Premier conteneur Nginx
\.0
.-t ~
0 V
N V
'ii Que faire de ce conteneur ?
@ ·c
....... [Link];
..c CO Le cycle de vie de la figure 5.1 nous indique que deux options sont possibles :
O'l c
0
ï::::: c
>-
o. c • stopper le conteneur avec la commande stop ;
u
0 ·3ù
:::; • tuer le conteneur avec la commande k i 11.
"O
0
....
c.
~
~
:::; 5.1.2 Stopper un conteneur <commande stop ou kilD
rS
1
"O
0
Il n'y a pas de grande différence entre les deux commandes, si ce n'est la violence de
c
8 l'injonction de s'arrêter. k i 11 va envoyer un signal SIGKILL au processus principal
(Ç) qui s'exécute dans le conteneur (Nginx dans notre cas). La commande st op va tout
Chapitre 5. Conteneurs et images

d'abord en voyer un message SIGTERM puis, après un délai donné et si le processus


n'est pas encore arrêté, un message SIGKILL (comme le ferait la commande Unix
ki 11 - 9). En général, on utilise donc plutôt la méthode stop.
Pour stopper un conteneur, il est nécessaire de con naître son identifiant.

Identifier un conteneur
Pour déterminer cet identifiant, nous utiliserons la commande ps.

1 $ docker ps

C ette commande liste tous les conteneurs en cours d'exécution de même que
d'autres informations utiles :

CONTAINER ID IMAGE COMMA ND CREATED


855bbd5e9823 nginx "n gi nx -g 'daemon of f " 17 min ut es ago
STATUS PORTS NAM ES
1 Up 17 minutes 443/tc p. 0.0.0. 0:8000 ->80/tcp stupefied_f erma t

Vo ici un descriptif des informations retournées par cette commande ps :


Champ Description
CONTAINER ID Chaque conteneur Docker est associé à un identifiant unique
généré par le démon Docker.
Celui qui est affiché ci-dessus est l'identifiant court. Il existe
aussi un identifiant long globalement unique (selon la norme
RFC4122*> et qui est visualisable en utilisant la commande :
docker ps -no-trunc
IMAGE L'image à partir de laquelle a été créé ce conteneur
COMMAND La commande qui est exécutée dans le conteneur. Dans notre
cas, on constate que Nginx est lancé en mode deamon off.
Cela signifie que cette commande est bloquante : elle ne rend
pas la main après avoir été exécutée.
l:l Nous verrons que c'est une condition nécessaire, dans le
0
c cas contraire le conteneur s'arrêterait immédiatement après
:::i
0 lexécution de la commande.
\.0
.-t CREATED Combien de temps s'est écoulé depuis la création du conteneur
0
N STATUS L'état actuel du conteneur, dans notre cas Up. S'il venait d'être
@ stoppé, le conteneur serait dans un état Exited.
.......
..c PORTS Les ports utilisés par le conteneur et éventuellement exposés
O'l
'i: sur l'hôte. Ici nous pouvons noter que Nginx occupe deux
>-
0. ports (80 et 443) à l'intérieur du conteneur. Par contre, seul
0
u le port 80 est réexposé sur l'hôte et associé au port 8000.
NAM ES C'est le nom intelligible du conteneur. Il est possible lors de
l'exécution de la commande run (ou create) de spécifier un
autre nom de son choix. Si tel n'est pas le cas, Docker en
génère un automatiquement composé d'un adjectif et d'un
nom de famille de personnage célèbre...
* [Link] [Link]
** h ttps://gith [Link]/docker/docker/blob/master/pkg/namesgenerator/n [Link]
5. 1 Le cycle de vie du conteneur -----------------------El
Résultat de la commande stop
Maintenant que nous sommes en possession de l'UUID (l'identifiant unique) de notre
conteneur, nous allo ns le stopper. Notez que l'UUID court est suffisant lorsque l'on
travaille sur un hôte donné.

1 $ docker stop 85 5bbd5e9823

Le rafraîchissemen t du navigateur sur l'adresse [Link] montre que


le serveur N ginx est désormais éteint.
Notre conteneur est-il pour autant définitivement détruit ?
Non, celui-ci existe toujours ou, plus exactement, l'image complémentée de la
couche persistante read/write propre aux conteneurs (cf. chapitre 1, union file systems)
est toujours stockée sur le système.
Sur notre hôte (pour peu que l'on dispose des droits root), nous pouvons même
lister chaque répertoire contenant l'état des conteneurs.

$ l s /var/ l ib/docker/conta i ners/


1 855bbd5e98239 bdl 56253b370dae0384e628bclf3300dea60fde20b3d952b2a l
Nous constatons dans notre cas que le réperto ire /var/lib/docke r/containers/ ne
contient qu'un seul sous-réperto ire. Vous aurez peut -être remarqué que les douze pre-
miers caractères correspondent à l'UUID court de notre conteneur (855bbd5e9823 ).
Le nom du réperto ire est en effet constitué de l'UUID long de ce dernier.

Redémarrer un conteneur stoppé


Si nous exécutons la commande docker ps comme précédemment, vous noterez que
notre conteneur stoppé n'apparait plus. En effet, par défaut, la commande ps n'affi che
que les conteneurs U p. Il faut ajouter le paramètre - a (pour «AU ») afin d'affi cher les
conteneurs qui ne sont pas actifs.
"'Cl
0
c ~
,.,
:::i
"O $ docker ps -a
0 [Link];
\.0
.-t ~ CONTAI NER ID I MAGE COMMAN D CR EATED
0 V
N V
'ii 855bbd5e9823 ngi nx "nginx -g 1daemon off " 2 ho urs ago
@ ·c
....... [Link];
..c CO STATUS PORTS NAM ES
O'l c
0 Ex i ted (0) 26 min utes ago stupef ied_fermat
ï::::: c
>-
o. c
u
0 ·3ù Nous allons maintenant redémarrer ce con teneur.
:::;
"O
0
....
c.
~
~
:::;
1 $ docker start 855bbd5e9823
rS
"O
1 Le test habituel via notre navigateur nous confirme que Ngin x est actif à nouveau.
0
c
8 Notez que nous aurion s pu aussi lancer la commande suivante qui, à la place de
(Ç) l'identifiant du conteneur, utilise son nom (généré automatiquement par Docker).
J 102 I Chapitre 5. Conteneurs et images

1 $ docker start stupefied_fermat

5.1.3 Détruire un conteneur <commande rm)

C'est la dernière étape du cycle de vie de notre conteneur. Tentons de stopper n otre
conteneur.

$ docker rm 855bbd5e9823
Er ror respons e from daemon : Can nat destroy conta i ner 855bbd5e9823 : Conflict.
You can not remove a ru nn i ng cont ai ner . St op the container before at tempting
remov al or use -f
Error : failed to remove conta in ers : [8 55bbd5e9823 J

Docker nous indique que nous ne pouvons pas détruire un conteneur qui n'est
pas stoppé. C omme cela est indiqué sur la figure 5.1, nous devons d'abord stopper le
conteneur avant de le détruire.

$ docker stop 855bbd5e9823


1 $ docker rm 855bbd5e9823

Cette fo is, docke r ps -a montre que notre conteneur n'existe plus au niveau du
système, ce que confirme un ls /var/lib/docker/containers/.

Notez qu'il est possible de forcer la destruction d'un conteneur Up en utilisant, comme
le suggère le message d'erreur plus haut, le paramètre - f (ou - - force). Ce paramètre
provoque l'envoie un SIGKILL (comme pour la commande ki 11 ), ce qui a pour effet
de stopper le conteneur avant de le détruire.

5.1.4 La commande create


l:J
0
c
::J Certains auront probablement remarqué que nous n'avons pas abordé le cas de la
0
\.0
commande create. C elle-ci est en fait très similaire à la commande r un, si ce n 'est
.-t
0 qu'elle crée un conteneur inactif et prêt à être démarré .
N
@
.......
..c:
O'l
1 $ docker crea t e -p 8000 :80 ng i nx
·;::
>-
0..
0 La commande ci-dessus crée un conteneur dans un statut nouveau (ni Up, ni
u
Exited) : Created.

$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED
2ab2ba l 543ce nginx "n gi nx -g 'daemon of f " 8 seconds ago
STATUS PORTS NAM ES
Created roma ntic_nobel
5.2 Accéder au conteneur et modifier ses données -----------------11031
Il ne reste alors qu'à démarrer notre conteneur en utilisant l'habituelle commande
s t art.

1 $ docke r st art 2ab2bal 543ce

Nous avons parcouru dans cette section l'ensemble du cycle de vie d'un conteneur.
Néanmoins, le conteneur que nous avons utilisé était relativement inintéressant. Nous
devons donc maintenant aborder deux questions :
• Comment configurer le comportement d'un conteneur et le faire, par exemple,
interagir avec son système hôte ?
• Comment créer une image originale qui fournisse un service correspondant à
nos besoins ?

..
5.2 ACCEDER AU CONTENEUR ET MODIFIER SES
..
DONNEES

Nous allons aborder dans cette section différents points d 'intégration entre le conte,
neur et son système hôte :
• la connexion en mode terminal avec le conteneur ;
• la gestion des volumes et la manière d'assurer la persistance de données sur
l'ensemble du cycle de v ie d 'un conteneur (y compris après sa destruction) ;
• la configuration des ports IP.

Nous ne traiterons pas des liens réseaux entre les conteneurs. Cet aspect sera traité
dans la quatrième partie de cet ouvrage sur la base d'exemples significatifs.
l:J
0
c
::J
~
,.,
"O
0 c::;
\.0
.-t .,.,
~ 5.2.1 Connexion en mode terminal
0
N
'~
@ ·c Dans le paragraphe précédent, nous avons utilisé une image générique prise depuis le
....... B::;
..c: CO Docker Hub sans la modifier. En pratique, lancer un conteneur sans le modifier n'a
Ol c
ï:::: 0
>- c aucun intérêt.
o.. c
u
0 ·3
<.) Nous allons reprendre notre image nginx en modifiant les pages retournées par le
::;
"O
0
.....
c.
serveur web.
~
~
::;
rS
1
"O
0
c
8
(Ç)
Chapitre 5. Conteneurs et images

Attention, pensez à supprimer le conteneur créé au paragraphe précédent avant


de vous lancer dans celui~ci. Pour ce faire utilisez la commande doc ker sto p puis
docker rm comme nous l'avons fait un peu plus h aut. Dans le cas contraire il est
probablement qu'un message d'erreur« Bind for [Link]:8000 failed: port is already
allocated » ne s'affiche indiquant que le port 8000 est déjà occupé !

La page que nous avons vue jusqu'à maintenant se trouve (au sein du conteneur)
dans le répertoire /usr/share/nginx/html.
Comment la modifier ?
Comme nous allons le voir plus bas, Docker offre la possibilité de lancer des
commandes dans un conteneur actif tout en obtenant un lien de type pseudo~terminal.
En premier lieu, démarrons un nouveau conteneur.

1 $ doc ker r un -d -p 8000 :80 -- name webserver nginx

Vous noterez que nous venons d'utiliser un nouveau paramètre - -name pour la
commande r un. Celui~ci permet de changer le nom d'un conteneur en utilisant un
alias généralement plus simple à mémoriser que l'UUID ou le nom donné par défaut
par Docker.

CONTA INER ID IMAGE COMMAND CREATED


28314fdbd549 ngi nx "ng i nx -g 'daemo n of f " 2 min utes ago
STATUS PORTS NAMES
1 Up 2 minutes 443/tcp . 0. 0. 0. 0:8000 ->80/tc p webserver

Pour se connecter à l'intérieur de ce conteneur actif, nous allons utiliser la


commande exec.

l:J
1 $ docker exec -t -i webserver /bin/bash
0
c La commande exec permet de démarrer un processus dans un conteneur actif.
::J
0 Dans notre cas, n ous lançons un nouveau terminal (bash) en l'associant (grâce aux
\.0
.-t
0
paramètres - i et -t ) au flux d'entrée (STDIN) et à un pseudo~terminal. L'exécution
N
de la commande ouvre un prompt Unix qui permet alors de naviguer à l'intérieur du
@
....... conteneur.
..c:
O'l
·;::
>-
0..
0
root@28314fdbd549 : /# hostname
u 28314fdbd549
root@28314fdbd 549 : /# l s
bi n boot devetc home l i bl i b64 media mnt optproc root run sbin srv
sys t mp usr var

Comme vous pouvez le constater, le nom d'hôte est 28314fdbd549, ce qui


correspond à l'UUID court du conteneur. Ce sera systématiquement le cas pour tout
conteneur.
5.2 Accéder au conteneur et modifier ses données - - - - - - - - - - - - - - - - - - l10sl

Pour co nfirmer que nous sommes bien à l'intérieur du conteneur, nous allons
modifier la home page du serve ur web. La commande suivante écrase le contenu du
fichier HTML par défaut avec une simple chaîne de caractères« Je suis dedans» .

$ echo "Je suis deda ns " > /usr/share/nginx/html /index . html


1 $ exit

Ouvrons notre navigateur pour constater que la modification s'est déroulée


correcte ment.

M ozill.a Firefox c )(

[Link] 8000/ )( 1 +
~) Localhost·8000 V ~1 » -
Je suis dedans

Figure S.3 - Home page de Nginx modifiée depuis l'intérieur du contrôleur

Bien que fonctionnelle, cette approche n'est pas franchement efficace car il n'est
pas réellement possible de modifier des quantités importantes de données. Par ailleurs,
la destruction du conteneur entraînera automatiquement la perte des modifications
opérées.

5.2.2 Créer un volume

Les volumes' sont le moyen qu'offre Docker pour gérer la persistance des données au
sein des conteneurs (et en relation avec leur machine h ôte).
Comme nous l'avo ns vu précédemment, la page d'accueil du serveur web Nginx
l:J se trouve dans le répertoire /usr/share/nginx/html/[Link]. Définissons un volume
0
c ~
,., correspondant à ce chemin à l'aide du paramètre -v de la commande run .
::J
"O
0 c::;
\.0
.-t
0
N
.,.,
~
1 $ docker run -p 8000 :80 --name webserver -d -v / usr/share/nginx/ html ng i nx
'~
@ ·c
....... B::;
..c: CO
Attention, si vous n'avez pas supprimé le conteneur webserver créé dans le
Ol c
ï:::: 0
>- c paragraphe précédent, vous noterez que la tentative d'en créer un nouveau (avec
o.. c
u
0 ·3
<.)
le même nom) se solde par une erreur « Error response from daemon: Conflict. The
::;
"O
0
.....
name "webserver" is already in use by container ... You have ta remove (or rename) that
c.
~ container ta be able ta reuse that name. »
~
::;
rS
1
"O
0
c
8
(Ç) 1. Veui llez-vous reporter au chapitre l pour une explication du concept de volume de conteneur.
Chapitre 5. Conteneurs et images

Pour comprendre le résultat de cette action , nous allons inspecter le conteneur


ainsi créé. La commande i nspect permet d 'obtenir une structure JSO N 1 décrivan t le
con teneur et sa configuration.

1 $ docker i nspect webserver

Au sein de la structure retournée par la commande i nspect, nous pouvons


notamment iden t ifier la section suivante :

"Mounts ": [
{
"N ame ":
"c29b645f024f59988c24dbb0564a6f893da5lbl7ccd687dfbf794ef4143c48f5 " ,
"Sou rce" : "/var/ l i b/docker/volumes
/c29b645f024f59988c 24dbb0564a6f89 3d a5lbl 7ccd687d fbf 794ef4143c48f5/_data " .
"Des t i nation " : "/ usr/share/ngi nx/ html ",
"Driver" : "loca l ",
11
Mode 11
:
1111
,

"RW ": tr ue

C elle-ci nous donne plusieurs informations résumées dans le tableau ci-dessous.


Paramètre Description
Name Un identifiant unique pour cette structure <UUID>.
Source Le chemin sur le système de fichiers de la machine hôte contenant
les données correspondant au volume.
Destination Le chemin à l'intérieur du conteneur.
Driver Comme nous le verrons par la suite, il est possible d'utiliser
plusieurs drivers pour la gestion des volumes en offrant un
stockage des données via différents systèmes <pas uniquement
sur le système hôte).
Dans notre cas, le driver utilisé est celui par défaut nommé
« local ». Les données sont stockées sur l'hôte dans le répertoire

"'Cl
identifié par le paramètre Source.
0
c RW Indique que le volume (à l'intérieur du conteneur) est reod-write
:::i
0 (il peut être lu et modifié).
\.0
.-t Si no us n ous plaçons dan s le répertoire obtenu via la commande i nspe ct , nous
0
N constatons effectivement qu'il contient le fic hier [Link] que nous avions trouvé
@
.......
précédemment dans le réperto ire /usr/share/ngi,nx/html à l'intérieur du conteneur.
..c
O'l
'i:
>-
0. $ sudo ls /var/ l i b/doc ker/volumes
0
u /c29b645f024f 59988c24dbb0564a6f893da5 lbl7ccd687d fbf 794ef4143c48f5/_data
1 50x .h t ml i ndex . html

l. [Link]
5.2 Accéder au conteneur et modifier ses données -----------------11071
Attention, notez que nous sommes contraints d'utiliser la commande sudo pour
disposer des droits root. Caccès au système de fichiers Docker n'est évidemment pas
accordé sans ce niveau de privilège.

Un accès à l'URL [Link] nous confirme que le serveur web tourne


bien correctement et affiche l'habituelle page d'accueil standard de Nginx.
Nous a llons maintenant l'éditer pour vérifier si cette modification est prise en
compte par le conteneur. Encore une fois, nous devons recourir à des privilèges étendus.
N'oubliez pas d'exécuter la commande exi t pour revenir à l'utilisateur vagrant.

$ sudo su
$ ec ho "J e modif i e un vol ume " > /va r / l ib/docker/vol ume s
/6ld5 b52ba3385203910 dd8237700de02056 a40a23a f 3le3b5b62d95 f 63117d06/ data /index. html
1 $ exit

Le résultat peut une fois de plus être visualisé à l'aide de notre navigateur web.

M ozilla Firefox Cl )(

[Link] :8 0 00/ )( l +
+ Localhost 8000 v(! I » --
Je modifie un vo lume
Figure 5.4 - Home page de Nginx modifiée sur l'hôte

C ette méthode présente néanmoins des inconvénients majeurs :


• il est nécessaire de disposer de privilèges étendus pour accéder aux données et
pour les modifier ;
"'Cl
0 • la destruction/recréation du conteneur entraînera l'allocation d'un nouveau
c
:::i
~
,.,
0 "O volume différent et les modification s opérées seront perdues.
[Link];
\.0
.-t ~
0 V
N V
'ii En réalité Docker n'efface jamais le contenu du répertoire /var/lib/docker/volumes/,
@ ·c
B même lorsque les conteneurs sont détruits. Par conséquent, la création d'un nouveau
....... :::;
..c
O'l
CO
c
conteneur à partir de la même image entraînera la création d'un autre volume .
0
ï:::::
>- c Le volume précédent restera orphelin jusqu'à ce qu'il soit effacé explicitement
o. c
0 ·3ù (manuellement ou par un script écrit à cet effet).
u :::;
"O
0
.... S i on considère que dans de n ombreuses architectures les conteneurs ont pour
c.
~
~ vocation d'être éphémères et, autant que possible, san s état propre , on pourrait
:::;
rS penser que l'intérêt de ce type de volumes locaux est limité. N ous verrons dans la
1
"O
0
troisièm e partie de cet ouvrage qu'il est possible à p lusieurs conteneurs de référen cer
c
8 les mêmes volumes, ce qui permet dans une large mesure de s'abstraire des contraintes
(Ç) d'implémentation de ceux-ci.
Chapitre 5. Conteneurs et images

5.2.3 Monter un répertoire de notre hôte dans un conteneur

Il est possible, à la place du driver local de Docker, de mon ter un répertoire de l'hôte
dans le conteneu r. N ous allons en premier lieu créer ce réperto ire dans l'espace de
travail de l'utilisateur vagrant.

1 $ mkdi r -p / home/vag rant/workdir/c ha pi t re5

La syntaxe de c réation du volume est la suivante :

$ doc ker r un -p 8000 :80 --n ame webs erver -d -v


1 /home/vagrant /wo rkdir/c hapit re5 : /u s r/ share/ ngin x/ html nginx

Encore une fois, pensez à vérifier à l'aide de la commande docker ps - a que vous
n'avez pas de conteneur existant qui porte déjà le nom « webserver » ou qui écoute
sur le mê me port 8000. Si c'est le cas (ça devrait l'être si vous avez suivi les exercices
précédents pas à pas), pensez à supprimer ce conteneur à l'aide des commandes
st op puis rm.

La syntaxe est relativement intuitive :


-v <Réperto ire de l'hôte>:<Répertoire à l'intérieur du conteneur>
Il ne s'agit ni plus ni mo ins que d'un mount Unix.
Regardons notre navigateur pour voir ce que la page d'accueil affiche.

40 3 Forbidden - M ozilla Firefox c )(

.../ 403 Forbidden )( +


l:J
0
~' \t Localhost.8000 V el )) --
c
::J
0
\.0
.-t
0
N
4 03 Forbi dden
@
.......
..c:
O'l
·;:: ngin x/1.9.9
>-
0..
0
u Figure 5.5 - Montage d'un répertoire vide

Le résultat est inattendu, si on le compare avec le comportement des volumes


locaux, et pourtant il est parfaitement logique. C e que nous avons créé à l'aide de
la commande précédente, c'est un mount d'un réperto ire de l'hôte dans le conteneur.
Malheure usement, ce répertoire ne contenait aucun fichier [Link] à afficher.
5.2 Accéder au conteneur et modifier ses données -----------------11091
$ cd /home/vagra nt/workdir/chapi tre5
1 $ echo "Un f i ch i er sur l e host " > [Link]
La commande précédente crée un fichier [Link] sommaire dans notre réper-
to ire et le résultat est immédiat.

Mozilla Firefox c )(

[Link] 8000/ )( +
~) Localhost 8000 V ~1 )) --
Un fi chier su r le hast

Figure 5.6 - Montage d'un répertoire contenant un fichier [Link]

Notez qu'il est possible de faire un montage en lecture-seule du point de vue du


conteneur (c'est-à-dire que le conteneur ne pourra pas modifier ces données). Pour
ce faire, il faut ajouter à la syntaxe de définition d'un volume le suffixe : ro.

5.2.4 La configuration des ports IP


Depuis le début de ce chapitre, n ous créons des conteneurs qui offrent un service sur
le port 8000 de l'hôte à l'aide du paramètre - p 8000 : 80. Comment la gestion des ports
fonctionne-t-elle avec Docker ?

1 $ docker run -d -p 8000 :80 -- name webserver ng i nx

Faisons une inspection de la configuration du conteneur.


l:J
0
c
::J
~
,.,
"O
1 $ docker in spect webserver
0 c::;
\.0
.-t .,.,
~ La structure )SO N retournée contient la section suivante :
0
N
'~
@ ·c
....... B::; "Port s" : 1
..c: CO
Ol c
0
"443 /tcp ": nul l .
ï:::: c
>- c
"80/tcp ": [
o..
u
0 ·3
<.)
1
::;
"O
"Hostlp ": "[Link]",
0
.....
c. "Hos t Port" : "8000 "
~
~
::;
rS
1
"O
0
c
8 C ette structure n ous indique que le conteneur que nous avons créé déclare en fait
(Ç) deux ports T C P :
Chapitre 5. Conteneurs et images

• le port 80 qui correspond à HTTP ;


• le port 443 qui correspond à la version sécurisée HTTPS.

Pourtant seul le port 80 est accessible au niveau de l'hôte et, comme nous l'avons
indiqué, il est mappé sur le port 8000.

Nous reviendrons plus en détail sur les problématiques de réseau et sur l'adresse
IP associée ici au port exposé : [Link] 1• À ce stade, notez seulement qu'il s'agit de
l'adresse par défaut à laquelle Docker attache le port ainsi ouvert sur l'hôte.

Notez qu'il est possible de laisser Docker choisir le port de l'hôte.

$ docker rm -f webserver
$ docker run -P --n ame webserver -d ngi nx
$ docker ps
CONTAI NER ID IMAG E COMMA ND CREA TE D
97066be7 b321 nginx "n ginx -g 'daemon off " 4 minutes ago
STATUS PORTS NAM ES
Up 3 minutes 0. 0. 0. 0:32769->80/tcp. 0. 0. 0.0:32768 ->443 /tcp webserver

Lors que le paramètre - P est utilisé, Docker va associer les ports du conteneur avec
les ports disponibles sur l'hôte (choisis au hasard).
Dans le cas ci~dessus, le port 80 est associé au port 32769 de l'hôte.

5.3 CONSTRUIRE UNE IMAGE DOCKER ORIGINALE


Nous avons jusqu'à maintenant abordé rapidement les différents aspects de la gestion
des conteneurs. Au cours de cette présentation, nous avons volontairement passé sous
silence un certain nombre d'éléments. Le lecteur curieux aura, par exemple, noté
en lançant une commande i nspect sur l'un de nos conteneurs Nginx que certaines
l:J
0
c
configurations semblaient être prédéfinies :
::J
0 • Qui a défini que le conteneur pouvait gérer les ports 80 et 443 ?
\.0
.-t
0 • Qui a défini le volume /var/cache/nginx qui est par défaut présent ?
N
@
.......
Ces paramètres sont apportés par l'image nginx .
..c:
O'l
·;:: Nous allons maintenant étudier la création d'images. Dans cette première section
>-
0..
0
consacrée aux images, nous n'allons pas aborder la manière canonique de procéder,
u mais plutôt étudier ce qu'est une image et comment la créer manuellement. Une fois
ces connaissances acquises, nous étudierons l'un des apports majeurs de Docker, qui
représente la manière aujourd'hui usuelle de création d'images: le Dockerfile.

l. La notion d'adresse "[Link]" par rapport à" 127.0.0. l " est expliquée dans le chapitre 3 ( § 3.2.3 ).
5.3 Construire une image Docker originale --------------------8
5.3.1 Lister les images

Avant de nous intéresser à la création de nouvelles images, étudions quelques


instruc tions qui permettent de les manipuler.
En premier lieu, nous allons liste r les images présentes sur notre machine h ôte à
l'aide de l'instruction docker i mages :

$ docker images
RE POSITORY TAG IMAGE ID CREATED
ng i nx l at es t 5328fdf e9b8e 3 wee ks ago
VIRTUA L SI ZE
133 .8 MB

C omme vous po uvez le constater, notre image nginx est bien là.
Si vous ajoutez le paramètre - a (pour all) à cette commande, vous constatez que la
liste est net tement plus longue :

$ docker images -a
RE POS ITORY TAG IMAGE ID CREATED
VIRTUA L SI ZE
ng i nx l at es t 5328f df e9 b8e 3 wee ks ago
133. 8 MB
<none> <none> f608475c6c65 3 weeks ago
133 .8 MB
<none> <none> l b6c0 a20b353 3 weeks ago
133 .8 MB
<none> <none> 21656 a3c l256 3 weeks ago
133.8 MB
<none> <none> Oe07123e6531 3 weeks ago
133 .8 MB
<none> <none> 2e518e3d3f ad 3 weeks ago
133 .8 MB
<none> <none> 1526247f349d 3 weeks ago
125. l MB
l:J
<none> <none> f5bbldddc876 5 weeks ago
0 125.1 MB
c ~
,.,
:J
"O
<none> <none> d65968cl aa44 5 weeks ago
0 c::;
\.0
125.1 MB
.-t
0
.,.,
~ <none> <none> 62df5e17dafa 5 weeks ago
N
'~
125. 1 MB
@ ·c <none> <none> 23cb15büfcec 5 weeks ago
....... B
..c:
::;
CO 125 .1 MB
Ol c <none> <none> 9ee13ca3b908 5 weeks ago
ï:::: 0
>- c
o.. c 125.1 MB
u
0 ·3
<.)
::;
"O
0
Mais d'où viennent ces images qui n'ont pas de nom, mais uniquement un U UID ?
.....
c.
~ S i vous lisez attentivement la section « C réer et démarrer un conteneur », vous
~
::;
remarquez que les mêmes identifiants étaient présents lors du chargement de l'image
rS
"O
1 ( lors de la création de notre premier conteneur) .
0
c
8 C es images sans n om sont ce que l'on appelle des images interméd iaires. Elles
(Ç) correspondent aux couches dont une image est constituée (voir le chapitre 1). Nous
Chapitre 5. Conteneurs et images

verrons plus tard comment ces images intermédiaires sont utilisées lors de la création
d 'une n ouvelle image.

5.3.2 Charger et effacer des images

Effaçons notre image nginx avec la commande docke r rmi (à ne pas confondre avec
docker rmqui, comme nous l'avons déjà vu, est réservé aux conteneurs) :

1 $ docker rmi ngi nx

Comme pour les conteneurs, nous pouvons indifféremment utiliser le nom de


l'image ou son UUID (53 28fdfe9b8e).
Si vous avez encore un conteneur n ginx (actif ou inactif), vous risquez de voir
apparaître le message d'erreur suivan t :

Er ror respo nse f rom daemon : conflict : unable to remove repos i to ry ref erence
"ngi nx " (mus t force) - cont ainer 050e5c55 7d8a is usi ng its refe r enced image
5328fdf e9b8e
1 Error : failed to remove images : [nginx ]

Il n'est en effet pas possible de supprimer une image pour laquelle des conteneurs
sont encore présents. Si l'on se souvient de la structure en couches des conteneurs, on
comprend que cela n'aurait effectivement pas de sens. Il vous faut donc détruire tous
les conteneurs.

Le client du Docker Engine ne propose pas de commande pour détruire plusieurs


conteneurs en une seule fois. Inutile d'essayer les « * » ou autres jokers. L'astuce
habituelle consiste à utiliser la commande docker rm - f $(docker ps -a -q) qui va
arrêter tous les conteneurs et les effacer. À utiliser évidemment avec prudence.
l:J
0
c
::J Une fois l'image effacée, nous pouvons la rech arger en utilisant le Docker Hub.
0
\.0 N o tez que le téléch argement de l'image sera automatique lors de la création d'un
.-t
0 conteneur (si l'image n'est pas présente localement). Il est parfois cependant ut ile de
N
@ pouvoir manipuler directemen t les images.
.......
..c: Jusqu'à maintenant nous avons utilisé l'image Nginx. C ertains auront probable,
O'l
·;::
>- ment remarqué que nous n'avons pas précisé de numéro de version. Par défaut, lorsque
0..
0 rien n 'est précisé, c'est la version la plus récente de l'image qui est chargée, d'où le
u
statut en fin de chargement :

1 St atus : Downl oaded newer image fo r ngi nx : la t est

N ous allons volontairemen t charger l'image de version (ou plus communément de


tag ) l. 7 de Nginx.
5.3 Construire une im age Docker originale --------------------8
OFFICIAL REPOSITORY

nginx i::l

Repo rito i!_Î"9'_i;

Tag Name Size Docker Pull Command

docker pull nginx


1.9.9 55MB

55MB

55MB

letest 55MB

Figure 5.7 - Tags de l'image officielle nginx sur le Docker Hub

Reportez-vous au chapitre 2 pour savoir comment naviguer au sein du Docker Hub


et lister les tags disponibles pour une image. N otez, comme nous le verrons par la
suite, qu'il est aussi possible d'interroger le Docker Hub par l'intermédiaire d'une
API REST.

$docker pull ngi nx : l. 7


1. 7: Pu l l i ng f rom l i br ary/ng i nx
91408b29417e : Pull comp l ete
ld57bb32d3b4 : Pul l complete
e6c41bfl9dd4 : Pu ll comp 1ete
16b4b2 a 3620a : Pu 11 comp l ete
b643082c0754 : Pull comp l ete
575 577 12fa86 : Pu ll comp l et e
249130facle4 : Pull comp l ete
23299622ed29 : Pu11 comp l ete
7abe60 a22 c0d : Pul l complet e
fea 4feb4d44b : Pull comp l et e
"'Cl
0 lb03d3f2a77e : Pul l comp l ete
c
:::i
~
,., 5109569c0fed : Pull comp l ete
"O
0 [Link]; Di gest :
\.0
.-t ~ sha256 : 02 537b932a849103ab21c7 5fac2 5c0de622ca 12fe2c5ba8af2c7cb23339ee6d4
0 V
N V Status : Down l oaded newer i mag e for ng i nx : l . 7
'ii
@ ·c
....... [Link];
..c CO C ela n 'est pas aussi compliqué qu'il y paraît: il suffit de suffixer le nom de l'image
O'l c
0
ï:::::
>- c avec le tag que vous souhaitez télécharger grâce à la commande pu 11, soit « nginx:1.7 »
o. c
0 ·3ù pour le tag 1. 7.
u :::;
"O
0
.... Créons maintenant un conteneur à partir de cette image :
c.
~
~
:::;
rS
1
1 $ docker r un -p 8000 :80 -- name webserver17 -d ngi nx : l . 7
"O
0
c
8 Ouvrez maintenant un navigateur et entrez l'URL suivante : [Link]
(Ç) En effet, Nginx, par défau t, affi che son numéro de version sur les pages d'erreur 404.
Chapitre 5. Conteneurs et images

404 Not Found - Mozilla Firefox c )(

Docker Hub X 4 0 4 N ot Found )( +


Localhos t· 8000/ V cl ))

404 Not Found


ngin x/ 1 .7 .12

Figure 5.8 - Conteneur avec Nginx en version 1.7

Maintenant, créons une image avec la dernière version (latest) de Nginx, comme
nous l'avons déjà fait précédemment :

1 $ doc ke r run -p 8001: 80 --n ame webs er ver l9 -d ngi nx

Attention à ne pas utiliser le même port TCP que pour notre conteneur webser,
ver1 7, afin d'éviter un message d'erreur déplaisant.

Ouvrez maintenant un navigateur et entrez l'URL suivante, [Link]


pour constater que la version de N ginx est bien la dernière (dans notre cas la 1.9). Il
n'y a pas d'obstacle particulier au fait d'avo ir deux versions de la même image à un
même instant sur le même système.

5.3.3 Créer une image à partir d'un conteneur

Maintenant que nous avons vu comment obtenir une image depuis le Hub, voyons
l:l
0 comment en créer une qui nous convienne et intègre des modifications par rapport à
c
:::i une image de base.
0
\.0
.--t
Créons donc un conteneur nginx :
0
N
@
.......
..c
1 $ doc ke r r un -p 8000: 80 -- name webser ver -d ngi nx
O'l
'i:
>- C omme nous l'avons fait dans la section 5.2, ouvrons un terminal sur le conteneur
0.
0 pour modifier la page d 'accueil de Nginx :
u

$ doc ker exec -i -t webserver /bi n/bas h


root@7d4f688992b0 : /# ech o "Hel l o world " > / usr/sha re /ngi nx/ html / i ndex . html
1 root@7d4f 688992b0 : /# ex i t

À partir de ce conteneur, nous pouvons créer une image en utilisant la commande


commi t .
5.4 Le D ockerfile ----------------------------8
$docker commit webserver ngi nxhe ll o
908a3cb565656 bca615367b5009ba8d l 7ddaad bd24fa77cfbb4 bbfcf4c336227
$ docker images
REPOS ITORY TAG IMAGE ID CREATED VIRTUA L SIZE
nginxhello latest 908a3cb56 565 3 seconds ago 133 .8 MB
ng inx latest 5328fdfe9b8e 3 wee ks aga 133 .8 MB
ngi nx 1.7 5109569c0fed 8 months aga 93 .4 MB

N ous venons de créer une nouvelle image « nginxhello », à partir de laquelle nous
pouvons maintenant créer de nouveaux conteneurs, par exemple :

1 $docker run -p 8001 :80 - -name webserverhel l o -d ngi nxhello

Un accès à l'URL [Link] montrera que la page d'accueil de N ginx


dans cette image est bien modifiée. N ous avons donc créé une variante de l'image
nginx à partir d'un conteneur existan t (qui lui-même s'appuie sur l'image nginx ).

M ozilla Firefox c )(

Docker Hub X ' [Link] )( 1 +


+ localhost:8001 V el )) --
Hello wo rld

Figure 5.9 - Conteneur créé à partir de l'image« nginxhello »

Cette technique de création d'image, bien que fonctionnelle, n'est utilisée que
pour des besoins de debugging, comme nous le verrons dans la prochaine section. On
lui préfère la création d'image à partir de Dockerfile.

"'Cl
0
c ~
,.,
0
:::i
"O 5.4 LE DOCKERFILE
[Link];
\.0
.-t ~
0 V
N V Le Dockerfile est probablemen t l'une des raisons du succès de Docker dans le domaine
'ii
@ ·c des conteneurs. Voyons en pratique ce dont il s'agit.
....... [Link];
..c CO
O'l c
0
ï::::: c
>-
o. c 5.4.1 Les risques d'une création d'image par commit
u
0 ·3ù
:::;
"O
0
.... Dans ce chapitre, nous avons créé un conteneur N ginx dont nous avons ch angé la
c.
~ page par défaut ([Link]). Nous avons vu une technique pour créer un conteneur
~
:::;
à l'aide de la commande commit, c'est-à-dire en sauvegardant l'état d 'un conten eur
rS
1 précédemmen t créé à partir d'une image de base, puis modifié manuellement.
"O
0
c
8 Le défaut de cette technique réside dans la documentation du processus de création
(Ç) de l'image. Il est possible de distribuer cette image de conteneur web, mais la recette
Chapitre 5. Conteneurs et images

pour le créer n'est pas n ormalisée. O n pourrait certes la documenter, mais rien n e
permettrait d'avoir l'assuran ce que l'image a insi produite soit bien la résultante de
la séquen ce d 'instructions documentées. En cla ir, quelqu'un pourrait avoir exécuté
d'autres commandes (non documentées) pour créer cette image et il ne serait pas
possible de prévoir les con séquen ces de son usage.
C'est justement le propos des Dockerfile : décrire la création d'images de manière
forme lle.

5.4.2 Programmer la création des images

Dans cette section n ous allons programmer un [Link] réalisant la création d'un
con ten eur ayant les mêmes caracté ristiques que notre exemp le Nginx.
En premier lieu, créez un réperto ire vide.
Dans ce répertoire, n ous allons mettre deux fichiers :
• un fichier Dockerfile ;
• un [Link] [Link].

Dans ce dernier [Link], nous allons écrire le texte suivant (par exemple, à l'aide de
l'éditeur v i) :

1 Un f ichier qui di t "Hello "

Éditons mainten ant le contenu du [Link] [Link] :

FROM ngi nx: l.7


1 COPY index. html /usr/share/ nginx/ html /index . ht ml
l:J
0
c Nous en expliquerons le contenu par la suite.
:J
0
\.0 Nous a llons mainten ant créer notre image « n ginxh e llo » à l'aide de ce [Link]
.-t
0
N
Dockerfile et de la commande bui l d :
@
.......
..c:
O'l $ docker bui l d -t ngi nxhell o .
·;::
>- Send i ng build co ntext to Doc ke r daemon 3.072 kB
0..
0 Step 1 : FROM ng i nx :l .7
u --- > d5acedd7e96a
St ep 2 : COPY i ndex . html /us r /share/ ngin x/html /i ndex .html
---> a8f 7c2454f7f
Removing i ntermed i ate conta i ner 4954cbl b74a7
Succes sf ully built a8f7c2454f 7f
5.4 Le D ockerfile ----------------------------8
Si nous lançons la commande docker ima ge s, nous voyons qu'une image a bien
été créée il y a q uelques instants :

$ docker images
RE POSITORY TAG IMAGE ID CREATED
SIZE
nginxhello l atest a8f7c2 454f7 f About a mi nute ago
93 .4 MB
<none> <none> cc0b89 24 5d0d 15 min utes ago
93 .4 MB
<none> <none> e3d6892f8073 3 months ago
133 .8 MB
ngi nx la t est 4045d5284714 4 months ago
133 .8 MB
ngi nx 1. 7 d5acedd7e96a 12 mon ths ago
93 .4 MB

Créons maintenant un conteneur à partir de cette image :

1 $ docker run -p 8000 :80 --name webserver -d ng i nxhello

Un accès à l'URL [Link] ost:8000 nous confirme que notre serveur web est
actif et que sa page par défaut correspond bien au texte que nous avions mis dans le
fichier [Link].
N ous venons de créer notre premier Dockerfile et, grâce à celui-ci, nous pouvons :
• créer une image permettant de produire des conteneurs N ginx modifiés à loisir ;
• distribuer la recette pour fabriquer cette image.

5.4.3 Quelques explications


"'Cl
0
c
:::i
~
,., Penchons-nous maintenant sur les quelques instructions que nous avons utilisées dans
"O
0 [Link]; ce fi chier Docker.
\.0
.-t ~
0 V
N V
'ii
@ ·c
B
1 FROM ng i nx :l .7
....... :::;
..c CO
O'l c
0
ï::::: c
>-
o. c C ette première commande indique à Docker que nous souhaitons créer une image
u
0 ·3ù à partir de l'image de base nginx en version 1. 7. Il ne s'agit ni plus ni mo ins que
:::;
"O
0
....
d'une fonction d'héritage. Elle permet de ne pas avoir à recréer la recette qui a permis
c.
~ l'installation de Nginx.
~
:::;
rS Cette recette est d'ailleurs publiquement disponible puisque les Dockerfile des
1
"O
0
images sont publiés sur la partie publique du Docker Hub :
c
8
(Ç)
Chapitre 5. Conteneurs et images

Full Description

Supported tags and respective


Dockerfile links
• latest 1 1. 9 , 1. 9 .15 (memlme/jesSJe/Dockerti/e)
• stabl e 1 .10 1.10 . 0 1stable/jeSSJefDockerf1/e)
• mainl i ne-alpine a lpine 1 -alpi ne 1. 9-al pi ne 1 .9. 1 5-alpine
(mamlme/alpme/Dockertile)
• stable-alpi ne 1. 10-al pine 1.10. 0 -alpine (slable/alpme/Dockerti/e)

ImageLayers.10 183 MB J 8 Layers

Figure 5.10 - Lien vers le Dockerfile de l'image de base nginx sur le Docker Hub

En voici d'ailleurs le contenu pour sa version 1.9.15-1:

FROM deb i an : jessi e


MAINTA INER Nginx Docker Maintainers "docker -ma i nt@nginx . com"
ENV Nginx_VERSION 1.9 .15 -1-jessie
RUN apt - key adv -- keyserver hkp://pgp .mi t .edu :80 -- recv - keys
573B FD6B3D8 FBC641079A6ABAB F5BD827BD9BF62 \
&& echo "deb http : //ng in [Link]/packages/main l ine/debian/ j ess i e nginx" >>
/etc/apt/sources . l is t \
&& apt -get update \
&& apt -get in stall -- no-i ns t all- recommends -- no-i nsta ll- suggests -y\
ca -certi f i cates \
ng in x=$ {Ng inx_VERS ION } \
ng inx -module -xslt \
ng in x-module-geo i p \
ng inx -module-image- fil ter \
ngin x-module -perl \
ng in x-module -njs \
gettext -base \
l:J
&& rm - rf /var/ li b/apt/ l i st s/ *
0
c
# f orward request and error l ogs to doc ker l og co l lector
::J RUN ln -s f /dev/s t dout /var/log/nginx/access . l og \
0 && ln -sf /dev/stderr /var/log/ngi nx / error .l og
\.0
.-t EXPOSE 80 443
0
N CMD [" nginx ", "-g", "daemon off :" ]
@
.......
..c:
O'l
·;::
À nouveau, nous notons que ce Dockerfile hérite lui-même de « debian:jessie »
>-
0..
qui n'est autre qu'une version de l'image de base de la distribution Linux Debian.
0
u La seconde instruction indique à Docker qu'il faut, lors de la création de l'image,
remplacer le [Link] [Link] par défaut de Nginx (localisé comme nous l'avons vu
auparavant dans /usr/share/nginx/html/[Link]) par le [Link] que nous avions posé
dans notre répertoire.

1 COPY index . html / usr/s hare/nginx/html / index . html


5.4 Le Dockerfile ----------------------------8
Cette de rnière instructio n est l'application de la notio n d'images en couches que
nous avons abordée dans le chapitre 1. Elle ne modifie pas l'image de base nginx mais
ajoute notre [Link] par-dessus, et via le concept d'union [Link] system (UFS), le système
de fichiers résultant prend en compte notre fichier au lieu du fichier original.
La preuve est d'ailleurs visible lors de la création de notre image. Chaque étape de
création (c'est-à-dire chaque ligne d'instruction) correspond à une couche.
Rappelons-nous de la première étape (Step 1) :

$ docker build -t ng in xhe llo .


Sending buil d cont ext t o Doc ker daemon 3.072 kB
Step 1 : FROM nginx : l .7
---> d5acedd7e96a

Notez l'identifiant de cette couche : d5ac edd 7e96a. N ous l'avons déjà vu aupara-
vant car il s'agit de celui de l'image de base n ginx en version 1.7:

$docke r images
REPOS ITORY TAG IMAG E ID CREATED
SIZE
ngi nx 1. 7 d5acedd7e96a 12 months ago
93 .4 MB

N otre image finale est donc constituée d'une série d'images qui peuvent être soit
complètement originales, soit h éritées d'une image existante par l'intermédiaire de
l'instruction FROM .
Il est d'ailleurs possible de visualiser l'ensemble des couches d'une image donnée
grâce la commande doc ke r hi story :

$ docker history ng i nxhell o


IMAGE CREATED CREATED BY
l:J SIZE COMMENT
0
c ~
,., a8f7c2454f7 f 2 days aga /bin/sh -c #(nop) CO PY
::J
0 -0 fi l e :l378a5a0clfa30fe5 27 B
c::; /bin/ sh -c #(nopl CMD [ "n ginx " g
\.0 d5acedd7e96a 12 months ago Il - Il

.-t
0
.,.,
~
"daemon o 0 B
N
'~ abdbd9163c9b 12 months ago /bin/sh -c #(nop) EX POSE 443/tcp
@ ·c
B 80/tcp 0 B
....... ::;
..c: CO e5 51 fl54c24f 12 months ago /bin/ sh -c #(nopl VO LUME
O'l c
·;:: 0
c [/var/cac he/ng i nx] 0 B
>- c a33 f3c9e flc 4 12 months ago /bin/sh -c ln -sf /dev/stderr
o..
u
0 ·3
<.) /var/l og/ngi nx/ 0 B
::;
-0
0 bl ce25f2cd9c 12 months ago /bin/sh -c ln -sf /dev/stdout
.....
c.
~
/var/l og/ngi nx / 0 B
~ 3c5fee6e68b3 12 months ago /bin/sh -c apt- get upda te &&
::;
rS apt -get i nst 8 .38 MB
1 4446b7f2ac03 12 mont hs ago /b in /sh -c #( nop ) ENV
-0
0
c Ngi nx_VERSION=l.7 .1 2-1- 0 B
8 e97439968948 12 months aga /bin/sh -c ec ho "deb
(Ç) http : //n gi [Link]/package 221 B
Chapitre 5. Conteneurs et images

acca21866ee7 12 mant hs aga / bi n/s h -c apt - key adv -- keyserver


pgp .mit . ed 58 .45 kB
6d f c7 b45c331 12 mant hs aga / bin/s h -c #(nap) MA INTA INER Ngin x
Doc ker Mai 0 B
325520a5db fd 12 mant hs aga / bi n/s h -c #(napJ CMD [ "/ bi n/bash "J
0 B
358523180737 12 mont hs ago / bin/s h -c #(nop) AOD
f il e :20cd6318f68d34ca8e 84. 96 MB

Là encore, vous remarquerez l'image a8f7 c 2454f7 f qui correspond à notre instruc~
tion copy. Si vous vous reportez au journal (log) de l'instruction docke r bui l d, un peu
plus haut, vous verrez que l'identifiant correspond.

En résumé
Nous avons vu dans ce chapitre ce qu'était un conteneur en pratique : comment le
créer, le supprimer, le démarrer et l'arrêter. Nous avons vu que les conteneurs étaient
produits à partir de moules que représentent les images. Nous avons enfin étudié
comment créer de nouvelles images qui intègrent des spécificités par rapport à des
images de base téléchargées d'habitude depuis le Docker Hub. Nous nous sommes
aussi penchés sommairement sur la notion de Dockerfile.
À l'issue de ce chapitre, vous maîtrisez les concepts et commandes fondamentaux
du moteur Docker. Il est temps de monter en puissance et de mettre en pratique ces
connaissances à travers des exemples de plus en plus complexes.

l:J
0
c
:J
0
\.0
.-t
0
N
@
.......
..c:
Ol
·;::
>-
0..
0
u
....
TROISIEME PARTIE

Apprendre Docker

Cette troisième partie, qui peut aussi servir de référence, vise à expliquer en détail, à
travers des exemples pratiques :
• les commandes du client Docker ;
• les instructions des Dockerfile que nous avons commencé d'étudier dans le
dernier chapitre de la précédente partie.

Nous avons choisi de découper cette partie en trois chapitres qui peuvent être lus
de manière no n séquentielle :
• le chapitre 6 montre l'usage des commandes principales du client Docker.
L'objectif ici n'est pas d'être exhaustif, mais de montrer et d'expliquer les
l:J
0 commandes essentielles (celles dont on se sert tous les jours) à travers des
c
:J
~
,.,
0 "O exemples utiles ;
c::;
\.0
.-t .,.,
~ • le chapitre 7 est consacré aux principales instructions des Dockerfile, c'est-à-dire
0
N
'~
celles qui sont présentes dans 95 % des fichiers Dockerfî.le que vous aurez à lire ;
@ ·c
....... B::;
• le chapitre 8 se penche, quant à lui, sur des commandes et instructions
..c: CO
Ol c Dockerfî.le plus avancées.
ï:::: 0
>- c
o.. c
0 ·3 Chacun de ces chapitres peut être lu individuellement. Des références croisées
u <.)
::;
"O
0
permettent de passer d'un chapitre à l'autre pour acquérir progressivement la maîtrise
.....
c. de Docker.
~
~
::;
Nous conseillons cependant de lire les chapitres dans leur ordre naturel en
rS
"O
1
commençant par le chapitre 6.
0
c
8
(Ç)
"'O
0
c:
:::i
0
\.0
r-1
0
N
@
......,
..c:
en
·;::
>-
0..
0
u
6
Prise en main
du client Docker

Dans ce chapitre, nous vous présenterons les commandes usuelles du client Docker
et leurs options les plus importantes.
À travers les différe nts chapitres précéd en ts, n ous avon s déjà abordé certaines de ces
commandes. Notre objectif ici est d'en présenter quelques autres par l'intermédiaire
d'exemples simples e t ciblés.
Le but de ce chapitre est de faire atteindre au lecteur un bon niveau de maîtrise de
cette ligne de commande que nous utiliserons intensivement dans la suite de ce livre.

l:J
0
c
::J
~
.
., 6.1 INTRODUCTION À LA CLl 1 DOCKER
"O
0 c::;
\.0
.-t
0
.,.,
~ Dans ce premier paragraphe, n ous allons donner quelques informations complémen~
N
·~ taires sur le clie nt Docker, à savoir :
@ ·c
B
.......
..c:
::;
CO
• les variables d 'en vironnement qu'il utilise (et qui permettent d'en modifier la
Ol c
ï:::: 0
c configuration) ;
>- c
o.. • la structure génériq ue des options des différents outils Docker.
u
0 ·3
<.)
::;
"O
0
.....
c.
~
~
::;
rS
1
"O
0
c
8
(Ç) 1. Command Line In terface= la ligne de commande
J 1241 - - - - - - - - - - - - - - - - - - - - Chapitre 6. Prise en main du client Docker

6.1.1 Les variables d'environnement Docker

La ligne de commande Docker, qui permet l'exécution des commandes Docker, utilise
un certain nombre de variables d'environnement. En modifiant ces dernières, le
comportement des commandes Docker est affecté. Le tableau 6.1 décrit de manière
exhaustive les variables d'environnement Docker. Nous verrons ensuite un exemple
illustrant l'impact fonctionnel d'une telle variable.

Tableau 6.1 - Variables d'environnement Docker


Nom Définition
DOCKER_API_VERSION La version de l'API Docker à utiliser.
DOCKER_ CON FIG L'emplacement des fichiers de configuration
Docker.
DOCKER_ CERT_PATH L'emplacement des certificats liés à
l'authentification.
DOCKER_DRIVER Le pilote graphique à utiliser.
DOCKER_HOST Le démon Docker à utiliser.
DOCKER_NOWARN_KERNEL_VERSION Si le paramètre est activé, cela empêche l'affi-
chage d'avertissements liés au fait que la version
du noyau Linux n'est pas compatible avec
Docker.
DOCKER_RAMDISK Si le paramètre est activé, alors Docker fonc-
tionne avec un utilisateur en mémoire RAM
(l'utilisateur est sauvé en RAM et non sur le
disque dur).
DOCKER_TLS_ VERIFY Si le paramètre est activé, alors Docker ne
permet des connexions distantes qu'avec le
protocole de sécurisation TLS.
DOCKER_ CONTENT_TRUST Si le paramètre est activé, alors Docker utilise
Docker Content Trust pour signer et vérifier
les images. Ce comportement est équivalent
à l'option -- disable -content -trust=fals e lors
de l'utilisation des commandes buil d, c rea t e,
pul l , pus h et ru n. Nous le verrons en détail dans
l:J
0 le chapitre 8.
c
::J DOCKER_ CONTENT_TRUST_SERVER L'URL du serveur Notary à utiliser
0
lorsque la variable d'environnement
\.0
.-t DOCKER_ CONTENT_TRUST est activée.
0
N DOCKER_TMPDIR L'emplacement des fichiers temporaires Docker.
@
.......
..c:
O'l
·;:: Pour illustrer l'impact fonctionnel d'une variable d'environnement, prenons un
>-
0..
0 exemple simple: nous utiliserons la variable DOCKER_CONF IGqui décrit l'emplacement
u des fichiers de configuration du client Docker (par défaut stockés dans le répertoire
-/.docker). Il est ainsi possible de définir un fichier de configuration particulier
[Link] qui permet de spécifier diverses options pour la ligne de commande.
Pour commencer créons un répertoire de configuration alternatif:

1 mkd i r - p /home/v ag r ant / alt_doc ker_co nf i g/


6.1 Introduction à la CU Docker -----------------------l 12sl
Éditons rapidement un fichier de configuration :

t ee / home/vagrant/alt_docker_config/co nfig . json <<- 'EO F'


{
"psFormat ":"t able
{{.ID l l \ \ t {{.I mage l l \ \ t {{. Command l l \ \ t {{. Ports l l \ \ t {{. Stat us l l "
}
EOF

Modifions maintenant la variable d'environnement DOCKER_CONFIG pour que


cette configuration alternative s'applique automatiquement par la suite :

1 export DOCKER_CONFI G=/home/vagran t/ al t_doc ke r_confi g/

Nous spécifions ici un format alternatif pour l'affichage de la commande ps . Par


défaut, celle-ci montre un tableau dont les colonnes sont CONTAINER ID, IMAGE,
COMMAND, CREATED, STATUS, PORTS et NAMES. La modification que nous
avons configurée changera l'affi chage par défaut de la manière suivante :

$ docker ps
CONTAINER ID IMAGE COMMAN D PORTS STATUS
c7ccla31d8f0 ngin x "n gi nx -g 'daemon off " 80/tcp . 443/tcp Up 12
1 minutes

Il est bien sûr possible de spécifier d'autres paramètres de configuration. Pour plus
de détails reportez-vous à la documentation en ligne de Docker.

6.1.2 Les options des commandes Docker

Les commandes Docker peuvent être paramétrées grâce à des options. C haque option
a une valeur par défaut, si bien que lorsque l'option n'est pas spécifiée, c'est sa valeur
l:J
0 par défaut qui sera appliquée.
c
::J
~
,.,
"O
0 c::; En termes d'écriture, les options sont soit représentées par une lettre (dans ce cas
\.0
.-t
0
.,.,
~ elles sont spécifiées par un simple tiret « - »), soit par plusieurs lettres (dans ce cas
N
'~ nous utilisons un double tiret « - - » ). Par exemple :
@ ·c
....... B::;
..c: CO
Ol c
$ docker run -i
1 $ docker run --detac h
ï:::: 0
>- c
o.. c
u
0 ·3
<.)
::;
"O
0
.....
c.
Généralement, une option définie par un simple tiret est un raccourci du nom
~ d'une option avec un double tiret. Par exemple, les deux options suivantes sont
~
::;
rS équivalentes :
1
"O
0
c
8 $ docker run -m 5M
(Ç) 1 $ docker run --memory 5M
J 1261 - - - - - - - - - - - - - - - - - - - - Chapitre 6. Prise en main du client Docker

Comme nous le constatons dans les exemples ci,dessus, certaines options ont une
valeur (par exemple, docker run -m 5M ) et d'autres non (par exemple, docker r un
-i ). En réalité, toutes les options ont une valeur, mais dans certains cas, il n'est pas
nécessaire de la spécifier ; tout dépend du type de l'option qui peut être Booléen,
Valeur simple ou Valeur multiple.

Les types d'option


Booléen
Une option de type Booléen décrit si un comportement spécifique de la commande
est activé ou non; ainsi les valeurs possibles sont vrai (true en anglais) et faux (false
en anglais).
Si une option de type Booléen est utilisée sans valeur, alors la valeur de l'option
est vrai. Ainsi les appels suivants sont équivalents :

$ doc ker r un -i
1 $ docker r un -i=true

Dans la documentation des commandes Docker, les options de type Booléen sont
décrites par le format suivant :

1 {nomüption}

{nomOption} définit le nom de l'option, par exemple - i ou - -i nterac t ive. La


valeur par défaut est faux.
Son modèle d'utilisation est :

1 ( - 1-- ){nomüpt i on }[=( valeur )J


l:J
0
c Par exemple:
:J
0
\.0
.-t
0 $ docker r un -i
N $ docker r un -i =true
@
.......
1 $ doc ker r un -- i nteract i ve
..c:
O'l
·;::
>-
0..
Valeur simple
0
u Une option de type Valeur simple définit une option qui ne peut être utilisée qu'une
seule fo is.
Dans la documentation des commandes Docker, les options de type Valeur simple
sont décrites par le format suivant :

1 [nomüption)=" [vale ur ParDefautl"


6.1 Introduction à la CU Docker -----------------------11211
{nomOption} définit le nom de l'option, par exemple - -net , et {valeurParDefaut} sa
valeur par défaut, par exemple br i dge. À noter que la valeur par défaut peut être vide.
Son modèle d'utilisation est :

1 ( - 1--) (nomOpt i on} (=I ) (" (val eur J"I (val eur })

Par exemple :

$ docker run -m 5M
1 $ docke r run - -memory 5M

Valeur multiple
Une option de type Valeur multiple définit une option qui peut être utilisée plusieurs
fois ; on dit que l'option est cumulative.
Dans la documentation des commandes Docker, les options de type Valeur multiple
sont décrites par le format suivant :

1 (nomOpt i on}=[ J
{nomOption} définit le nom de l'option, par exemple - p.
Son modèle d'utilisation est identique à celui du type Valeur simple, à l'exception
du fait qu'il peut être répété autant que nécessaire. Par exemple :

1 docker r un -p 35022 : 22 -p 35080 :80

La bonne pratique
Comme cela est indiqué dans les modèles ci,dessus ( =1), la valeur d'une option, quand
elle est donnée, peut soit être placée après un signe égal, soit après un espace ; ainsi
l:J
0 les deux écritures suivantes sont équivalentes:
c
::J
~
,.,
"O
0 c::;
\.0
.-t .,.,
~ $ docker run -m=5M
0
N
@
'~
·c
1 $ docker run -m 5M

....... B::;
..c: CO Toutefois, pour des raisons de lisibilité et de conformité avec le monde Unix, il
Ol c
ï:::: 0
c convient de n'utiliser le sigle égal que pour les options de type Booléen. Ainsi nous
>- c
o.. aurions :
u
0 ·3
<.)
::;
"O
0
.....
c.
~ $ docker run -i=tr ue
~
::; 1 $ docker run -m 5M
rS
1
"O
0
Toujours selon les modèles, la valeur d'une option peut être encapsulée par des
c
8 guillemets. Cependant, nous éviterons cette écriture, sauf si la valeur en question
(Ç) contient des espaces.
J 12sl-------------------- Chapitre 6. Prise en main du client Docker

..
6.2 LES COMMANDES SYSTEME

Dans cette section, nous allons présen ter ce que nous avons regroupé sous le terme de
« commandes système» . Il s'agit des commandes qui sont relatives au Docker Engine

dans son ensemble, soit pour piloter le démon , soit pour obtenir des informations sur
son fonctionnemen t.

6.2.1 docker daemon

docker daemon COPTIONSl

C'est la commande permettant de contrô ler le démon Docker. N ous l'avons déjà
abordée dans le chapitre 3.
Évidemment, dans la plupart des cas, le démon est démarré automatiquement
par un gestionnaire de système (comme systemd pour CentOS ou REHL).
Par exemple, sous C entOS, la définition du service est stockée sous
/usr/ lib/systemd/system/[Link] :

$ cat / usr/li b/systemd/sys t em/ docker .se r vice


[Unit]
Descri pt i on=Doc ker Applicat i on Container Engine
Documentation=https : //docs .docker . com
After=network .target docker . socket
Requires=doc ker .socket

[Serv i ce]
Type=not i fy
#the defaul t is not to use sys temd f or cgro ups because the delegate issues
st il l
# exists and systemd currently does not support the cgroup fea tu re set
l:J required
0
c # f or conta i ners r un by doc ker
::J
0 ExecSt art=/ usr/bin/doc ker daemon -H fd : //
\.0
.-t
0
N
@ N ous voyons que celle-ci fait appel à la commande docker da emon . Cette dernière
....... prend en paramètre de très nombreuses options relatives à différents sujets:
..c:
O'l
·;::
>- • authentification (plugins spécifiques et h eaders HTTP à ajouter aux requêtes
0..
u
0 REST du client Docker) ;
• paramétrage réseau (certificats, serveur ONS à utiliser, règles de forwarding IP,
etc.) que nous aborderons dans les chapitres 9 et 11 ;
• labels (dont nous parlerons dans le ch apitre 11 avec Swarm) qui permettent
de qualifier un hôte pour permettre l'application automatique de règles de
déploiemen t dans le cadre d'un cluster ;
• etc.
6.2 Les commandes système -----------------------11291
6.2.2 docker info

docker info COPTIONSJ

Cette commande permet de visualiser la configuration du démon. Nous l'avons


notamment utilisée dans le chapitre 4 pour visualiser la configuration du stockage
Docker. Elle fournit aussi des informations sur l'état du moteur, comme le n ombre de
conteneurs, le nombre d'images, les plugins installés, e tc.

6.2.3 docker version

docker version COPTIONSJ

Affiche la version du client et du serveur (démon) Docker (pour peu que ce dernier
soit installé) :

$ docker vers io n
Client :
Version: 1. 11.l
API version : 1. 23
Go version : gol .5. 4
Git commit : 5604cbe
Bui lt : Wed Apr 27 [Link] 2016
OS/Arch : l inux/amd64

Server:
Version: 1.11 .1
API version : 1. 23
Go version : gol .5. 4
Git commit : 5604cbe
Bui lt : Wed Apr 27 00:34 :42 2016
l:J
0
OS/Arch : lin ux/amd64
c
::J
~
,.,
"O
0 c::;
\.0
.-t
0
.,.,
~ 6.2.4 docker stats
N
'~
@ ·c
....... B::; docker stats COPTIONSJ
..c: CO
Ol c
ï:::: 0
>- c
o.. c
u
0 ·3
<.)
Une instruction qui donne (un peu à la manière d'un to p sous Unix) des
::;
"O
0
.....
informations sur les conteneurs exécutés par le moteur :
c.
~
~
::;
$ docker st at s
rS
1 CONTA INER CPU % MEM USAGE / LI MI T MEM %
"O
0
c NET 1/0 BLOCK 1/0 PIDS
8 b7f69 l e522b8 0.00% 7.815 MB / 1. 929 GB 0.41%
(Ç) 5.213 kB / 4. 956 kB 6. 791 MB / 0 B 0
J nol-------------------- Chapitre 6. Prise en main du client Docker

Cette commande accepte notamment une option - a qui permet de visualiser tous
les conteneurs (sous-en tendu, même ceux qui son t à l'arrêt) et une option - -no- s tream
qui permet de n'afficher qu'un instantané (un snapshot en anglais) des statistiques qui
ne sont donc pas rafraîchies en temps réel.

6.2.5 docker ps

docker ps COPTIONSJ

Cette commande permet de lister les conteneurs actifs (par défaut) ou l'ensemble
des conteneurs avec l'option - a.
La commande est aussi à la base de l'astuce permettant d'effacer tous les conteneurs
et que nous avons vue dans le chapitre 5 :

1 $ docke r rm $(docker ps -a - q)

Le modificateur - q limite l'affichage de la commande à l'iden t ifiant du conteneur,


ce qui permet à la commande rmde détruire tous les conteneurs (actifs ou inactifs du
fait du modificateur - a).
Il est aussi possible de modifier le format d'affichage de la commande à l'aide du
modificateur - -format (comme nous l'avons montré en début de chapitre) ou de filtrer
les conte n e urs à l'aide de l'optio n - - fi 1 ter .

6.2.6 docker events

1 docker events IOPTIONSI

l:J
0
c Une commande qui permet d'affi cher les événements qui se produisent sur le bus
::J
0 d'événements Docker. Une fois activée, la commande (un peu à la manière d'un t a i l
\.0
.-t
0
- f sur un fichier) affiche les événements du moteur Docker concernant les conteneurs,
N
les images, les vo lumes et le réseau.
@
....... Par exemple, si nous lançons un conteneur (ici nommé « tiny_bassi ») et que nous
..c:
O'l
·;:: lui faisons subir une séquence d 'actions (ici pause, unpause, stop puis start ):
>-
0..
0
u
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b7f691e522b8 ng i nx "nginx -g 'daemon off " 3 mi nutes aga Up 3 mi nut es
0.0 . 0.0 :80 ->80/tcp , 443/tcp ti ny_bassi
$ doc ker pa use b7f691e522b8
b7f691e522b8
$ docker unpa use b7f69le522b8
b7f69 1e522b8
6.2 Les commandes système -----------------------El
$ docker stop b7f69 l e522b8
b7 f69 1e522b8
1 $ docker start b7f691e522b8

Nous obtiendrons l'affichage suivant (à la condition de lancer la commande sur


un autre terminal avant d'effectuer les actions) :

$ docker events
2016-05 -09T13 :16 : 24 . 768480481+02 :00 container pa use
b7f69 1e522b80b69ca4a01d9f267eb31717f95b4e029c9068620322c0e81ac12 ( i mage=nginx,
name=tiny_bass i l
2016 -05 -09Tl3 :16 : 29 . 567098215+02 :00 container unpause
b7f69 1e522b80b69ca4a01d9 f 267eb31717f95b4e029c9068620322cüe81ac12 ( i mage=nginx ,
name=tiny_bass i l
2016 -05 -09T13 :16 :34 . 573241379+02 :00 container ki l l
b7f69 1e522b80b69ca4a01d9 f 267eb31717 f95b4e029c9068620322c0e81ac12 ( image=nginx,
name=tiny_bass i , sig nal =l 5)
2016 -05 -09T13 :16 :34 . 619735796+02 :00 container die
b7f69 1e522b80b69ca4a01d9 f 267eb31717 f95b4e029c9068620322c0e81ac12 (exitCode=O ,
image=ng i nx , name=ti ny_bassi)
2016 -05 -09T13 :16 :34. 767099031+02 :00 network disco nnect
cdb6ff80d4f9ff518d907de596fbd6ed437a9d247c l edb8a6b0b4d24ef4d583d
(conta i ner=b7 f 691e522b80b69ca4a0 1d9f267eb31717f95b4e029c9068620322c0e81ac12,
name=bridge , t ype=br id ge)
2016-05-09Tl3 : 16 :34 . 813257612+02 :00 container stop
b7f69 1e522b80b69ca4a0 1d9f267eb3 1717f95b4e029c9068620322c0e81ac12 ( i mage=nginx ,
name=tiny_bass i l
2016 -05 -09T13 :16 :38 . 957730296+02 :00 network connect
cdb6ff80d4f9ff5 18d907de596fbd6ed437a9d 247c l edb8a6b0b4d24ef4d583d
(conta i ner=b7f691e522b80b69ca4a0 1d9f267eb31717f95b4e029c9068620322c0e8lacl2 ,
name=bridge , t ype=br id ge)
2016-05 -09Tl 3:1 6:39 . 16607 1968+02 :00 conta i ner start
b7f69 l e522b80b69ca4aüld9f267eb3 1717f95b4e029c9068620322c0e81acl2 ( i ma ge=nginx ,
name=tiny_bass i )

l:J
0 On remarquera les événements réseau qui sont implicitement déclenchés par l'arrêt
c
::J
~
,., et le démarrage du conteneur.
"O
0 c::;
\.0
.-t
0
.,.,
~

N
'~ À noter que, co mme n ous l'avons déjà expliqué, toutes les commandes du client
@ ·c
....... B::;
Docker correspondent à des API REST. Il est ainsi possible à des applications tierces
..c: CO
Ol
0
c de s'enregistrer sur l'API suivante qui va streamer les événements au format JSON:
ï:::: c
>- c
o..
0 ·3
u <.)
::;
"O
0
1 GET /events
.....
c.
~
~
::;
rS
1
6.2. 7 docker inspect
"O
0
c
8 docker inspect [OPTIONSl CONTAINERllMAGE [CONTAINERllMAGE...l
(Ç)
El------------------- Chapitre 6. Prise en main du client Docker

Cette commande permet de récupérer sous un format JSON des métadonnées


relatives à une image ou un conteneur. Les données ainsi rendues sont très variées. Par
exemple, pour un conteneur : configuration des volumes, paramètres de démarrage du
conteneur, image, configuration réseau, etc.

6.3 CYCLE DE VIE DES CONTENEURS


Cette section étudie les commandes permettant d'influer sur le cycle de vie d'un
conteneur. Nous avons déjà vu un nombre important de ces commandes dans le
ch apitre 5. Le lecteur pourra donc s'y reporter pour voir leur effet sur divers exemples
pratiques.

6.3.1 docker start

docker start [OPTIONSl CONTAINER

Cette commande perme t de démarrer un conteneur qui aura été préalablement


créé (mais pas encore démarré ), à l'aide de la commande cre ate, ou arrêté.

6.3.2 docker stop

docker stop [OPTIONSl CONTAINER

Cette commande, qui permet de stopper un conteneur, a aussi déjà été étudiée
dans le ch apitre 5. Elle accepte notamment une option - t qui permet de spécifier un
nombre de secondes à attendre avant de tenter un ki 11.

l:J
0
c
6.3.3 docker kill
:J
0
\.0
.-t 1 docker klll !OPTIONSI CONTAINER
0
N
@
.......
..c:
Cette commande, déjà évoquée au chapitre 5 , permet de forcer l'arrêt d'un
O'l
·;:: conteneur (un peu à la manière du célèbre ki 11 -9 pour un processus Unix).
>-
0..
0
u
6.3.4 docker restait

docker restart [OPTIONSl CONTAINER

Une commande qui combine un s t op et un sta r t en séquence. Elle accepte comme


option le même paramètre - t que la commande s t op.
6.3 Cycle de vie des conteneurs -----------------------El
6.3.5 docker pause et docker unpause

docker pause COPTIONSJ CONTAINER

docker unpause COPTIONSJ CONTAINER

La commande pau se permet de freezer un conteneur. A ttention , le conteneur n'est


pas arrê té ; il est suspendu, c'est;à;dire qu'il ne fait plus rien. Il peut être réactivé en
utilisant la commande unpa use.
C ette fonctionnalité s'appuie sur celles de C G roups dans la gestion des processus.

6.3.6 docker rm

docker rm COPTIONSJ CONTAINER

La commande permet de détruire un contene ur (qui doit au préalable avoir été


arrêté ). Si le conteneur n'est pas arrêté, une erreur est affichée à mo ins d'utiliser
l'option - f (pour forcer) qui va d'abord déclencher une commande ki 11 avant
d'exécuter la commande rm.

6.3.7 docker wait

docker wait COPTIONSJ CONTAINER


l:J
0
c
::J
~
,.,
"O
0 c::;
\.0 C ette commande inté ressante permet de bloquer l'invite de commande tant que
.-t
0
.,.,
~
le conteneur passé en paramètre n'est pas arrêté. En effet, par défaut, la commande
N
'~
@ ·c stop rend la main immédiatemen t, le conteneur pouvant mettre plusieurs minutes à
....... B
..c:
::;
CO s'arrêter ensuite .
Ol c
ï:::: 0
>- c G râce à cette commande, il est par exemple possible de s'assurer qu'un conteneur
o.. c
u
0 ·3
<.)
est effectivement arrêté avant d'effectuer une autre action . Par exemple:
::;
"O
0
.....
c.
~
~ $ docker stop mon -conteneur
::;
rS 1 $ docker wai t mon-conteneur
1
"O
0
c
C ette dernière commande rend la main dès que le conteneur mon;conteneur est
8
(Ç) correctement arrêté.
J n41 - - - - - - - - - - - - - - - - - - - - Chapitre 6. Prise en main du client Docker

6.3.8 docker update

docker update [OPTIONSl CONTAINER

La commande update a un lien avec les commandes create et run . Elle permet
en effet de mod ifie r les paramètres d'un conteneur alors que celui,ci est démarré.
Attention, il ne s'agit pas de modifier des paramètres de volume ou réseau, mais
uniquement la configuration des ressources allouées au conteneur, par exemple :
• -cpuset- cpu s pour le nombre de C PU ;
• -mpour la mémoire maximale disponible.

N otons tout de même le modificateur - - resta rt qui permet de modifier la politique


de redémarrage automa tique du conteneur (dont les valeurs peuvent être no , on -
f ail ure [ nombre de tentatives ], al ways , unl ess-stopped ).

6.3.9 docker create et docker run

docker create [OPTIONSl IMAGE [COMMANDl [ARG...l

docker run [OPTIONSl IMAGE [COMMANDl CARG...l

create et r un sont des commandes sœ urs dans la mesure où un r un correspond à


un create suivi d'un st art. Rien d'étonnant à ce qu'elles partagent la plupart de leurs
options.
C es deux commandes prennent pour paramètre l'identifiant ou le nom d'une image
et , optionnellement, une commande à exécuter ou des paramètres qui compléteront
l'EN TRYPO IN T défini dans le Docke rfile qui a présidé à la création de l'image (voir
l:J
0 le chapitre 7) :
c
:J
0
\.0
.-t
$ docker crea t e -name=webse r ver ng i nx
0
N
#Crée un conteneur ngin x prêt à être démarré
$ docker start webserver
@
.......
..c:
1 #Déma r re l e conteneur précédemment créé
O'l
·;::
>- La liste des options est lon gue, au point que run a sa propre entrée dan s la
0..
u
0 documentation Docker. On peut catégoriser les options de cette commande comme
suit:
• les paramètres relatifs au contrôle des ressources (mémoire, CPU, IO) allouées
au conteneur (ce sont les mêmes paramètres que pour la commande up dat e) ;
• les paramètres relatifs aux volumes (que nous avons déjà vus sommairement
dans le chapitre 5, et que nous reverrons plus en détail dans le chapitre 7 et les
suivants) :
6.3 Cycle de vie des conteneurs -----------------------8
- - -vol urnes - f rom qui permet à un con teneur d'hériter des volumes d'un autre
conteneur (en général un data container, c'est-à-dire un con teneur qui n'a
pour autre objectif que de référencer des volumes),
- -vol urne-driver qui permet de changer le gestionnaire de volume (cf.
chapitre 1) qui pe rmet à Docker de déléguer la gestion des volumes à un
système tiers externe,
-v qui permet de spécifier les montages de volumes selon divers arguments
que nous verrons en détail dans le ch apitre 7,
les paramètres relat ifs à la gest ion du réseau (qui seront étudiés dans les
chapitres 9, 10 et 11) e t au mappage des ports IP (que nous verrons dans le
prochain chapitre en lien avec l'instruction EXPO SE du Dockerfile).

Il existe d 'autres paramètres dont les plus importants sont détaillés ci-dessous :
• - -en trypo i nt="" qui permet de surcharger l'instruct io n EN TRYPO IN T du
conteneur spécifiée dans le Dockerfile. Nous verrons le but de cette commande
dans le chapitre 7 ;
• -t et - i , la plupart du temps combinés, qui permettent d'ouvrir un pseudo
terminal sur le conteneur. Ceci permet donc de travailler avec le conteneur en
mode interactif. Par exemple :

docker run -t -i cent os : 7 /bi n/bas h


$
1 #ouvre une l i gne de commande dan s un conteneur de t ype centos 7

• -d (évidemment incompatible avec - i ) qui lance le conteneur en mode démon.


La commande ru n rend la main et le con teneur tourne en tâche de fond ;
• - w qui permet de spécifier un répertoire de travail différen t de celui spécifié avec
l'instruction Dockerfile WORKDIR (nous aborderons cette instruction dans le
ch apitre 8 ) ;
l:J
• - - pri vi l eged permet de lancer un conteneur en mode privilégié. Cela signifie
0
c ~
,., que ce dernier est alloué avec toutes les permissions du kernel (root) et peut
::J
0 "O
c::;
faire tout ce que l'hôte peut faire. C e type d 'allocation de droits est à utiliser
\.0
.-t .,.,
~ avec de grandes précaut io ns, mais est nécessaire notamment dans le cas de
0
N
'~
Docker dans Docker que nous étudions dans le chapitre 10 ;
@ ·c
....... B::;
• - -name, vu dans le chapitre 5, permet de nommer un conteneur (en contournant
..c: CO
Ol
0
c le système d 'allocation de nom par défaut de Docker) ;
ï:::: c
>- c • - - rm va garantir que si le conteneur est stoppé, il est automat iquement détruit
o..
u
0 ·3
<.)
::; avec la commande rm. A ttention, cette option n'est pas compatible avec le
"O
0
.....
c. mode démon ;
~
~
::;
• - -1 og- d ri ver permet de changer le gestionnaire de logs pour ce conteneur (voir
rS la commande l ogs ci-après).
1
"O
0
c
8
(Ç)
J 1361 - - - - - - - - - - - - - - - - - - - - Chapitre 6. Prise en m ain du client Docker

.. ..
6.4 INTERACTIONS AVEC UN CONTENEUR DEMARRE
Les diverses commandes de ce paragraphe permettent d'interagir avec un conten eur
démarré.

6.4 .1 docker logs

1 docker logs lOPTlONSJ CONTAINER

Cette commande permet d'affi ch er les logs du con ten eur.


Il s'agit d'une propriété intéressante des conten eurs Docker. Par défaut, Docker va
me ttre à d isposition de la commande l ogs ce qui est écrit dan s le STDOU T pour le
processus racine (celui qui est à la base de l'arborescence des processus du conten eur).
Prenons la lign e suivante :

$ docker r un -d -- name l oop php php -r "whi l e( t r uel lec ho \ "Log somet hi ng every
1 2 sec\n\ " ; sl eep(2) ; }"
Elle n 'est certes pas très élégante, ma is compréh ensible :
• la commande ru n va c réer pu is démarrer un conteneur ;
• ce conten eur est créé à partir de l'image de base ph p 1 ;

• le paramètre - d indique que le conteneur doit êt re lan cé en tâch e de fon d ;


• le nom de ce conteneur sera loop ;
• il va exécuter le m ini script PHP wh i le(true)lecho \ "Log something every
2 sec\ n\ " ; s l e e p( 2) ; ) qui va affi ch er une ch aîne de caractères toutes les deux
secondes.

Une fois ce con teneur démarré, n ous constaton s q u'il s'exécute :


l:l
0
c
:::i $ docker ps
0
\.0 CONTAINER ID IMAGE COMMA ND CREATED
.-t STATUS PORTS NAM ES
0
N 6d54638a92a5 php "p hp -r 'while(true)(" 3 seconds ago
@ Up 2 seconds l oop
.......
..c
O'l
'i: La commande l ogs va permettre de v isualiser les logs du conteneur :
>-
0.
0
u
$ docker l ogs - -ta il 4 l oop
Log somet hing every 2 sec
Log somethi ng eve ry 2 sec
Log somet hi ng every 2 sec
Log somet hi ng every 2 sec

l. [Link] [Link]/_/php/
6.4 Interactions avec un conteneur démarré -------------------El
La commande l ogs admet deux optio ns utiles:
• - - f o11ow ou - f permet de fonctionner en mode ta i l - f en affichan t les logs en
continu (au fur et à mesure qu'ils sont produits) ;
• - -t a i l Xperme t d'afficher X lignes de logs en partant de la fin.

Notez qu'il est possible de ch anger le pilote de logs (logs driver) d'un conteneur.
Docker en supporte nat ivement plusieurs et notamment des pilo tes comme fluentd 1
qui perme ttent de me ttre en place des systèmes de collecte, de centralisation et
d'indexat ion des logs.
Voyons ici un exemple dans lequel nous remplaçons le pilote par défaut par syslog
(le log système de Linux) :

$docker run -d -- l og -driver sys l og -- name loop php php - r "wh i le(true)(ec ho
1 \ "Log somet hi ng every 2 sec\n\ "; sl eep(2) ; }"

Maintenan t, n ous pouvons (sous Cen tOS) v isualiser le conteneur du syslog :

$ sudo tail -f /var/log/messages


May 10 00 : 21: 00 loca l host docker/94250ba05053[23043 J: Log somet hi ng every 2
sec
May 10 00 : 21: 02 localhos t docker/942 50ba05053[23043 J: Log somet hing every 2
sec
May 10 00 : 21:04 localhost docker/94250ba05053[ 23043 ] : Log somet hi ng eve ry 2
sec
May 10 00 :21:06 localhost doc ker/94250ba 05053 [23043 ]: Log somet hing eve ry 2
sec

6.4.2 docker exec

docker exec COPTIONSl CONTAINER COMMAND CARG...l


"'Cl
0
c
:::i
~
,., C ette commande permet d'exécuter une commande à l'intérieur d'un conteneur
"O
0 [Link]; démarré. L'un des cas d'usage très commun consiste à lancer un terminal bash dans un
\.0
.-t
0
~
V
conteneur Linux (pour aller fouiller dedans).
N V
'ii
@ ·c Lançons par exemple un conteneur Nginx (que nous avons déjà vu dans le
....... B
..c
:::;
CO chapitre 5 ) que nous nommerons « webserver » :
O'l c
0
ï::::: c
>-
o. c
u
0 ·3ù 1 $ docke r run -d -- name we bserve r nginx
:::;
"O
0
....
c.
~
Il est possible de se connecter à l'intérieur du conteneur démarré à l'aide de la
~
:::;
commande :
rS
1
"O
0
c
8
(Ç) 1. [Link]
J 1381 - - - - - - - - - - - - - - - - - - - - Chapitre 6. Prise en main du client Docker

$docker exec -t -i webserver /bi n/bas h


root@e80 fd 51 f 2119 : /# l s
bin boot devetc home l ibl i b64 media mnt opt proc roo t run sbin srv
sys tmp usr var
root@e80fd5l f 2119 : /# exi t

La commande exit met fin à l'exécution du termina l et rend la main sans pour
autant affecter le conteneur qui continue son exécution.
Il est évidemment possible de lan cer des commandes san s les modificateurs - i et
-t qui seront alors exécutées mode n on interactif.

6.4.3 docker attach

docker attach COPTIONSJ CONTAINER

C ette comman de permet de s'attach er à un conten eur démarré pour v isualiser


e t éventuellement interagir avec le processus racine du conteneur (si ce dernier le
perme t) .
Lan çons un conten eur de type serveur web:

1 $ docke r run -d -p 8000 :80 - -name webserver ng i nx

Il est en suite possible de se connecter au conten eur pour en v isualiser le


con tenu. Dans n otre cas, ouvrez un n avigateur et faites quelques appels à l'URL
[Link] lhost:SOOO pour générer des logs :

$ docker at tach --sig -proxy=fa ls e webserver


l:l
172 . 17.0.l - - [09 /May/20 16 :22 :39:30 +0000] "GET / HTTP/1 .1" 304 0 "- "
0
c "Mozil l a/5 . 0 (X ll; Li nux x86_64 ; rv :38 . 0) Gec ko/2010010 1 Fi refox/38 . 0"
:::i 172 . 17 .0. 1 - - [09/May/2016:22 :39 : 31 +0000] "GET / HTTP/1 . 1" 304 0 "- "
0
\.0
"Mozil l a/5 . 0 (Xll ; Li nux x86_64; rv :38 . 0) Gec ko/2010010 1 Firefox/ 38 . 0"
.-t
0
N
@ L'option - - si g-proxy=f a1se permet d'éviter que la commande Ctrl~C que vous
.......
..c utiliserez pour quitter l'attachement n e mette fin au processus et , de ce fait, arrête le
O'l
'i: conten eur.
>-
0.
0
u
6.4.4 docker rename

docker rename OLD_NAME NEW NAME

Cette commande, comme son nom l'indique, permet de renommer un conten eur.
6.4 Interactions avec un conteneur démarré -------------------11391
6.4.5 docker cp

docker cp COPTIONSl CONTAINER:SRC_PATH DEST_PATH

docker cp COPTIONSl SRC_PATH I- CONTAINER:DEST_PATH

Cette commande permet de copier des fichiers entre un conteneur démarré et le


système de fichiers de l'hôte.
Reprenons notre exemple de serveur web Nginx :

1 $ do cke r ru n -d -p 8000 :80 --n ame webserver ng i nx

Ouvrez un navigateur sur [Link] et constatez que la page par défaut


du serveur s'affiche. Nous allons maintenant la remplacer par le texte « Hello World » :

$do cker cp webserver : /usr/ share/ng i nx/ht ml / i ndex . ht ml .


$ echo "Hel l o Wo rl d" > index . html
1 $docker cp i ndex . html webserver : /usr/sha re/ ng inx/ html/i ndex . html

La séquence de commandes ci~dessus effectue les opérations suivantes :


• copie le fichier [Link] du serveur web (dans le conteneur) sur la machine
hôte ;
• remplace le contenu de ce fichier ;
• copie le fichier modifié depuis l'hôte vers le conteneur.

6.4.6 docker diff


"'Cl
0
c ~
docker diff COPTIONSl CONTAINER
:::i ,.,
"O
0 [Link];
\.0
.-t ~
0 V
V
C ette commande permet de visualiser les changements effectués sur les fichiers
N
'ii d'un conteneur, qu'il s'agisse :
@ ·c
....... [Link];
..c
O'l
CO
c
• d'ajouts (A) ;
ï::::: 0
>- c • de modifications (C) ;
o. c
u
0 ·3ù • d'effacements (D).
:::;
"O
0
....
c.
~ L'exemple suivant nécessite deux terminaux.
~
:::;
rS Dans le premier, nous allo ns ouvrir un conteneur CentOS en mode interactif :
1
"O
0
c
8 $ docker run -t -i - -name exemple centos : 7 /bi n/b ash
(Ç) 1 [ roo t @57538f4 5c5d2 /J#
J 1401 - - - - - - - - - - - - - - - - - - - - Chapitre 6. Prise en m ain du client Docker

U ne fois le conte neur ouvert, l' inv ite du terminal bash est affichée. O uvrez un
nouveau terminal et entrez la commande suivante :

1 $ docker di ff exempl e

Même si vous attendez longtemps, rien ne s'affiche car le conteneur n'a subi aucune
mod ification par rapport à son image de base.
Revenons à notre premier terminal et entrez la ligne suivante :

[root@57538f45c5d2 /J# echo "Hel lo" > t est . t xt


1 [ r oot@57538f45c5d2 /J#

Lançons alors à nouveau la même commande di ff dans notre second terminal :

$ docker di f f exempl e
1 A /test . txt
Nous pouvons constater que l'ajout du fich ier [Link] a bien été détecté.

6.4. 7 docker top

1 docker top IOPTIONSJ CONTAINER

C ette commande affiche le résultat de la commande t op effectuée à l'intérieur d'un


con teneur actif.

$ docker run -d -- name webserver nginx


94aaaa9db232626baaf8dc6179899528bf b9e9bdd5e40bl9e3e976292875eb2d
$ docker top webserver
l:J
UID PID PPID c
0
c STIME TTY TIME CMD
::J root 32259 32243 0
0
\.0
01:14 ? 00 :00 :00 ngi nx: mas te r
.-t
0
process nginx -g daemon off;
N 104 32271 32259 0
@ 01 :14 ? 00 :00 :00 nginx : worker
....... process
..c:
O'l
·;::
>-
0..
8 6.4 .8 docker export

docker export [OPTIONSl CONTAINER

C e tte commande permet d'exporter l'ensemble du système de fichiers d'un conte~


neur dans un fichier tar.
6.5 Commandes relatives aux images ---------------------El
$docker run -d - -name webserver nginx
1 $docker export webserver > test. t ar

Rarement utilisée en pratique, cette commande ne prend vraiment de sens qu'avec


docker i mpo rt qui permet de créer une image à partir de ce type d'export.
Elle peut aussi être utilisée pour faire tourner un conteneur avec un autre moteur
qui ne serait pas directement compatible avec le format d'image Docker, par exemple
RunC 1.

6.4.9 docker port

docker port COPTIONSJ CONTAINER

C ette commande permet de v isualiser les ports exposés par un conteneur :

$ docker run -d --name webserver -p 8000 :80 ng i nx


84515d2c56807e6f428d0a044c2 f 2f277 c42eac0bed5d65f929 alabc80289c37
$ docker port we bserve r
1 80/tcp -> [Link]:8000

6.5 COMMANDES RELATIVES AUX IMAGES


Nous allons maintenant effectuer un recensement des commandes qui permettent de
manipuler des images Docker.

6.5.1 docker build

"'Cl docker build COPTIONSJ PATH I URL


0
c
:::i
~
,.,
"O
0 [Link];
\.0
.-t ~
Il s'agit d'une commande que n ous avons abordée sommairement à la fin du
0 V
N V chapitre 5 et que nous allons utiliser intensivement dans le ch apitre 7.
'ii
@ ·c
....... [Link];
C e tte commande permet de construire une image à partir d'un Dockerfile.
..c CO
O'l c
ï::::: 0
c Vo ici quelques-unes de ses options les plus courantes :
>-
o. c
u
0 ·3ù • - t permet de définir le tag d'une image, c'est-à-dire son nom. Il est de convention
:::;
"O
0
de nommer les images en combinan t le n om de leur auteur (ou organisation) à
....
c.
~ un n om unique (un peu à la manière des repository GitHub) 2 ;
~
:::;
rS
1
"O
0 l. [Link] io/
c
8 2. Par exemple, l'image [Link] de la société lngensi qui
(Ç) fourni t une image Play framework prête à l'emploi.
J 1421 - - - - - - - - - - - - - - - - - - - Chapitre 6. Prise en main du client Docker

• - f permet de spécifier un Dockerfile possédant un no m différent du standard


usuel ;
• - - rmet - - fo r ce - rm permettent d'effacer les images intermédiaires produites lors
du processus de build (uniquement en cas de succès pour - - rm ou systématique-
ment pour --for ce-rm).

À noter que la commande accepte aussi les mêmes options de configuration des
ressources que pour les commandes r un ou crea t e.

6.5.2 docker commit

docker commit COPTIONSJ CONTAINER CREPOSITORYC:TAGll

Nous avons déjà utilisé cette commande dans le chapitre 5. C elle-ci permet de
créer une image à partir d'un conteneur démarré.

6.5.3 docker history

docker history COPTIONSJ IMAGE

N ous avons utilisé cette commande dans le chapitre 1 pour expliquer la structure
en couches des images Docker. Elle permet en effet de visualiser les différentes couches
d'une image et , e n regard, les instructions du Dockerfile qui ont été utilisées pour les
produire.

6.5.4 docker images

l:J
0 docker images COPTIONSJ CREPOSITORYC:TAGll
c
::J
0
\.0
.-t Cette commande permet de lister les images du cache local. Le paramètre - a
0
N permet de visualiser toutes les images intermédiaires (les couches) qui, par défaut, ne
@ sont pas visibles. Il est aussi possible d'appliquer des filtres via le paramètre - - f i l te r .
.......
..c:
O'l
·;::
>-
0..
0
6.5.5 docker rmi
u
docker rmi COPTIONSJ IMAGE CIMAGE...l

C ette commande permet d'effacer une image du registre local.


Elle est souvent combinée avec la commande dock er i ma ges, comme dans
l'exemple suivan t:
6.6 Interactions avec le registry -----------------------11431
1 $docker rmi $(docker i mages -- quiet -- filter "dangl i ng=tr ue")

Il s'agit ici d'effacer les images dangling {littéralement « pendantes » c'est~à~dire


dépourvues de tag donc de nom). Ce cas arrive lorsque vous construisez plusieurs fois
la même image (en phase de développement). Comme il n'est possible dans le cache
local Docker (comme dans un registry) de n 'avoir qu'une seule image pour un tag
donné, l'image précédente est dépossédée de son nom. Il est donc utile de lancer cette
commande pour faire le ménage.

6.5.6 docker save et docker load

docker save COPTIONSJ IMAGE [IMAGE...]

docker load COPTIONSJ

Ces deux commandes permettent d'importer des images depuis le cache local
Docker ou de les exporter vers le cache local. Elles permettent donc de transférer des
images entre hôtes sans faire appel à un registry :

$docker save cent os :7 > cen to s . t ar


1 S docker load -i=centos . ta r

6.5.7 docker import

docker import COPTIONSJ filelURLI- CREPOSITORYC:TAGll

"'Cl
0 Cette commande fonctionne avec la commande export. Elle permet d'importer le
c ~
,.,
0
:::i
"O système de fichiers d'un conteneur (préalablement exporté) en tant qu'image. À ce
[Link];
\.0 titre, son but est assez proche de celui de la commande commit.
.-t ~
0 V
N V
'ii
@ ·c
....... [Link];
..c
O'l
CO
c
0
6.6 INTERACTIONS AVEC LE REGISTRY
ï::::: c
>-
o. c
u
0 ·3ù Les commandes de cette section sont consacrées aux interactions entre le Docker
:::;
"O
0
.... Engine d'un hôte et les registries qu'il s'agisse du Docker Hub ou d'un autre registry
c.
~ public ou privé.
~
:::;
rS
"O
1
Notons que Google ([Link] et Amazon
0
c ([Link] ont annoncé la création de leurs propres offres de
8 registry de conteneur.
(Ç)
J 144, ___________________ Chapitre 6. Prise en main du client Docker

6.6.1 docker login

docker login [OPTIONSl [SERVERl

Cette commande permet de s'authentifier auprès d'un registry en vue d'effectuer


des opérat ions de pull e t de push. Elle accepte deux options :
• - -username, - u : le nom d'utilisateur d 'un compte du registry;
• - - password , - p : le mot de passe de ce compte.

6.6.2 docker logout

docker logout [OPTIONSl [SERVERl

San s surprise, cette commande déconnecte le démon du registry auquel il est


connecté (suite à l'usage de la commande l ogi n).

6.6.3 docker push

docker push [OPTIONSl NAME[:TAGl

C ette commande permet d'importer une image du cach e local dan s un registry.

6.6.4 docker pull

docker pull [OPTIONSl NAME[:TAG l@DIGESTl

l:J
0 La commande pu 11 permet de téléch arger une image dans le cach e local de l'h ôte.
c
:J
0 N otons que cette commande est par défaut implicitement lancée par run ou create
\.0
.-t lorsque l'image utilisée n 'est pas présente dan s le cach e local.
0
N
@
....... Il est possible d'utiliser le nom de l'image ou le digest, un identifiant globalement
..c:
O'l
·;::
unique et non mutable.
>-
0..
0
u
6.6.5 docker search

docker search [OPTIONSl NAME[:TAG l@DIGESTl

C ette commande permet de recherch er dans un registry. La rech erch e se fait sur le
nom de l'image. Il est possible d'appliquer un filtre sur le n ombre d'étoiles attribuées à
l'image à l'a ide du paramètre - s.
6.7 Réseau et volumes --------------------------11451
$ docker search -s=3 redmi ne
NAME DESCR IPTION
STARS OFFI CIAL AUTOMATED
sameersbn/redmi ne 194
[O K]
redmine Redmi ne i s a flexib l e proj ect management w.. . 176
[ OK]
bi tn ami /redmi ne Bi tnami Docker Image for Redmi ne 7
[ OK]
74t h/redmi ne-al l -i n-one Redmine i nc l udes host in g SV N & Git. ba ckl. .. 3
[O K]

6.6.6 docker tag

docker tag COPTIONSl IMAGEC:TAGl CREGISTRYHOST/l CUSERNAME/l


NAMEC:TAGl

Cette commande permet de créer un nom alternatif pour une image. Par exemple
si vous d isposez de l'image « monimage » en version 1. 7, il est possible de créer un
alias alternatif pour cette image avec la commande suivante :

1 $docker tag mon i mage :l . 7 mon i mage :l at es t


Si d'aventure quelqu'un lançait la commande rmi sur ce nouveau nom , l'image ne
serait pas effacée pour autan t, seul l'alias serait supprimé :

$ docker rmi mon i mage :la t est


1 Unta gged : mo ni mage : l atest

Ceci permet notamment de s'assurer que l'alias latest (couramment utilisé pour des
images Docker) po inte toujours vers la version la plus récen te d'une image.
l:J
0

0
c
::J ..
\.0
.-t
6.7 RESEAU ET VOLUMES
0
N
@ C es commandes sont apparues avec Docker 1.9 et apportent deux avancées majeures :
.......
..c: • le nouveau modèle réseau Docker dont nous allons parler en détail dans les
O'l
·;::
>- ch apitres 9 et 11 ;
0..
0
u • les volumes nommés qui permettent de s'affranch ir de la technique des data
containers dont nous verrons des exemples dans les chapitres 9 et 10.

C omme ces commandes seront abordées en détail dans la suite de cet ouvrage,
nous n'en ferons ici qu'une présen tation sommaire.
J 1461 - - - - - - - - - - - - - - - - - - - - Chapitre 6. Prise en main du client Docker

6.7.1 Les commandes docker network

Tableau 6.2 - Commandes docker network

Commande Objet
docker network create Permet de créer un réseau Docker. Cette commande prend
notamment en paramètre - -driv er qui permet de spécifier le
type de réseau souhaité (par défaut bridge).
docker network connect Cette commande permet de connecter un conteneur à un
réseau.
docker network disconnect Cette commande permet de déconnecter un conteneur d'un
réseau.
docker network inspect Une fonction d'inspection du réseau dont nous verrons l'utilité
dans le chapitre 9.
docker network ls Une commande qui liste les réseaux disponibles. Par défaut, trois
réseaux sont systématiquement définis : none, hast et bridge.
docker network rm La commande qui permet de détruire des réseaux existants
(sauf évidemment nos trois réseaux prédéfinis).

6.7.2 Les commandes docker volume

Tableau 6.3 - Commandes docker volume


Commande Objet
docker volume create Une commande qui permet de créer un volume qu'il sera
ensuite possible d'associer à un ou plusieurs conteneurs. Cette
commande prend en paramètre - -driver qui permet de
spécifier le driver utilisé pour ce volume. Il existe aujourd'hui
des plugins Docker permettant de s'appuyer sur des systèmes
de stockage tiers (en lieu et place d'une simple persistance sur
l'hôte).
docker volume inspect Une commande pour visualiser des métadonnées relatives à un
volume.
docker volume ls La commande qui permet de lister les volumes disponibles.
l:J
0 docker volume rm La commande qui permet d'effacer des volumes. Attention, une
c
::J fois détruit, les données associées à un volume sont perdues
0
\.0 définitivement. Il n'est cependant pas possible d'effacer un
.-t
0 volume utilisé par un conteneur.
N
@
.......
..c:
Ol
·;::
ii:
0
En résumé
u
Ce chapitre, qui peut être utilisé comme référence, nous a permis d'aborder la grande
majorité des commandes Docker disponibles. En pratique, il est assez rare d'avoir
recours à l'ensemble de ces commandes tous les jours, mais les connaître rend parfois
de précieux services.
Il est maintenant temps d'aborder plus en détail la conception de Dockerfile que
nous n'avons fait qu'effleurer dans le chapitre 5.
1
Les instructions Dockerfile

Ce chapitre a pour but de décrire les instructions d'un fichier Dockerfile, leurs
paramètres et leurs particularités, et comment elles doivent être utilisées en pratique.
La première section introduira la façon d'écrire u ne instruction , appelée modèle,
puis la deux ième section détaillera les instructions principales. Les instructions plus
techniques seront étudiées dans le chapitre 8 .

..
7 .1 LES MODELES D'INSTRUCTION
7.1 .1 Introduction
l:J
0 U n modèle d 'instruction Dockerfile décrit simplement comment cette dernière doit
c
::J
~
.
.,
0 "O être utilisée. O n peut le comparer à la signature d'une méthode dans un langage
c::;
\.0 de programmation. A insi, pour chaque instruction, il existe au mo ins un modèle,
.-t
0
.,.,
~

N mais plusieurs sont souvent disponibles, chaque modèle couvrant un cas d'ut ilisation
·~
@ ·c spécifique.
....... B::;
..c: CO
Ol
0
c De manière générale, les modèles d'instruction sont simples à comprendre. Il
ï:::: c
>- c existe pourtant une particularité : certaines instructions (par exemple C MD ou
o..
u
0 ·3
<.) EN TRYPO INT) contiennent plusieurs modèles dont le résultat peut sembler similaire,
::;
"O
0
.....
c.
mais qui comportent quelques subtiles différences. C es modèles sont décrits par deux
~ formats particuliers : terminal et exécution. Nous nous attarderons sur ces deux formats
~
::;
afin de déterminer dans quels cas l'un ou l'autre do it être ut ilisé.
rS
1
"O
0
c
8
(Ç)
J 1481 - - - - - - - - - - - - - - - - - - - - - Chapitre 7. Les instructions Dockerfile

Tableau 7.1 - Formats de modèles

Format Exemple de modèle Exemple d'application Commande résultante


terminal CMD <command> CMD ping localhost /bin/sh -c " ping localhost"
exécution CMD ["executable", CMD ["ping", "localhost"l ping localhost
"param 1", "param2"l

L'option -c du binaire / bin / sh (dernière colonne de la première ligne) définit que la


commande qui suit est décrite par une chaîne de caractères, dans notre cas "pi ng
localhost ".

7 .1.2 Terminal ou exécution ?

Le format terminal (shell en anglais) perme t d'exécuter un binaire (par exemple, la


commande pi ng ) au travers d'un terminal applicatif, autrement d it la commande
sera préfixée par "/ bi n / s h - c" . Par exemple, l'instruction CMD pi ng l oca l hos t sera
exécutée par :

1 /bi n/sh -c "ping loca l host "

Premier point important et obligato ire dans le cas terminal : le binaire / bi n/ s h


do it ê tre disponible dans l'image pour que la commande puisse être exécutée. Une
image minimale pourrait ne pas le contenir si bien que cette commande échouerait.
Le deuxième problème est plus technique : comme cela est mentionné plus h aut,
l'exécution <lu pi ng est encapsulée <lans l'exécution <lu / bi n / s h, ce 4ui en suit n'est pas
un problème, mais le devient dans un contexte Docker, notamment lors de l'arrêt d'un
con teneur. Pour comprendre le problème, il faut tout d 'abord expliquer les principes
suivants:
1. Le PID du processus démarré par le point d'entrée d'un conteneur (instructions
C MD et/ou EN TRYPO IN T) est le 1.
l:J 2. Lorsqu'un conteneur actif est arrêté par la commande docker sto p, alors cette
0
c dernière n 'essaie d'arrêter proprement (SIG TERM) que le processus dont le
::J
0
\.0
PID est 1. S 'il existe d'autres processus, alors ils seront arrêtés brutalement
.-t
0 (SIGKILL) après le délai accepté pour l'arrêt d'un conteneur (par défaut 10
N
secondes).
@
.......
..c: 3. Lorsque le binaire /bin/sh reçoit un sign al lui demandant de s'arrêter, alors il
O'l
·;:: s'arrê te proprement, mais ne retransmet par le signal à ses enfants, c'est-à-dire
>-
0..
0 les autres binaires qu'il encapsule (dans notre exemple pi ng ).
u
Reprenons maintenant l'exemple du pi ng . Nous aurons donc deux processus
démarrés dans le conteneur :
1. / bi n/ s h avec le PID 1 (car représentant le point d 'entrée du conteneur).
2. pi ng avec un autre PID.

Si on souhaite arrêter le con teneur ( docker stop ), le résultat sera le suivant:


7. 1 Les modèles d'instruction

1. / bi n/ s h s'arrêtera proprement car il a le PID 1.


2. ping ne s'arrêtera pas proprement car il n 'a pas le PID 1, et /bi n/s h ne
retransmet pas le signal d'arrêt à ses enfants. 11 sera ainsi arrêté brutalement à la
fin du délai d'arrêt du conteneur.

Notre exemple utilise le binaire pi ng, ce qui, au final, n'est pas un réel problème
s'il s'arrête brutalement ; par contre, si le processus en question est plus critique,
par exemple un serveur HTTP (Nginx, A pach e ... ), la situation serait différente : les
requêtes du serveur HTTP en attente de traitement ne seraient pas exécutées, ce qui
pourrait entraîne r des comportements étran ges au niveau des clients, ou pire, une
perte de données.

Vous souhaitez en savoir plus sur l'arrêt des conteneurs ? Un article décrivant
comment arrêter proprement un conteneur Docker et disponible v ia le lien ci,
dessous :
[Link]

Le format exécutable (exec en anglais) permet d'exécuter un binaire sans intermé,


diaire. Par exemple, l'instruction C MD ["ping" , "localhost"] sera simplement exécutée
par pi ng l oc al ho s t .
Ainsi on remarque que le terminal applicatif / bin/ s h n 'est plus utilisé, et que le
binaire à exécuter ( pi ng dans n otre exemple ) est directement appelé, ce qui règle les
deux problèmes du format terminal :
• une image minimale qui ne contiendrait pas le binaire /bin/sh ;
• un arrêt brutal d'un processus supplémentaire à celui défini par le po int d'entrée
du con teneur.

Toutefois, le format terminal a l'avantage d'être plus lisible et confortable à utiliser,


si bien qu'on l'utilisera dans les cas suivants :
"'Cl
0
• l'image contient le binaire / bin/sh ;
c ~
,.,
:::i
"O
• il n'existe pas de processus supplémentaire demandant un arrêt propre.
0 [Link];
\.0
.-t ~
0 V Dans les autres cas, on utilisera le format exécution . Plus concrètement, le
N V

@
'ii
·c tableau 7 .2 décrit les règles d 'utilisation des formats.
....... [Link];
..c CO
Tableau 7.2 - Règles d'utilisation des formats
O'l c
0
ï::::: c
>-
o. c Contexte d'utilisation Format
u
0 ·3ù
:::;
"O
Cas de tests terminal*
0
.... Commande se terminant directement après son exécution (par terminal*
c.
~
exemple : ls ou mkdir)
~
:::;
rS Commande lançant un processus (par exemple : ping ou httpd) exécution
"O
1
Autres cas exécution
0
c
8
(Ç) * pour autant que l'image cont ienne le bi naire /bin/sh , sinon exécuti on.
J 1501 - - - - - - - - - - - - - - - - - - - - - Chapitre 7. Les instructions Dockerfile

7.1.3 Les commentaires


U n fichie r Dockerfile peut contenir des commentaires, c'est-à-dire des lignes qui n e
seront par interprétées. Pour cela, il suffit d 'utiliser le caractère « # » :

#L' i mage sour ce es t cento s 7


FROM cent os :7
#On ajout e f ichier testl dans t mp
COPY testl / t mp/
#On lis t e l e dossier t mp du con t eneur
CMD ls /tmp

7 .2 LES INSTRUCTIONS D'UN DOCKERFILE


Cette section décrit les instructions principales disponibles pour un fichier Dockerfile.
L'objectif ici est de fournir les connaissances nécessaires à l'élaboration d'un Dockerfile
afin d'éviter les erreurs usue lles. Pour cela, de nombreux principes so nt illustrés par
des exemples.
Pour rappel, un fichier Dockerfile représen te simplemen t le descripteur d'une image
Docker : après l'élaboration d'un Dockerfile, on construit l'image avec docke r bui l d
puis on démarre un conte neur basé sur cette image avec docker run .

7.2.1 FROM

L'instruction FRO M permet de spécifier l'image Docker parente à utiliser. A insi,


l'image résultante du Dockerfile sera basée sur cette dernière à laquelle seront ajoutés
les blocs d 'images produits par les instruction s suivantes.

Image
l:J
0 Instruction FROM Autres instructions
c
::J
0
\.0
.-t
0
N
@
....... Image source
..c:
O'l
·;::
>-
0..
0
u
Figure 7.1 - Décomposition d'une image Docker

La figure 7.1 représente l'image résultante d'un Dockerfile. N ous pouvons con stater
que l'instruction FROM définit l'image source, et que les autres instruction s sont
exécutées à partir de cette image (installation d 'une applicat ion , exécution d'un
script ... ).
7.2 Les instructions d'u n Dockerfile ----------------------El
Le modèle de l'instruction FROM est:

FROM <image>[:<tag>l

<image> représente l'image Docker source. Cette image doit être disponible soit
localement, soit dans le Docker Hub ou dans votre registry privé.
<tag> représente la version de l'image Docker source. S'il n'est pas spécifié, alors
la dernière version (latest) est utilisée.
Par exemple :

FROM centos
1 FROM centos :7

FROM est la seule instruction obligatoire d'un [Link] ; de plus, elle doit être
placée en début de [Link] (précédée d'éventuels commentaires).
Un même [Link] peut contenir plusieurs fois l'instruction FROM afin de créer
plusieurs images. Prenons un exemple simple dont le but est de créer deux images : la
première affiche un message « Hello world » à son exécution et la deuxième« Bonjour
à tous ».

FROM centos :7
CMD echo "Hel l o world "
FROM centos : 7
1 CMD echo "Bonj our a to us "

C onstruisons ensuite les images depuis le répertoire contenant not re [Link] :

$ docker bui l d .
Sending buil d cont ext t o Doc ker daemon 3. 072 kB
l:J
Step 1 : FROM centos :7
0
c ~
---> ce20c473cd8a
::J ,., Step 2 : CMD echo "Hello world "
"O
0
\.0
c::; ---> Run ni ng i n le0 94f 7bla01
.-t
0
.,.,
~ --- > cfef3a2f a477
N
'~
Removing i nt ermediate cont ainer le094f7b l a0 1
@ ·c Step 3 : FROM cent os : 7
B
.......
..c:
::;
CO --- > ce20c473cd8a
Ol
ï:::: 0
c Step 4 : CMD echo "Bonj our a t ou s"
c
>-
o.. c ---> Run ni ng in 07dc l 36e24b6
u
0 ·3
<.)
--- > 5b7f2d5028bd
::;
"O
0
Remov i ng i nt ermediate cont ai ner 07dcl36e24b6
.....
c. Successful ly bu ilt 5b7f2d5028bd
~
~
::;
rS Dans notre cas, la première image a pour identifiant cf e f3 a 2f a477 et la deuxième
"O
0
1
5b7f 2d5028bd.
c
8 Démarrons un conteneur avec la première image :
(Ç)
J 1521 - - - - - - - - - - - - - - - - - - - - - Chapitre 7. Les instructions Dockerfile

$ docker r un cfef3a2fa477
1 Hello worl d
Et maintenant un conteneur avec la deuxième image :

$ docker r un 5b7 f 2d5028bd


1 Bonjour à to us

C et exemple démontre que l'utilisation de plusieurs instructions FROM dans un


même Docke rfile est plus ou moins équivalente à l'utilisation de plusieurs fichiers
avec les mêmes instructions. C ela nous empêch e cependant de spécifier des options
d ifférentes lors du docker bui l d pour ch aque image (par exemple, spécifier le nom
de l'image). L'utilisation d'un même Dockerfile pour construire plusieurs images
s'utilise dans des cas très particuliers, par exemple lors de la construction de plusieurs
images fonctionnellement très proches, c'est-à-dire contenant très peu d'instructions,
et héritant d'une même image source : on se rend bien compte que ces cas sont
anecdotiques, et on appliquera la règle générale suivante :

Un fichier Dockerfile doit contenir exactement une et une seule instruction FROM.

Pour conclure, reven ons sur l'utilisation du modèle sans spécifier la version de
l'image de base (le tag ), par exemple FROM centos. La probabilité que l'image ne
puisse pas être construite augmente avec le temps : pour rappel, en omettant la version ,
c'est la dernière qui est utilisée. Ainsi, entre la création in itiale du Dockerfile et la date
actuelle, la version de l'image source va très certainement évoluer. En reconstruisant
un Dockerfile dont la version de l'image source aurait ch an gé, notamment si une
n ouvelle version majeure a été publiée, alors les instructions suivantes peuvent ne plus
fon ctionner ; ça serait le cas, par exe mple, lors de l'installation d'un paquet existant
sur une ancienne distribution de Linux, mais plus disponible sur la version courante.
On peut donc retenir la règle suivante :
l:J
0
c Dans l'instruction FROM d'un fichier Dockerfile, il faut toujours spécifier la version de
:J
0 l'image source.
\.0
.-t
0
N
@ 7.2.2 MAINTAINER
.......
..c:
O'l
·;:: L'instruction MA IN TA IN ER permet de spécifier la personne en charge de maintenir
>-
0..
0 le Dockerfile, générale ment son auteur.
u
Le modèle est :

MAINTAINER <name>

<na me> est une chaîne de caractères représentan t l'auteur, par exemple son prénom
et son n om.
7.2 Les instructions d'un Dockerfile -----------------------8
Par exemple :

1 MAINTA IN ER John Doe

L'instructio n MAIN TAINER va renseigner le champ A uthor de l'image. Cette


information est visible lorsqu'on exécute un do ck er i nspect sur l'image. Prenons un
simple exemple pour constater cela :

FROM centos :7
1 MA INTAI NER John Doe
Construisons et inspectons l'image :

$ docke r bui l d -t mai nt ainer .


$do cker i nspect -- forma t ='{ {json .Author}} ' maintai ner
1 "John Doe "

L'option -- format utilisée dans le docke r in s pect ci~dessus permet de focaliser


le résultat : dans notre cas, nous souhaitons visualiser l'auteur de l'image au
format JSON (car simple à lire), et no us utilisons ainsi le format {{json .Author}}.
« maintainer » représente le nom de l'image dont nous souhaitons visualiser des
informations. À noter qu'il est possible d'exécuter un doc ke r i ns pect sur une image
ou sur un conteneur.

7.2.3 RUN
L'instruction RUN (à ne pas confondre avec la commande docker run ) permet
d'exécuter des commandes utilisées généralement pour construire l'image. O n peut
représenter l'ensemble des instructions RUN comme l'écart entre l'image source et
l:J
l'image résultante.
0
c
::J
~
,., Il existe deux modèles pour l'instruction RUN :
"O
0 c::;
\.0
.-t
0
.,.,
~
RUN <command>
N
'~
@ ·c
....... B::;
..c: CO
Ol c
ï:::: 0
>- c
o.. c RUN ["executable", "param 1 ", "param2"l
u
0 ·3
<.)
::;
"O
0
.....
c. Le premier est orienté terminal et le second exécution.
~
~
::;
Par exemple :
rS
1
"O
0
c
8 RUN mkd i r /tmp/test
(Ç) 1 RUN [ "/bi n/sh ", "-c ", "mkd i r /tmp/test "J
J 1 s4I--------------------- Chapitre 7. Les instructions Dockerfile

Les deux exemples ci-dessus produiront le même résultat, c'est-à-dire créer un


dossier test sous /tmp. Pour rappel, l'option - c dans le second exemple permet de
spécifier que la commande (dans notre cas mkdi r /tmp/test ) sera décrite par une
chaîne de caractères.

Les instructions RUN servent à construire l'image ; ainsi, les commandes à exécuter
seront finies, c'est-à-dire inactives après leur exécution. Il est donc préférable d'utiliser
le format terminal qui est plus aisé à écrire et à comprendre.

Il est possible de combiner plusieurs commandes pour une même instruction RUN,
simplement en les séparant par des points-virgules (;) , par exemple :

1 RUN mkdi r /tmp /testl ; mkd i r /tmp/ test2

C et exemple crée deux dossiers ( testl et test2) sous /tmp.


Pour gagner en lisibilité, il est parfois préférable d'écrire les commandes sur
plusieurs lignes. Pour cela, il suffit de termine r une ligne par un antislash ( \ ) ; en
reprenant le dernier exemple, nous aurions :

RUN mkdir /tmp/test l ; \


1 mkd i r / t mp/test2
L'utilité majeure de l'instruction RUN est l'installation des fonctionnalités par-
t iculières à l'image: par exemple, si un conteneur a pour but l'explo itation d'une
application web PHP, alors l'image Docker devra probablemen t contenir un serveur
web (par exemple A pache ) ainsi que PHP et éventuellement une base de données. Le
Dockerfile doit donc décrire l'installation des services et applications nécessaires. Dans
la mesure où ce livre utilise comme image source un linux C entOS 7, le gestionnaire
de paquets n atif utilisé est Yellowdog Updater Modified (yum). L'installation de tout
l:J
0 paquet se fera alors grâce à la commande yum. Lors de son exécution, une confirmation
c
:J d'action est demandée à l'utilisateur : étant donné que l'utilisateur ne peut agir lors de
0
\.0 la construction d'une image, il faut forcer les actions grâce à l'option -y . Par exemple,
.-t
0
N
pour l'installation d'Apache nous aurions :
@
.......
..c:
O'l
·;::
1 RUN yum i nsta 11 -y htt pd
>-
0..
u
0 Pour pouvoir installer un paquet , on s'attend à un certain état de l'image, c'est-à-
d ire une version à jour et surtout cohérente avec d'autres paquets. Par cohérente, nous
entendons un état connu et qui ne diffère pas d'une exécution à l'autre. A insi, il faut
s'assurer de l'état avant l'installation du paquet souhaité ; pour cela, nous incluons
généralement la commande yum update à celle d'installation, par exemple:

1 RUN yum update -y && yum inst al l -y httpd


7.2 Les instructions d'un Dockerfile -----------------------11551
Il est important de ne pas utiliser l'instructio n seule RUN y um updat e -y, car un
problème de cache Docker peut survenir, entraînant une incohérence d'images. La
prochaine section illustre ce problème grâce à un exemple.

Quand le cache s'en mêle


C omme expliqué précédemment, l'utilisation de la commande RU N y um upda t e - y
peut en trainer un problème d'incohérence.
Pour l'illustrer, n ous utiliserons un dépôt fictif de paquets, illustré par l'image
suivante:

Dépôt fictif

Paquet Alpha Paquet Beta


Version 5 Version 2

Figure 7.2 - Dépôt fictif

Imaginons à présent une image, appelée AB, avec un paquet A lpha en version 3
et un paquet Beta en version 2 ; cela signifie que lors de la construction de l'image ces
deux paquets étaient disponibles dans ces versions.

Image AB

Paquet Alpha Paquet Beta


Version 3 Version 2

l:J
0
c
::J
~
.
.,
"O
0 c::;
\.0
.-t
0
.,.,
~
Figure 7.3 - Dépôt fictif plus ancien
N
·~
@ ·c
....... B::;
..c:
Ol
CO
c À noter que seuls les paquets utiles à l'exemple sont représentés, tout autre élément
ï:::: 0
>- c de l'image étant volon tairement ignoré afin de faciliter la compréhension.
o.. c
u
0 ·3
<.) O n souhaite construire une image XYZ à jour dont l'image source est A B. O n écrit
::;
"O
0
.....
c.
alors naïvement le [Link] suivant :
~
~
::;
rS FROM AB
"O
0
c
1

1 RUN yu m upda t e -y
8
(Ç)
J 1561 - - - - - - - - - - - - - - - - - - - - - Chapitre 7. Les instructions Dockerfile

En le construisant nous obtenons :

lmageXYZ

Paquet Alpha Paquet Beta


Version 5 Version 2

Figure 7.4 - Image basée sur le dépôt le plus récent

L'image XYZ contient donc logiquement le paquet Alpha en version 5, car il a été
mis à jour suite à la commande RUN y um upd ate -y.
Q uelque temps p lus tard, les paquets du dépôt fictif sont mis à jour ; de plus, un
nouveau paquet G amma est dispo nible, qui est dépendant du paquet Alph a dan s sa
derniè re version :

Dépôt fictif

r
Paquet Alpha Paquet Beta
Version 6 Version 3

r
î
Paquet Gamma
Version 1

l:J
0
c Figure 7.5 - Mise à jour du dépôt
::J
0
\.0
.-t
0
N
Nous souha itons ma inten ant ajouter le paquet Gamma à l' image XYZ, et nous
@ modifions donc le [Link] a insi :
.......
..c:
O'l
·;::
>- FROM AB
0..
0 RUN yum update -y
u 1 RUN yum i nstall -y gamma

En con struisant à n ouveau le [Link] sur la même machine, la commande


RUN yum upd ate -y n 'est pas exécutée, ma is lue depuis le cach e (car elle n 'a pas été
modifiée) ; ainsi, à ce stade, ni le paquet A lpha ni le paquet Beta n e sont mis à
jour. A lpha sera mis en version 6 grâce à l'instruction suivante (où seuls les paquets
nécessaires à Gamma sont mis à jour), Beta restant lui en version 2 :
7.2 Les instructions d'un Dockerfile -----------------------El
Image XYZ

Paquet Alpha Paquet Beta


Version 6 Version 2

Paquet Gamma
Version 1

Figure 7.6 - Première image

En construisant le Dockerfile depuis une autre machine, on se rend compte aisé-


ment qu'Alpha et Beta seraient respectivement en version 6 et 3 après construction;
ainsi, le résultat devient incohérent d'une machine à l'autre :

lmageXYZ

Paquet Alpha Paquet Beta


Version 6 Version 3

Paquet Gamma
Version 1

l:J
0
c
::J
~
.
.,
"O
0 c::;
\.0 Figure 7. 7 - Seconde image : même Dockerfile, résultat différent
.-t
0
.,.,
~

N
·~
@ ·c
....... B::;
..c: CO
Ol c
ï:::: 0
c Conclusion
>- c
o..
u
0 ·3
<.) Lorsque nous souhaitons installer un paquet, il faut toujours s'assurer que les paquets
::;
"O
0
.....
existants sont à jour: n ous utilisons pour cela la commande yum upda te -y. Toutefois
c.
~ nous devons garantir que cette dernière est exécutée lors de chaque construction
~
::; impliquant l'installation d'un paquet supplémentaire. Ainsi, nous devons combiner
rS la commande yum update -y avec les yum inst al l -y nécessaires, si bien que nous
1
"O
0
c obtenons par exemple :
8
(Ç)
11581--------------------- Chapitre 7. Les instructions Dockerfile

RUN yum update -y && yum i nst all -y\


ht tpd \
mari adb -server \
1 php php -mysql

7.2.4 CMD
L'instruction C MD permet d'exécuter une comman de (par exemple, une commande
U nix) au déma rrage du conteneur résultant.
Il est important de comprendre que cette instruction n 'est pas jouée lors de la
construction de l'image, mais bien lors de l'exécution d 'un conteneur associé. A insi,
son rô le est de fournir le contexte d'utilisation du conteneur, par exemple le démarrage
d'un serv ice.

Un Dockerfile peut contenir plusieurs instructions CMD, cependant seule la dernière


instruction du fichier sera exécutée au démarrage du conteneur. Ainsi il convient de
n'avoir, au maximum, qu'une seule instruction CMD dans un Dockerfile.

Il existe trois modèles pour l'instruction C MD :

CMD <command>

CMD ["executable", "param 1", "param2"l

1 CMD r'paramt", "param2"l

Le premier est orienté terminal et les autres exécution (sur le même principe que
l:J l'instruction RUN ).
0
c
::J Prenons un peu de temps pour décrire la troisième forme : nous constaton s
0
\.0 qu'aucun exécutable n'est spécifié, cela signifiant que l'instruction seule est incom~
.-t
0 plète ; elle do it don c être combinée avec l'instruction EN TRYPO INT (dont le
N
@ principe de fonctionnement sera donné dans la procha ine section) pour qu'elle
.......
..c: devienne fon ctionnelle. Illustrons la combinaison d'une instruction C MD avec une
O'l
·;:: instruction ENTRYPOIN T par un exemple :
>-
0..
0 Soit le Oockerfile suivan t :
u

FROM centos :7
ENTRYPOINT [" /bi n/pi ng ", "-c", "5"]
1 CMD [" l ocalhos t"J

L'instruction EN TRYPOINT représente l'exécution de la commande pi ng cinq


fois. Par contre, elle ne décrit pas la destination du pi ng ; autrement dit , en exécutant
7.2 Les instructions d'un Dockerfile ----------------------11591
la commande pi ng - c 5 depuis un terminal, nous obtiendrons une erreur du type
« mauvaise utilisation de la commande ping ».

L'option -c de la commande ping signifie count, soit le nombre souhaité d'exécutions.

L'instruction CMD représente uniquement le paramètre décrivant la destination


de la commande pi ng. Ainsi, mis bout à bout, nous obtiendrons la commande suivante
ping -c 5 l oca lh ost .
Construisons maintenant notre image et démarrons un conteneur :

$ docker bui l d -t my-pi ng .


$ docker run my -pi ng
PING loca l host (127 .0. 0.1 ) 56 (84) byte s of data .
64 bytes f rom loca l hos t (12 7. 0. 0. 1) : icmp_seq=l t t l =64 ti me=0. 083 ms
64 bytes f rom loca lhost (127. 0. 0.1 ) : i cmp_seq=2 t t l =64 t i me=O . 117 ms
64 bytes f rom l ocalhost (127. 0. 0. 1) : icmp_seq=3 t t l =64 t i me=0 . 082 ms
64 bytes f rom loca l hos t (127 . 0. 0. 1) : icmp_seq=4 t t l =64 t i me=0. 071 ms
64 bytes f rom loca lhost (127 . 0. 0.1 ) : i cmp_seq=5 t t l =64 t i me=0 . 058 ms
--- l ocal hos t pi ng sta tisti cs ---
5 packet s t r ansmitt ed . 5 received . 0% packet l oss. ti me 4007ms
r tt mi n/a vg /max/mdev = 0. 058/0 .082/0 . 117/0 . 020 ms

Le résultat représente l'équivalent de l'exécution pi ng - c 5 l oc al ho s t depuis un


terminal.
Mais alors pourquo i utiliser deux instructions (ENTRYPOINT et CMD) alors
qu'une seule donnerait le même résultat ? La réponse à cette question réside dans la
surcharge du point d'entrée d'un conteneur.
En effet, ce dernier décrit l'effet des instructions CMD et/ou ENTRYPOINT au
démarrage du conteneur. La surcharge représente quant à elle la modification de cet
effet. Illustrons ces principes par deux exemples, le premier pour l'instruction CMD et
le deuxième pour ENTRYPOINT.
Soit le Dockerfile suivant :
l:J
0
c ~
,., FROM cent os : 7
1
::J
"O
0
\.0
c::; CMD pi ng loca l host
.-t
0
.,.,
~

N
'~ Pour surcharger l'instruction C MD, nous spécifions simplement la commande
@ ·c
....... B::;
comme paramètre d'exécution (un build préalable est bien sûr nécessaire) :
..c: CO
Ol c
1 $docker run my-ping -cmd ls
ï:::: 0
>- c
o.. c
u
0 ·3
<.)
::;
"O
0
.....
Ainsi pi ng l oc al ho s t sera remplacé par la commande l s (lister le contenu du
c.
~ répertoire courant).
~
::;
rS Continuons notre exemple avec le Dockerfile suivant:
1
"O
0
c
8 FROM centos : 7
(Ç) 1 ENTRY PO INT pi ng l ocal host
J 1601 - - - - - - - - - - - - - - - - - - - - Chapitre 7. Les instructions Dockerfile

Pour surcharger l'instruction ENTRYPO INT, nous devons utiliser l'option - -


ent rypoi nt , par exemple :

1 $ docker run --e ntrypoint l s my -ping -entrypo i nt

La première constatation est qu'il est plus simple de surcharger une instruction
C MD que EN TRYPO INT; ainsi, nous privilégierons généralement cette façon de
fa ire. Ensuite, nous remarquons qu'il n'est pas toujours souhaité de surch arger la
totalité d'une commande. Dans ces derniers exemples, nous pourrions ne vouloir
surcharger que le nom de l'hôte (ici localhost) du pi ng et non toute la commande :
c'est dans ce sens que le cumul des instructions C MD et ENTRYPO INT devient utile.
Reprenons l'exemple my-ping : imaginons que nous souhaitons surch arger localhost
par "[Link]" ; l'exécution serait alors :

$ docker r un my -ping goog l e . com


PING goog le . com (77 .1 53 . 128 .182) 56(84) bytes of data .
64 bytes f rom 182 .1 28 . 153. 77 . rev . sf r . net (77 .153. 128 . 182) : i cmp_seq=l ttl =47
time=22 . 0 ms
64 bytes f r om 182 .1 28 . 153 . 77 . [Link] (77 . 153.128 . 182 ) : icmp_seq=2 ttl=47
time=21. 7 ms
64 bytes f rom 182 . 128 . 153 . 77 .rev .sfr . net (77 .153 .1 28 . 182 ) : icmp_seq=3 ttl=47
time=21. 6 ms
64 byt es f r om 182 . 128. 153 . 77 .rev . sf r . net (77 . 153. 128.182) : icmp_seq=4 ttl =47
t ime=22 . 7 ms
64 bytes f rom 77 .1 53. 128 . 182 : i cmp_seq=5 t tl=47 time=21. 5 ms
-- - google . com ping sta t i st i cs - --
5 packe Ls Lrct nsrn i LLed, 5 r·ece i ved, 0% pa ckeL luss , L i 111e 213741ns
r t t min/avg/max/mdev = 21. 515 /2 1. 927 /22. 701/0.468 ms

7.2.5 ENTRYPOINT
L'instruction ENT RYPO INT permet , tout comme l'instruction CMD, d'exécuter une
commande au démarrage du conteneur résultant.
l:J
0
c
:J
Elle possède les caractéristiques suivantes qui sont équivalentes à celles de l'ins-
0 truction CMD :
\.0
.-t
0
N
• ENTRYPOINT n'est pas jouée lors de la construction de l'image, mais lors du
@ démarrage du conteneur ;
.......
..c: • un Dockerfile peut contenir plusieurs instructions EN TRYPOINT, cependant
O'l
·;:: seule la dernière instruction du fichier sera exécutée.
>-
0..
0
u
Si un Dockerfile contient l'instruction ENTRYPOINT au format exécution et l'instruction
CMD (quel que soit son format), alors le contenu de l'instruction CMD (représentant
dans ce cas des paramètres) sera ajouté la fin de l'instruction ENTRYPOINT.
Si, par contre, un Dockerfile contient l'instruction ENTRYPOINT au format terminal et
l'instruction CMD (quel que soit son format>, alors l'instruction CMD sera ignorée.

Il existe deux modèles pour l'instruction ENTRYPO INT:


7.2 Les instructions d'u n Dockerfile -----------------------El
ENTRYPOINT <command>

ENTRYPOINT ["executable", "param1 ", "param2"l

Le premier est orienté terminal et le deuxième exécution (sur le même principe


que l'instruction RUN).

Lors du démarrage du conteneur (doc ker run), il est possible de surcharger l'instruction
ENTRYPOINT grâce à l'option · · ent ry poi nt, par exem ple, docker run · ·ent rypoin t
ls my·app.

Format exécution
Prenons un exemple d'utilisation de l'instruction ENTRYPO INT au format exécution.
Soit le Dockerfile suivant :

FROMcentos :7
1 ENTRYPOINT ["ping "," google .com "]

Nous construisons l'image :

1 $ docker build · t pi ng · google · exec .

Puis nous démarrons un conteneur :

1 $ docker run -- rm --n ame test ping -google -exec


L'option · · rm permet de supprimer automatiquement le conteneur dès qu'il se ter-
l:J mine. Elle est généralement utilisée dans des cas de tests afin d'éviter la multiplication
0
c
::J
~
,., de création de contene urs. Dans notre exemple, cette option est particulièrement
"O
0 c::; intéressante pour deux raisons :
\.0
.-t
0
.,.,
~
• D'abord, en supprimant le conteneur, son n om sera libéré et ainsi réutilisable par
N
'~
@ ·c un autre conteneur (c'est-à-dire une autre instance de l'image) ; n ous pourrons
....... B
..c:
::;
CO ainsi exécute r la commande doc ker run à plusieurs reprises en préservant le
Ol c
ï:::: 0
c n om du conteneur.
>- c
o.. • Ensuite, notre conteneur représente un simple test sans état : il ne dé marre
u
0 ·3
<.)
::;
"O aucun serv ice et n 'offre aucune utilité particulière après son démarrage ; ainsi,
0
.....
~
c. sa suppression automatique évite une multiplication de conteneurs inutiles et
~
::;
procure donc un gain d'espace évident.
rS
1
"O
0
L'option · ·name permet de nommer le conteneur résultant; dans notre cas, son
c
nom sera « test ». On peut par la suite utiliser ce nom dans d'autres commandes (par
8
(Ç) exemple doc ker exec ).
J 1621 - - - - - - - - - - - - - - - - - - - - - Chapitre 7. Les instructions Dockerfile

Nous souhaitons maintenant affich er les conteneurs actifs afin de voir les corn,
mandes en cours (colonne COMMA ND du résultat).

$ docker ps
CONTAINER ID IMAG E COMMA ND CREATED
STATUS PORTS NAM ES
409d fc 57a7a6 pi ng-google -exec "pi ng goog l e . com " About a min ute aga
Up About a min ute t es t

Comme attendu, la commande en cours du conteneur est pi ng googl e . corn.


Il est également possible d'exécuter une commande directement dans un conteneur
actif ; pour cela, on utilise la commande doc ker exe c. Si, par exemple, nous souhaitons
lister les processus actifs ( ps aux ) dans le conteneur « test », nous utilisons :

$ docker exec t es t ps aux


USER PID %CPU %MEM vsz RSS TTY STAT START TIME COMMAND
root 1 0. 2 0.0 17176 1088 ? Ss 09 : 26 0:00 ping
googl e. com
root 6 0.0 0.0 35888 1452 ? Rs 09 : 26 0:00 ps aux

Le premier processus correspond au pi ng et le second au ps lui,même.


N ous pouvons maintenant arrêter le conteneur grâce à la commande docker stop :

1 $ docker stop test

Format terminal
Reprenons le même exemple, mais en utilisant le format terminal. Soit le Dockerfile
suivant:

FROM centos :7
l:J
0
c
1 ENTRYPOINT pi ng google . com
::J
0 N ous construisons ensuite l'image, puis nous démarrons un conteneur :
\.0
.-t
0
N
@ $ docker bu il d -t ping-goog l e-s he ll .
....... $ docker r un - -rm - -name test ping -googl e-shel l
..c:
O'l $ doc ke r ps
·;::
>- CONTAI NER ID IMAG E COMMA ND CREATED
0..
0 STATUS PORTS NAM ES
u c844052a05e9 pi ng-goog l e-shel l "/bi n/sh -c ' ping goo" 15 seconds aga
Up 14 seconds t es t

La commande en cours est cette fois,ci différente : I bi nI s h - c ' pi ng goo gl e . com '
Il s'agit du pi ng google . com, précédé par /b i n/sh -c. C 'est le fameux problème
d' encapsulat ion de l'exécution d'un bin aire (pin g dans notre cas) par un termin al
applicatif ( I bin I s h - c) lors de l'utilisation du format terminal. Vous trouverez plus
7.2 Les instructions d'un Dockerfile ----------------------11631
d'information à ce sujet dans la section « Terminal ou exécution ? », au début de ce
chapitre.

7.2.6 EXPOSE
L'instruction EXPOSE décrit les po rts du conteneur que ce dernier écoute. Un
port exposé n'est pas directement accessible, et il devra ensuite être mappé (soit
automatiquement, soit manuellement) avec un port de l'hôte exécutant le conteneur.

Hôte Ports

Conteneur Ports
30080

80

33306

d
Maria DB
3306

Figure 7.8 - Mappage de ports entre un conteneur et un hôte

La figure 7 .8 illustre sommairement le mappage de ports entre un conteneur et un


hôte:
l:J
0
c • le conteneur contient les processus Nginx et MariaDB fonctionnant respective-
:J
0 ment avec les ports 80 et 3306 ;
\.0
.-t
0 • le conteneur expose les ports 80 et 3306 afin de les rendre potentiellement
N
@ accessibles avec l'hôte (autrement dit le Dockerfile utilisé pour la construction
.......
..c: de l'image contient l'instruction EXPOSE 80 3306) ;
O'l
·;:: • le port 80 du conteneur est mappé avec le port 30080 de l'hôte ;
>-
0..
0 • le port 3306 du conteneur est mappé avec le port 33306 de l'hôte ;
u
• l'hôte expose les ports 30080 et 33306 ;
• un client ayant accès à l'hôte pourra ainsi accéder au processus Nginx et
MariaDB du conteneur.

Le modèle de l'instruction EXPOSE est :

EXPOSE <port> C<port>...l


J 1641 - - - - - - - - - - - - - - - - - - - - - Chapitre 7. Les instructions Dockerfile

Par exemple :

1 EXPO SE 80 22

C et exemple indique simplement que les ports 80 et 22 du conteneur sont exposés


ou, autrement dit, écoutés.
Le mappage d'un port exposé du conteneur avec un port de l'h ôte peut se faire
automatiquement (dans ce cas le port hôte est cho isi par Docker dans une plage
prédéfinie ) ou manuellement (dans ce cas le port hôte est simplement spécifié ).
111ustrons ces deux méthodes par des exemples. Soit le Dockerfile suivant dont l'image
résultante est un conteneur accessible via SSH :

FROM centos :7
RUN yum update -y && yum i nst al l -y \
openssh -server \
passwd
RUN mkdir /var/run/ss hd
RUN ssh - keygen -t rsa - f /etc/ssh/ssh_host_rsa_key -N "
RUN user add user
RUN echo -e "pass\n pass " 1 (passwd --stdin user)
EXPOSE 22
CMD [" /usr/sbi n/sshd ", "- D"J

opens sh - server est un ensemble d'outils permettant de contrôler à distance une


machine e t de lui transférer des fichiers grâce au protocole O penSSH. passwd est
un outil permettant d'assigner ou de modifier un mot de passe à un utilisateur.

Parcourons rapidement les différentes instructions auxquelles vous êtes à présent


habitué:
l:J
0
• le dossier /v ar /run/sshd est requis par ss hd (démon SSH) pour la gestion de
c
::J privilèges ;
0
\.0 • la commande ssh - keyg en - t rsa - f /e t c/ss h/ssh_h ost_rsa _key - N · · per-
.-t
0
N
met la générat ion d'une clé RSA pour SSH ;
@ • les commandes use r add user et ec ho - e " pass\npass " 1 (passwd -- st din
.......
..c: user) permettent de créer un nouvel utilisateur 11 user 11 dont le mot de passe est
O'l
·;:: 11
>- pass 11 ;
0..
u
0 • finalement, l'instruction C MD démarre le démon SSH. L'option - Dspécifie que
le démon SSH ne doit pas être exécuté en tâche de fond, mais au premier plan
afin qu'il so it toujours accessible.

Pour finir, n ous construisons l'image (cette dernière sera utilisée ci-après) :

1 $ doc ker buil d -t ss h .


7.2 Les instructions d'un Dockerfile ----------------------11651
Mappage automatique
Pour mapper automatiquemen t tous les ports exposés dans le Dockerfile, il suffit de
spécifier l'option - P au démarrage du conteneur :

1 $ docker run -P -d ss h

L'option -d, quant à elle, permet d 'exécuter le conten eur en tâche de fond (ainsi
l'invite de commande reste disponible ). L'identifiant du conteneur est affich é.

Docker choisit un port aléatoire dans une plage. Cette dernière est définie à partir du
fichier /proc/sys/net/ipv4/ip_local_port_range.

Pour découvrir les ports alloués, on peut utiliser la commande docker ps et se


référer à la colonne PO RTS:

$ docke r ps
CONTAI NER ID IMAGE COMMA ND CREATE D
STATUS PORTS NAMES
l d8e61685fe8 ssh "/usr/sbi n/sshd -D" 26 seco nds ago
Up 26 seconds 0. 0. 0. 0:32772 ->22/ t cp condescending_boot h

Dans le résultat ci~dessus, nous constatons que le port 3 277 2 de l'hôte est mappé
avec le port 22 du conteneur (ce dernier étant le port exposé).
Il est également possible d'utiliser la commande docker port <Ide nti fia nt du
con t ene ur > ; dans ce cas, nous obtenons le résultat suivant:

$ docker port 5b7f2d5028bd


1 22/tcp -> 0. 0. 0. 0:32772
Mappage manuel
l:J
0
c ~
,., Le mappage manuel d'un port exposé peut se comprendre sous deux angles différents :
::J
"O
0 c::;
\.0
1. d'une part, spécifier manuellement quels ports do ivent être mappés parmi ceux
.-t
0
.,.,
~
exposés dans le [Link] ;
N
'~
@ ·c 2. d'autre part, spécifier manuellement les ports hôtes à utiliser afin de les mapper
....... B::;
..c: CO avec les ports exposés .
Ol c
ï:::: 0
>- c
o.. c C es deux cas sont couverts par l'option -p de la commande docker run . Voici son
u
0 ·3
<.)
::; principe de fonctionnement :
"O
0
.....
c.
~
~
1-p [<port hôte>:l<port exposé>
::;
rS
1
"O
0
La spécification du port exposé est obligatoire (dan s n otre exemple, 22 ), ce qui
c
8 n'est pas le cas du port h ôte. Il est donc possible grâce à l'option -p de spécifier quels
(Ç) sont les ports exposés sans préciser un port hôte à ut iliser. Par contre, dès que l'on
J 1661 - - - - - - - - - - - - - - - - - - - - - Chapitre 7. Les instructions Dockerfile

souhaite spécifier les ports hôtes à mapper, alors on est contraint de préciser également
quels sont les ports exposés correspondant, ce qui au final est logique.

L'option - p est cumulative, dans le sens où il est possible d'avoir plusieurs fois loption
- p pour la commande doc ker r un.

Reprenons l'exemple ssh. Imaginons que nous souhaitons spécifier manuellement


le port exposé (soit le 22) en le mappant automatiquement avec un port hôte ; la
commande serait:

1 $ doc ker r un -d -p 22 ssh

Et maintenant, si nous souhaitons mapper manuellement le port 22, e t cela en


spécifiant le port hôte, par exemple 35022, nous aurions:

1 $ doc ker r un -d - p 35022 : 22 ssh

Comme mentionné plus haut, l'option -p requiert le port exposé ; nous le


constatons aisément dans les deux exemples ci-dessus avec le port 22. Ainsi, il y
a une redondance avec l'instruction EXPOSE du Dockerfile. En réalité, dans le cadre
de l'utilisation de l'option - p, l'instruction EXPOSE n'est plus utilisée formellement ;
elle devient uniquement informelle : elle permet une lecture rapide et aisée des ports
que le conteneur expose, et donne ainsi des informations sur la nature des services
correspondants. Grâce à un doc ker i nspect sur une image, nous pouvons rapideme nt
nous rendre compte des ports exposés de l'image:

$doc ker i nspect - - forma t= 1 { 1j son .ContainerConfi [Link] Por t s } } 1 ssh


1 { " 22/tcp ": { } }

En résumé
l:J
0
c Soit nous utilisons l'option - Pet, dans ce cas, tous les ports exposés par l'instruction
:J
0 EXPOSE seront mappés automatiquement avec des ports disponibles de la machine
\.0
.-t hôte .
0
N
@ Soit nous utilisons l'option - p autant que nécessaire et, dans ce cas, les ports
.......
..c: exposés sont spécifiés manuellement ; l'instruction EXPOSE devient alors uniquement
O'l
·;:: informelle. Le mappage se fait soit automatiquement (on ne spécifie pas le port hôte,
>-
0.. par exemple - p 22) soit manuellement (on spécifie le port hôte, par exemple - p
0
u 35022 : 22 ).
Pour conclure cette section, reprenons une nouvelle fois l'exemple ssh: l'image a
été construite, le conteneur correspondant démarré et le port hôte est connu (dans
notre cas 35022), ce dernier étant mappé avec le port 22 du conteneur qui fait
référence au processus SSH. On souhaite maintenant se connecter au conteneur par
SSH avec l'utilisateur « user » et le mot de passe « pass » :
7.2 Les instructions d'un Dockerfile ----------------------11671
$ ss h user@l oca l host -p 35022
The authenticity of host ' [localho st J:350 22 ([::1 ] :35022)' can't be
established .
RSA key fi ngerprint is 09 : 7f :b6 : 6b :d5 :83 :3d:db :c5 : la :29 : f8: 7c : f6 :48 : l b.
Are you sure yo u wa nt to conti nue con nect i ng (yes/no) ? yes
Warning : Permanent l y added ' [loca l host ] :35022 ' ( RSA) to t he list of known
hosts .
user@l oca l host 's password :
[use r@ld8e61685f e8 ~ ]$

Pour arrêter le con ten eur, n ous utilisons doc ker st op :

1 docker st op ld8e61 685fe8

7.2.7 ADD
L'instruction A OD permet d'ajouter un fichier dan s l'image. La source du fichier
(d'où il provient) doit être disponible à travers la machine qui construira l'image (par
exemple , un fichier local ou distant si une connexion distante est possible ). Le fichier
sera définitivement ajouté dans l'image, dans le sens où il n e s'agira pas d'un raccourci
ou d 'un alias.

L'instruction ADD est très proche de l'instruction COPY, néanmoins il existe quelques
différences qui sont détaillées dans cette section et la suivante.

Les modè les possibles sont :

ADD <src>... <dest>

ADD ["<src>",... "<dest>"l


"'Cl
0
c
:::i
~
,.,
0 "O
[Link]; < s r c> désigne le ch emin local ou distant (une URL, par exemple ) du fichier à
\.0
.-t ~ ajouter à l'image. < sr c> peut être répété autant de fois que souhaité et peut contenir
V
des caractères génériques (par exemp le « * » ).
0
N V
'ii
@ ·c
....... [Link];
..c CO
O'l c
0
Vutilisatio n de caractè res gén ériques dans un ch emin source répond aux mêmes
ï::::: c
>-
o. c règles utilisées pour la fonction Match du langage Go dont la documentation est
u
0 ·3ù accessible à :
:::;
"O
0
....
c.
[Link]
~
~
:::;
rS <ds t > désign e le ch emin de destination du ou des fichiers à ajouter dan s l'image.
1
"O
0
c
8 Si <s rc> désigne un fichier local, alors ce dernier doit être disponible sur la machine
(Ç) construisant l'image <celle qui exécute le docker bu i l d) et non sur la machine hôte
J 1681 - - - - - - - - - - - - - - - - - - - - Chapitre 7. Les instructions Dockerfile

(celle qui exécute doc ker r un), simplement car l'ajout se fait à la construction de
l'image.

Par exemple:

AOD http ://code . jque [Link]/jq ue ry -2. [Link]. js / t mp/jq [Link]


AOD tes t * doss ierRel ati f/
1 AOD [ "/home/vagrant/add/testl ", "/home/vag rant/add/test2 ", "/doss i erAbsol u/ "J

Le premier exemple téléchargera le fichier [Link] à l'URL indiquée,


puis le déposera dans le dossier /tmp de l'image en le renommant par [Link].

En réalité, nous éviterons d'utiliser une source au format URL. En effet, la fonctionnalité
de téléchargement de l'instruction ADD est limitée : elle ne supporte pas les URL
protégées par un mécanisme d'authentification. Nous préférerons donc utiliser une
instruction RUN (par exemple, RUN wget... ou RUN curl..J à la place.

Le deuxième exemple prendra tout fi chier du dossier courant (de la machine qui
construit l'image) dont le modèle de nom correspond à« test* » (par exemple« testl »
ou « testlambda ») et les déposera dans le dossier « dossierRelatif/ » dont le chemin
est donné relativement (car il n'y a pas de slash en début de chemin) par rapport au
chemin courant dans le conteneur.
Pour finir, le troisième exemple prendra les fichiers testl et test2 (dans la machine
qui construit l'image) dont les chemins sont donnés spécifiquement (c'est-à-dire en
absolu) ; ils seront déposés dans le dossier « /dossierAbsolu/ » qui lui aussi est donné
spécifiquement.
Le dossier courant, ou plutôt le chemin courant de la machine qui construit
l'image, correspond simplement au chemin spécifié qui est donné en paramètre de la
commande docker build (le fameux « . » en fin de commande).
Lors de la construction d'une image, le chemin courant dans le conteneur est « / »,

l:J
à moins qu'il n'ait été changé par une instruction WORKDIR (voir chapitre 8 ).
0
c Afin de bien comprendre le principe du chemin courant dans le conteneur, prenons
::J
0
\.0
un exemple complet.
.-t
0
N Soit le Dockerfile suivant :
@
.......
..c:
O'l FROM centos :7
·;::
>- RUN pwd > /tmp/i nitialPath
0..
0 RUN mkdi r out put
u RUN cd out put
RUN pwd > /tmp/pat hAfterOutp ut
AOD t es tl . I
AOD [ "t est2" , "/out put / "]
CMO l s /output

Nous con sidérons que les fichiers testl et test2 existent et sont dans le même
dossier que le Dockerfile.
7.2 Les instructions d'u n Dockerfile -----------------------11691
Les instructions de type RUN pwd > file n ous permettent de sauvegarder le chemin
courant dans des fichiers que n ous déposon s dan s le dossier /tmp du con teneur.
L'instruction CMD ls /output nous permet , quant à elle, de lister les fichiers et
dossiers dans le dossie r /output au démarrage du conteneur.
Nous con struisons l'image :

1 $ docker build -t add .

Puis nous démarron s un conten eur:

1 $ docker run -- rm add

Le résultat est :

1 test2
N ous voyon s logiquement le [Link] ier test2 qui a été déposé par l'instruction A OD
["test2" , 11 /output/'1]. Étant donné les instruction s RUN cd output puis AOD testl
./, nous pourrions cependant nous attendre à ce que le fi.c hier testl soit aussi dan s
le dossie r out pu t, car l'instruction A OD utilise le ch emin relatif « ./ » et, selon
l'instruction RUN, n ous pounion s pen ser être dan s le dossier output ... M ais ce n 'est
pas le cas : rappelons-nous que ch aque instruction dans un Dockerfile est exécutée de
manière indépendante dans le but de créer des images intermédiaires pour le système
de cach e. Ainsi, à ch aque instruction le contexte courant redevient celui par défaut
(dans notre cas « / » ), et notre [Link] testl se trouve donc à la racine. En démarrant à
nouveau le conteneur, mais en surch argeant le point d 'entrée par un ls / :

1 $ docker run -- rm add ls I

nous obten on s la liste des fichiers et dossiers se trouvant à la racine, n otamment


l:J
0
testl.
c
::J
~
,.,
0 "O Pour confirmer les explication s ci-dessus, regardons les fich iers qui ont sauvegardé
c::;
\.0 l'état du ch emin courant:
.-t
0
.,.,
~

N
'~
@ ·c
....... B::;
$ docker run -- rm add cat / t mp/ i nitialPa t h
..c: CO
I
Ol c
ï:::: 0
c $ docker run -- rm add cat /tmp/pathAfterOutput
>-
o..
0
c
·3
1I
u <.)
::;
"O
0
..... Dan s les deux cas, no us con statons bien que le ch emin courant est « / ».
c.
~
~ M a is alors, si le dossier courant dan s le conten eur est toujours « / » , quelle est la
::;
rS différen ce entre un chemin absolu et un ch emin relatif ? En réalité, le dossier courant
1
"O
0
du conten eur n 'est pas toujours « / » ; il peut se paramétrer grâce à l'instruction
c
WORKDIR, et c'est dan s ce cas qu'il existe une différen ce entre un ch emin absolu et
8
(Ç) un ch emin relatif.
J 1101 - - - - - - - - - - - - - - - - - - - - - Chapitre 7. Les instructions Dockerfile

Maintenant que n ous avons bien compris comment fon ctionnent les ch emins
à spécifier dans l'instruction AOD, regardons la différence entre les deux modèles :
le premier (AOD <src> ... <<lest > ) est p lus facile à lire, ma is le deuxième (AOD
["<src>" ,... "<<lest >"]) permet d'ajouter des espaces dans les chemins san s devoir les
échapper. Dans la mesure où la bonne pratique d'écriture des noms de fichiers et de
dossiers consiste à éviter les espaces, nous préférerons utiliser la première forme.

Quand une facilité de /'instruction ADD devient un inconvénient


L'instruction AOD offre égale ment une facilité supplémenta ire : lorsque la source est
un fichier local de type archive tar avec un format de compression reconnu (identity,
gzip, bzip2 or xz), alors le fi chier est automatiquement décompressé en un dossier.

Lorsque la source est un fichier défini par une URL, il ne sera pas décompressé, et ce
même s'il correspond à une archive de format reconnu.

Pour illustrer le principe de décompression automatique, prenons un exemple.


Soit le Dockerfile suivant :

FROM centos : 7
AOD word press- 4. 4. 1- f r_FR. tar . gz /tmp /
1 CMD l s /tmp

Nous considérons que le fichier wordpress-4.4.1-fr_ [Link] existe et réside dans


le même dossier que le Dockerfile ; le cas échéant, il peut être téléchargé sur le site de
WurJPress ([Link] [Link]/wurJpress-4 .4.1-fr_FR.[Link]).
Nous construisons l'image et démarrons le conteneur:

$ doc ker bu il d -t unta r


$ doc ker r un -- rm unta r
ks-sc r ipt -06 Fe P3
l:l
1 word press
0
c
:::i N ous remarquons que le fichier wordpress-4.4.1-fr_FR.[Link] n'est pas présent, mais
0
\.0 nous apercevons une entrée« wordpress ». Essayons de voir ce qu'il y a à l'intérieur :
.-t
0
N
@ $ doc ker r un -- rm untar ls / t mp/wordpress
.......
..c index. ph p
O'l
'i:
l icens [Link]
>-
0.
readme. ht ml
0 wp- activate . php
u wp-a dmi n

N ous constatons aisément qu'il s'agit bien de l'archive qui a été décompressée, car
elle contient des fichiers et des dossiers du CMS WordPress.
À première vue, il s'agit d'une fonctionnalité utile, et pourtant elle constitue deux
désavan tages majeurs :
7.2 Les instructions d'un Dockerfile ----------------------El
l , Tout fichier tar compatible sera décompressé. Si nous souhaitons simplement
ajouter une archive tar sans la décompresser, cela n'est pas possible (sauf en
utilisant un format source de type URL).
2. Il n'est pas toujours aisé de savoir si le format de compression est compatible
avec la décompression automatique. Nous pouvons donc penser qu'un fichier
sera décompressé, alors que cela ne sera pas le cas.

C es deux désavantages vont nous inciter à utiliser l'instruction COPY (détaillée


dans la prochaine section) au lieu de l'instruction ADD. En effet , COPY ne décom-
presse pas les archives. Ainsi, nous serons sûrs que le fichier à ajouter ne sera pas
modifié, et si nous souhaitons le décompresser, nous le ferons alors spécifiquement,
grâce à une instruction RUN.

Le slash à la fin de la destination... ?


Lorsque la destination se termine par un slash (/), cela signifie simplement qu'elle
représente un dossier et que la source y sera ajoutée telle quelle, c'est-à-dire que le
nom du fichier ne sera pas modifié, S i la destination ne contient pas de slash à la
fin, alors le dernier élément du chemin (c'est-à-dire tout ce qui suit le dernier slash)
deviendra le nouveau nom de la source, qui sera ainsi renommée.
Imaginons un Dockerfile qui contient entre autres les instructions suivantes :

AOD testl /tmp/ out put l

1 AOD t est 2 /tmp / out put 2/

Dans le premier AOD, le fichier testl sera déposé dans le dossier /tmp du conteneur
avec pour nouveau no m outputl.
Dans le second ADD, le fichier test2 sera déposé dans le dossier /tmp/output2 et
gardera son nom.
l:J
0
c ~
,.,
0
::J
"O 7.2.8 COPY
c::;
\.0
.-t
0
.,.,
~
L'instruction COPY permet d'ajouter un fichier dans l'image. La source du fichier
N
'~
@ ·c (d'où il provient) do it être un fichier local à la machine qui construira l'image. Le
B
.......
..c:
::;
CO
fichier sera définitivement ajouté dans l'image, dans le sens où il ne s'agira pas d'un
Ol c raccourci ou d 'un alias.
ï:::: 0
>- c
o.. c
0 ·3 L'instruction COPY est très proche de l'instruction ADD, car elle compose avec
u <.)
::;
"O
0
les mêmes propriétés suivantes (voir la section précédente pour plus de détails) :
.....
c.
~ • le principe des chemins courants dans la machine construisant l'image et dans
~
::;
le conteneur ;
rS
"O
1
• l'utilisation de la fonction Match du langage Go pour l'interprétation des
0
c caractères géné riques ;
8
(Ç) • l'interprétation du slash optionnel à la fin de la destination.
J 1121 - - - - - - - - - - - - - - - - - - - - - Chapitre 7. Les instructions Dockerfile

Toutefois, il existe des différences do nt les principales sont les suivantes :


• la source doit être un fichier local, et il n'est pas possible de spécifier une URL ;
• l'instruction C O PY ne décompresse pas automatiquement une archive tar
compatible.

Les modèles possibles sont :

COPY <src>... <dest>

COPY r'<src>",... "<dest>"l

<src> désigne le chemin local du fichier à ajouter à l'image. <s r c> peut être répété
autant de fo is que souhaité et peut contenir des caractères génériques (par exemple
« * »).

<ds t > désigne le chemin de destination du ou des fichiers à ajouter dans l'image.
Par exemple :

COPY test* dossierRel at i f/


1 COPY [" /home/vagrant/add/testl ", "/ home/vagrant/add/test2", "/doss i erAbso l u/ "J

Le principe de fonctionnement de ces deux exemples est le même que celui


expliqué pour l'instruction ADD. En résumé, le premier exemple prendra tout fichier
du dossier courant dont le modèle de nom correspond à « test * » et les déposera dans le
dossier « dossierRelatif/ » du conteneur. Le deuxième exemple prendra les fichiers testl
et test2 dans /h ome/vagrant/add/ et les déposera dans le dossier « /dossierAbsolu/ » du
con teneur.

l:J Comme cela est mentionné dans la précédente section, nous utiliserons systémati-
0
c
:J quement l'instruction COPY (et non ADD>, notamment pour éviter les problèmes de
0
\.0
décompression automatique.
.-t
0
N
@
.......
L'instruction COPY, tout comme l'instruction A DD, pe rme t d 'ajouter plusieurs
..c: fichiers dans l'image, d'un seul coup. Pourtant, cette pratique n'est pas recommandée,
O'l
·;::
>-
0..
afin de pouvoir explo iter au mieux le cache Docker.
0
u Avant d'illustrer cela par un exemple, regardons tout d'abord comment fonctionne
le cach e avec les instructions AOD et COPY; le principe est simple : si au moins un
fi chier source est modifié (c'est-à-dire que son contenu est modifié ), alors l'instruction
sera considérée comme changée et sera donc rejouée (pas de cache ut ilisé), ainsi que
toute instruction suivante (principe général du cache Docker).
Voyons maintenant un exemple. Soit les deux Dockerfile suivants :
7.2 Les instructions d'u n Dockerfile ----------------------El
#Dockerfil e mult icopy l
FROM cent os :7
CO PY test l . t ar . gz /tmp/
RUN t ar xz f /tmp/testl . tar . gz
CO PY test2 . t ar .gz /tmp/
RUN t ar xz f /tmp/test2 . tar . gz

#Dockerfi le multicopy2
FROM centos :7
CO PY t es t l . t ar . gz tes t2 . t ar .gz / t mp/
RUN tar xzf /tmp/ t es t l . ta r . gz
RUN t ar xz f /tmp/test2 .tar . gz

Nous construisons les images :

$ docker build -t mul t icopy l


1 $ docker bui l d -t multicopy2

Dans les deux cas, la construction n'utilise pas le cache Docker car il s'agit de la
première tentative.
Modifions les fichiers [Link] (pour chaque Dockerfile ) et reconstruisons les
images:

$ docker build -t multicopy l .


Sending buil d cont ext t o Doc ker daemon 7.545 MB
Step 1 : FROM centos :7
---> 6Ue6Ja8e4UJU
Step 2 : CO PY t estl. tar . gz / tmp /
---> düe43d b03e6c
Removing intermed i ate conta i ner 4d3868 594a50
Step 3 : RU N t ar xzf / t mp/testl .tar . gz
---> Run ni ng i n 9202535ddaed
--- > 39a9decd83f b
Removing i nt ermed i at e conta i ner 9202535ddaed
l:J Step 4 : CO PY test [Link] . gz /tm p/
0
c ~
,., --- > e9536947ac28
::J
0 "O Remov i ng i ntermed i at e container eace3434f ea3
c::;
\.0 Step 5 : RUN tar xzf / t mp/test2 . tar . gz
.-t
0
.,.,
~
--- > Runn i ng i n 8f58bc549131
N
'~
·c
---> 6d0ee l 2la384
@ Remov i ng i nt ermediate cont ainer 8f 58bc549131
....... B::;
..c: CO Succes sfully bu il t 6d0eel2la384
Ol c
ï:::: 0
>- c
o.. c $ docker build -t mul t i copy2 .
u
0 ·3
<.) Sending buil d cont ext t o Doc ker daemon 7.545 MB
::;
"O
0 Step 1 : FROM cent os :7
.....
~
c. --- > 60e65a8e4030
~ Step 2 : CO PY testl. tar . gz t est 2. tar . gz /tm p/
::;
rS ---> 9alf8af948f 0
1 Removing intermed i at e container 95ce5740585c
"O
0
c Step 3 : RUN tar xzf / t mp/test l . tar . gz
8 --- > Runn i ng i n 32el9bb0e2e0
(Ç) ---> 5dc b5162ec7c
J 1141 - - - - - - - - - - - - - - - - - - - - - Chapitre 7. Les instructions Dockerfile

Remov i ng i nt ermed i at e conta i ner 32 el 9bb0e2e0


Step 4 : RUN tar xz f /tmp/t est 2. t ar . gz
---> Run ni ng i n a06fca73ed6c
--- > d33cl3e5bbc0
Remov i ng i nte rmed i ate cont ai ner a06fc a73ed6c
Successfull y bui l t d33cl3e5 bbc0

Là encore, le cache n'est pas utilisé : dans le premier Dockerfile, la copie de


[Link] [Link] étant placé en début de fichier, toutes les instructions suivantes seront
rejouées; dans le deuxième Dockerfile, la constatation est la même (rappelons,nous
que dès qu'au moins un fichier d'une instruction COPY est modifié, alors cette dernière
est considérée comme changée).
Modifions les fichiers test2 (pour chaque Dockerfile ) et reconstruisons encore une
fo is les images :

$ doc ke r bui l d -t mult i copyl .


Send i ng bu i ld context t o Doc ker daemon 4. 096 kB
St ep 1 : FROM ce ntos :7
---> 60e65a8e4030
St ep 2 : COPY test l. t ar. gz / t mp/
--- > Using cache
---> d0e43db03e6c
St ep 3 : RUN t ar xzf / t mp/t est l .tar . gz
---> Usi ng cache
--- > 39a9decd83fb
St ep 4 : COPY test2. t ar. gz / t mp/
---> e27d642lf69 6
Removing i ntermed i ate conta i ner 64173406dc32
St ep 5 : RUN t ar xzf / t mp/t es t Z.t ar .gz
---> Running i n 10f9ded2eb05
--- > f8c775d61595
Remov i ng i nte rmed i at e cont ai ner 10f9ded2eb05
Successfully built f8c775d 61595

$ doc ke r bui l d -t mu lt i copyZ .


l:J
0
Send i ng bu i ld context t o Doc ker daemon 4. 096 kB
c
::J
St ep 1 : FROM ce ntos :7
0 ---> 60e65a8e4030
\.0
.-t
St ep 2 : COPY test l . t ar. gz t est Z. t ar. gz / t mp/
0
N
--- > c3f 989c037a2
@
Remov i ng i nt ermed i ate cont ai ne r d7 f acd75577e
....... St ep 3 : RU N t ar xzf / t mp/t es t l .tar .gz
..c:
O'l
---> Run ni ng i n a93769d926ff
·;:: ---> d67 aa 62ef 046
>-
0..
0
Remov i ng i nte rmed i at e conta i ner a93769d9 26f f
u Step 4 : RU N tar xz f /tmp/t est [Link] . gz
--- > Run ni ng in ee02c7 5a d812
---> b8ecl0c61515
Remov i ng i nte rmed i ate cont ai ner ee02c75ad8 12
Successfull y bui l t b8ecl0c61515

N ous constatons cette fois,ci que la copie et la décompression de [Link] dans


le premier Dockerfile utilisent le cache (instruction Using cache), ce qui n'est toujours
7.2 Les instructions d'un Dockerfile ----------------------l 11sl
pas le cas dans le deuxième Dockerfile ; cela démontre bien l'utilité de séparer l'ajout
de plusieurs fichiers en autant d'instructions.

7.2.9 VOLUME

l.:instruction VOLUME permet de créer un point de montage dans l'image. C e dernier


se référera à un emplacement, appelé volume, dans l'hôte ou dans un autre conteneur.

Hôte

Conteneur

data

l
i
.......
/var/home/vagranU ·

Figure 7.9 - Point de montage dans un conteneur

La figure 7.9 illustre un po int de montage /tmp/data dans un conteneur qui


référence l'emplacement /var/home/vagrant/data ; autrement dit, le dossier data du
conteneur peut être vu comme un lien vers le dossier data de l'hôte. À noter que
l:J dans cet exemple les deux dossiers (dans le conteneur et dans l'hôte) sont nommés de
0
c
::J
~
.
., manière identique (data) , cependant leurs noms pourraient être différents.
"O
0 c::;
\.0
.-t
0
.,.,
~ Le montage et l'exploitation de volumes dans un conteneur sont un élément clé et
N
·~ complexe de Docker. Cette section se focalisera sur l'instruction VOLUME, et sur son
@ ·c
B utilisation correcte en pratique. Des exemples complets ont été donnés dans les autres
....... ::;
..c: CO
chapitres de cet ouvrage.
Ol c
ï:::: 0
>- c
o.. c
u
0 ·3
<.)
Les modèles possibles sont :
::;
"O
0
.....
c.
~
~
VOLUME <path>...
::;
rS
1
"O
0
c
8 VOLUME C"<path>",...l
(Ç)
J 1161 - - - - - - - - - - - - - - - - - - - - - Chapitre 7. Les instructions Dockerfile

Par exemple :

VO LUME / tmp /d at a
1 VOLUM E [ "/ t mp/dat al", "/ tmp /data2" ]

Nous préférerons utiliser le modèle VOLUME <path> ... , ce dernier étant plus
lisible ; et pour limiter le nombre d'images intermédiaires, nous n'utiliserons qu'une
seule instruction VOLUME, avec au besoin plusieurs chemins, par exemple :

VO LUME /chemi nl /doss i erl \


1 /chemin2/dossier2 \

Prenons maintenant un exemple simple pour bien comprendre le fonctionnement


de de l'instructio n VOLUME :

FROM centos: 7
VO LUME /tmp/data
1 CMD ping loca lhost

L'instruction CMD ping localhost permet de laisser le conteneur actif une fois qu'il
a démarré.
Nous construisons l'image, puis démarrons le conteneur:

$docker buil d -t volume .


1 $ docker r un -d -- name vol ume- conteneur vo l ume

Nous n'avons volontairement pas mis l'option - - rm afin de conserver le volume


monté lorsqu'on arrête le conteneur. Pour rappel, l'option -d permet d'exécuter le
conteneur en arrière-plan (ainsi l'invite de commande reste disponible).
Grâce à un docker i nspect, nous pouvons voir les volumes montés dans un
conteneur:
l:J
0
c $docke r i nspect --format= 1 {{j son .Mounts} }1 volume-contene ur
::J
0 [ {" Name" :" 4bla 5d7749dded44d569f15ce55c l f725 0bbadebb4b7747190e5656ecb71lc55 ",
\.0 "Source" :" /var/lib/doc ker/volumes /4bla5 ... llc55/_data",
.-t
0
N
1 "Des t i na t i on " : "/ tm p/da ta " . "Dr i ver " : "l oca 1" . "Mode " : " " . "RW" : t r ue l ]
@
....... Dans notre exemple, on voit que le volume du conteneur /tmp/data est basé sur
..c:
O'l
·;:: le dossier /var/lib/docker/volumes/4bla5 .. .1 lc55/_data dans l'hôte. Listons ce volume
>-
0.. depuis le conteneur :
0
u
1 $ docke r exec volume-conteneur ls /tmp /d at a

Le dossier est vide. Faisons la même chose depuis l'hôte (à faire avec un utilisateur
root) :

1 $ sudo l s /v ar / li b/d ocker/volumes/4bla 5 .. . l l c55/_dat a


7.2 Les instructions d'u n Dockerfile -----------------------11111
Là encore, le dossier est vide. Ajoutons maintenant un contenu :

1 $ docker exec vo l ume-cont eneur /bi n/sh -c 'echo "Hel lo " > / t mp/dat a/ hel l oîest'

A findes'assurer que la commandeecho "Hello " > /tmp/d at a/ hel loTest soitbien
exécutée en t ièrement dans le conteneur, on l'encapsule par terminal applicatif avec
/bin/sh ~c. En omettant ce procédé, la partie > /tmp / dat a/he l l oTes t serait exécutée
dans l'h ôte, ce qui n'est évidemmen t pas souhaité.
Listons une n ouvelle fois le volume :

$ docker exec vo l ume- conteneur l s /tmp/dat a


hel l oTest
$ sudo ls / var/ l i b/do cker /volumes/4bl a5 . .. l lc55/ dat a
1 hel loTest

Nous y voyons bien le [Link] helloTest fraîchement créé, quelle que soit la méthode
employée pour lister le volume. A rrêtons maintenant le conteneur :

1 $ docker stop vo l ume -conteneu r

S i n ous listons à n ouveau le volume (depuis l'hôte uniquement car le conteneur


est arrêté ) :

1 $helsudo
l s /var/lib/doc ker/vol umes/ 4b l a5 .. . l lc55/_data
l oî est

Nous y voyons touj ours le [Link] h elloTest: le comportement attendu est bien
respecté. Toutefois, il serait utile que le chemin dans l'hôte soit plus explicite ; pour
cela, n ous utilisons l'option - v de doc ker ru n.
Tout d'abord, supprimons le conteneur afin de libérer l'espace utilisé par ce dernier
l:J et pour pouvoir réutiliser son nom :
0
c
::J
~
,.,
0
\.0
"O
c::; 1 $ docker rm volume -conteneur
.-t
0
.,.,
~

N
'~
·c
À noter que le volume dans l'h ôte est aussi supprimé. Ensuite, démarrons le
@
....... B::; conteneur avec l'option -v :
..c: CO
Ol c
ï:::: 0
>- c
o.. c $ do cke r run -d -v /va r / home/vagrant /data: /tmp/ data -- name volume-conteneu r
u
0 ·3
<.)
::;
"O
1 vol ume
0
.....
c.
~ /var/home/vagrant/data représente le ch emin dans l'hôte et /tmp/data le chemin
~
::; dans le conteneur. C réons à n ouveau un [Link] dans le volume ( rappelons~nous que
rS
1 la suppression du conteneur a également supprimé le volume ) :
"O
0
c
8
(Ç) 1 $ docker exec vo l ume -conteneu r /b i n/sh -c 'echo "Hello " > / t mp/da ta / hel l oTest'
Chapitre 7. Les instructions Dockerfile

Maintenant, listons le contenu du vo lume depuis l'hôte :

$ sudo l s /var/ home/vagrant/data


1 helloî es t

Revenons sur la valeur de l'option ,v, notamment la partie qui décrit le point
de montage dans le conteneur, c'est~à~dire /tmp/data: nous remarquon s que cette
information fait double emplo i avec l'instruction VOLUME du Dockerfile. En réalité,
si nous spécifions l'option ~v sur un même volume défini par l'instruction VOLUME,
alors l'effet fonctionnel de cette dernière devient nul. Reprenons l'exemple :
• D'abord, nous arrêtons et supprimons le conteneur:

$ doc ker st op vol ume-conteneu r


1 $ doc ke r rm vol ume -cont eneur
• N ous modifions le Dockerfile en commentant l'instruction VOLUME :

FROM centos :7
# VOLUME / t rnp/dat a
1 CMD pi ng l oca l host

• N ous construisons et démarrons l'image, puis nous ajoutons un fichier au


volume:

$doc ker buil d -t volume .


$ doc ker r un -d -v /v ar /home/vag rant /data: / t mp/ data -- name vol ume-con t eneur
vo l ume
1 $ doc ke r exec vo l ume-contene ur /bi n/sh -c 'echo "He l lo " > /tmp/da t a/hel loîest '

• N ous effectuons un doc ke r i nspect afin de constater l'état du volume et son


point de montage :
l:J
0
c
::J
0 $doc ker i nspect -- format =' f{json .Mo un tsll ' vo lume -co nteneur
\.0
.-t
0
1 [f "Sour ce ":" /va r/home/v agrant/data " ," Des tina t i on ":" / t mp/ data " , "Mode ":"" ," RW": t r ue}]
N
• Pour finir, nous listons le volume :
@
.......
..c:
O'l
·;::
>- $ l s /var /home/vag ra nt/dat a/
u
0..
0 1 hel l oî est
A insi, le résultat avec ou sans l'instruction VO LUME dans le Dockerfile reste
le même dès le moment où l'on utilise l'option - v lors du docker r un. C ependant,
il existe un cas où l'instruction VO LUME reste malgré tout utile : elle apporte une
métadonnée qui décrit le point de montage dans le conteneur du volume dans l'hôte.
Nous nous efforcerons donc d'inclure l'instruction VOLUME au Dockerfile, et cela
même si son effet est surchargé lors du démarrage du conteneur.
7.3 Bonnes pratiques --------------------------11791
Pour terminer cette section, arrêtons,nous sur le format du chemin : faut,il le
spécifier en relatif ou en absolu ? Par sa conception, l'instruction VOLUME est
toujours exécutée à partir du chemin«/», et ce même si un précédent WORKDIR
avait changé le chemin courant ; en conséquence, la présence d'un « / » initial dans
le chemin de l'instruction VOLUME ne change rien. Cependant, pour qu'il ne puisse
y avoir d'ambiguïté à la lecture du chemin, nous le spécifierons toujours.

Les volumes nommés


Depuis la version 1.9 de Docker, il est possible de créer à l'aide de la commande
docker vol urne create des volumes nommés. En pratique, cette nouveauté permet de
ne plus recourir aux data containers c'est-à-dire aux conteneurs dont la seule vocation
est de référencer des volumes. Il est ainsi possible de créer un volume avant même
d'avoir créé un conteneur, puis de l'associer à un ou plusieurs conteneurs. Nous
verrons un exemple de ces volumes nommés dans le chapitre suivant (dans la section
consacrée à l'installation d'un registry privé).

7 .3 BONNES PRATIQUES
Pour conclure cette section, nous allons récapituler les bonnes pratiques de l'écriture
d'un fichier Dockerfile.

Généralités
Pour les instructions CMD et ENTRYPOINT, nous préférerons utiliser le format
exécution (par exemple CMD [11 ping11 , 11 localhost11 ]) afin d'assurer un arrêt propre d'un
conteneur.
Pour l'instruction RUN, nous préférerons utiliser le format terminal pour des
raisons de lisibilité.
Afin d'optimiser la gestion du cache Docker, nous trierons les instructions en
l:J
0
c fonction de la possibilité qu'elles soient modifiées dans le temps.
::J
0 L'ordre ci,dessous apporte un bon niveau fonctionnel et une bonne lisibilité. Nous
\.0
.-t
0
tâcherons de l'appliquer autant que possible :
N
@ 1. FROM
.......
..c:
O'l
2. MAINTAIN ER
·;::
>-
0.. 3. ARG
0
u 4. ENV, LABEL
5. VOLUME
6. RUN, COPY, WORKDIR
7. EXPOSE
8. USER
9. ONBUILD
10. CMD, ENTRYPOINT
J 1 sol--------------------- Chapitre 7. Les instructions Dockerfile

Dans toute instruction, nous n'utiliserons pas la commande sudo.

FROM
U n fichier Dockerfile contiendra une et une seule instruction FRO M , et nous
spécifierons aussi formellement la version (le tag ) de l'image source à utiliser, par
exemple FRO M centos:7.

RUN
Lo rs de l'installation de paquets avec l'instruction RUN, nous mettrons systéma~
tiquement à jour l'image courante et nous n 'utiliserons qu'une seule instruct ion,
c'est~à~dire :

RUN yum update -y && yum i nst all -y\


ht t pd \
mari adb -server \
1 php php -mysql

Nous éviterons de ch an ger le chemin courant avec l'instruction RUN et nous


utiliserons plutôt l'instruc tion WORKDIR (voir le chapitre 8 ).

CMD et ENTRYPOINT
Nous utiliserons en priorité l'instruction ENTRYPOINT (au format exécution, comme
mentionné ci~dessus) . L'instruction CMD sera utilisée si le point d'entrée do it être
surchargé partiellemen t (dans ce cas, l'instruction sera combinée avec EN TRYPO IN T)
ou complètement (dans ce cas l'instruction EN TRYPOIN T ne sera pas utilisée).
Un fichier Dockerfile ne contiendra au maximum qu'une seule instruction CMD
et ENTRYPO IN T.

EXPOSE
l:J
0
Bien que l'instruction EXPOSE ne soit utile que si nous spécifions l'option ,p au
c démarrage du conteneur, n ous n ous efforcerons de l'employer afin de renseigner
:J
0
\.0
clairement sur les ports (la nature des services) qu'utilise le conteneur.
.-t
0
N
@
ADDetCOPY
.......
..c: Nous utiliserons systématiquement l'instruction COPY au lieu de ADD, ceci afin
O'l
·;::
>- d 'éviter des comportements imprévisibles liés à la décompression automatique des
0..
0 archives tarde l'instruction A OD.
u
Nous préférerons utiliser le modèle COPY <src> ... <dest > (au lieu de COPY
["<src>" ,... "<dest >"]) car il est plus agréable à lire et à maintenir. Dans des cas
exceptionnels, o ù la bon ne pratique de l'écriture des n oms de fichiers et de dossiers
n 'est pas respectée, nous utiliserons l'autre forme.
N ous utiliserons une instruction C OPY par fichier à ajouter, ceci afin d 'optimiser
l'utilisation du cache Docker.
7.3 Bonnes pratiques ---------------------------El
VOLUME
Même si l'instruction VO LUME devait être surchargée lors du docke r run , nous nous
efforcerons de la mettre dans le Dockerfile afin de renseigner sur les points de montage
du contene ur.
Le chemin commencera toujours par un « / » afin d'éviter toute confusion ,
notamment si le Dockerfile contient des instructions WORKDIR.
Nous utiliserons une seule instruction VO LU ME avec le modèle VOLU ME
<path> ... et au besoin plusieurs chemins :

1 VOLUME /cheminl/dossier l \
/c hemi n2/doss i er2 \

ENV, LABEL et ARG


C es commandes seront expliquées en détail dans le chapitre 8.
Afin de limiter le nombre de couches, on regroupera les variables d'en vironnement
(EN V) définie dans un Dockerfile en une instruction. O n procédera de la même
manière pour les labels (LA BEL).
S i cela est nécessaire, on préférera surcharger la variable d'en v ironnement PATH
avec les chemins d'éventuels nouveaux exécutables installés dans l'image, au lieu de
devo ir spécifier le chemin absolu de l'exécutable à chaque ut ilisation.
Les instructions ARG seront toujours placées avant les instructions EN V et
LABEL.
Lorsqu'une variable d'env ironnement peut être surch argée lors de la construction
d'une image, alors on appliquera une utilisation conjo inte des instructions ENV et
A RG, c'est-à-dire :

l:J
0
c ~
1 ARG var i abl e
ENV var i abl e $( var i abl e: -valeur ParDéfaut l
::J ,.,
"O
0 c::;
\.0
.-t
0
.,.,
~

N
@
'~
·c En résumé
....... B::;
..c:
Ol
CO
c N ous avons décrit dans ce chapitre les principales instructions de Dockerfile. À
ï:::: 0
>- c travers différents exemples, nous avons abordé les principaux cas d'usage de ces
o.. c
u
0 ·3
<.)
commandes.
::;
"O
0
.....
Il est temps à présent d'aborder les commandes mo ins fréquentes et d'étudier quelques
c.
~ fonc tio nnalités plus avancées de Docker.
~
::;
rS
1
"O
0
c
8
(Ç)
"'O
0
c:
:::i
0
\.0
r-1
0
N
@
......,
..c:
en
·;::
>-
0..
0
u
8
Usage avancé de Docker

Nous avons vu dans les précédents chapitres comment installer Docker sur différents
environnements, comment créer des conteneurs, comment utiliser le client Docker
et comment créer des images à partir de Dockerfile.
L'objectif de ce chapitre est d'aborder des usages plus avancés de Docker.
Nous y décrirons quelques instructions Docke [Link] un peu mo ins courantes que celles
qui ont été présentées dans les chapitres précédents. Nous découvrirons ensuite
Notary, le système de signature d'images proposé par Docker. Enfin, nous verrons
comment installer un Docker registry privé.

8.1 DOCKERFILE : QUELQUES INSTRUCTIONS


l:J
0 ..
c
::J
~
,.,
"O
SUPPLEMENTAIRES
0 c::;
\.0
.-t
0
.,.,
~
Dans le chapitre 7, nous nous sommes attachés à décrire les commandes [Link]
N
'~
@ ·c les plus courantes. Dans cette nouvelle section, nous allons décrire celles que nous
B
.......
..c:
::;
CO
n'avons pas encore vues .
Ol c
ï:::: 0
>- c
o.. c
u
0 ·3
<.)
8.1.1 ENV
::;
"O
0
.....
~
c. L'instruction ENV permet de créer ou de mettre à jour une ou plusieurs variables
~
::;
d'environnement, afin de les utiliser lors de la construction de l'image et dans les
rS conteneurs associés.
1
"O
0
c
8 Les variables d'environnement créées (ou modifiées) sont disponibles dans toute la
(Ç) descendance de l'image. Autrement dit, un conteneur Docker a accès aux variables
Chapitre 8. Usage avancé de Docker

d'environnement décrites par son Dockerfile et celles décrites par le Dockerfile de


l'image source.
Si une variable d'environnement existe déjà, alors l'instruction ENV remplacera
simplement la valeur existante.

Les modèles sont :

ENV <name> <value>

ENV <name>=<value> ...

<name> représente le nom de la variable d 'en vironnement.


<va l ue> représente la (nouvelle ) valeur souhaitée pour la variable d'en v ironne-
ment.
Le p remier modè le permet de re nseigner une variable et sa valeur, tandis que le
second permet de renseigner autant de variables (avec valeurs) que souhaité.
Par exemple :

ENV myName James Bond


1 ENV myName="James Bond" myJob=Agen t\ secret

Dans le p re mier exemple, nous constatons qu'il n'y a pas de signe « = »,et que la
valeur n'est pas encapsulée par des guillemets n i échappée (par exemple, un antislash
avant un espace). Dans le second exemple, les valeurs doivent être encapsulées par des
guillemets (par exemple, "James Bond") ou échappées (par exemple, Agent \ secret ),
un signe « = » devant également être présent entre le n om et la valeur.

Si plusieurs variables d'environnement doivent être créées, alors nous préférerons


l:J
0
c utiliser la deuxième forme car elle ne produira qu'une seule couche de cache d'image,
0
::J alors que la première forme en produira autant que d'instructions ENV.
\.0
.-t
0
N
Prenons un exemple pour illustrer le fonctionnement de l'instruction ENV. Soit le
@ Dockerfile suivant :
.......
..c:
O'l
·;::
>-
0..
FROMcento s :7
0 ENV myNa me="James Bond " myJob=Agent\ secret
u
1 CMD echo $myName

C onstruisons et démarrons un con teneur :

$ docker bui l d -t env


$ docker run -- rm env
1 James Bond
8.1 Dockerfile: quelques instructions supplémentaires ----------------11ssl
Il est possible de surcharger une variable d'environnement au démarrage d'un
conteneur, nous utilisons pour cela l'option - -env <name>=<va l ue>, par exemple:

1 $ docker run --rm --env my Name="Ja son Bou r ne " env

L'option - -en v est cumulative, par exemple:

1 $ docker run -- rm -- env myName="J ason Bourne " -- env myJo b="CIA " env

Pour finir, si nous souhaitons afficher la variable my)ob au lieu de myName au


démarrage du conteneur, il suffit de surcharger l'instruction CMD:

1 $docke r run --rm env /bin /sh -c 'echo "$myJob "'

Cette dernière commande est un peu particulière : en effet, nous n'utilisons pas
echo $myJob, mais /bin/s h - c ' echo " $myJo b" '.La variable $myJob de la commande
echo $my Job sera substituée au niveau de l'hôte, ce qui correspondrait à echo "" (en
considérant que la variable n'existe pas dans l'hôte) ; à l'exécution, le résultat serait
donc vide au lieu d'afficher la valeur de la variable $myJob du conteneur. La version
/ bi n/ s h - c ' ech o "$my Job "', quant à elle, permet d'effectuer la substitution au ni veau
du conteneur (car echo est encapsulé par un terminal applicatif), de telle sorte que
nous obtenons le résultat souhaité.
Un autre cas typique d'utilisation de l'instruction ENV est la modification de la
variable d'environnement PATH. En effet, si un Dockerfile contient, par exemple,
l'installation d'une application ( RUN yum i ns t a11 ... ), il devient intéressant de
pouvoir y accéder facilement (c'est~à~dire en saisissant uniquement son nom et pas
son chemin absolu). Par exemple :

l:J ENV PATH /usr/local/ng i nx/bi n:S PATH


0
c
::J
~
,.,
"O
1
0 c::;
\.0
.-t
0
.,.,
~ L'application nginx (supposée installée par une autre instruction) est ajoutée à la
N
'~ variable d'environnement PATH. Nous pouvons donc l'utiliser directement dans une
@ ·c
....... B::;
autre instruction :
..c: CO
Ol c
ï:::: 0
>- c
o.. c
u
0 ·3 ENTRY POINT [ "ng i nx "]
1
<.)
::;
"O
0
.....
c.
~
~
::; Pour terminer cette section, voyons comment il est possible de lister les variables
rS d'environnement d'un conteneur actif. Nous utilisons pour cela un docker i nspect :
1
"O
0
c
8
(Ç) 1 $docker i nspect -- format ='( (json . Confi [Link] ll ' test
Chapitre 8. Usage avancé de Docker

Pour exécuter un docker i nspect sur un conteneur, ce dernier doit être actif. Dans les
exemples ci-dessus, le conteneur n'est actif qu'un très court instant car il se termine
directement après l'instruction CMD qui est un simple echo. Pour prolonger l'activité
du conteneur, on pourrait surcharger la commande ec ho par un pi ng, ainsi le docker
run serait docker run - rm -name test env ping localhost.

Le résultat retourné est :

["PATH=/ usr /local/sbin : / usr/ l oca l /bin : /us r/sbin : /us r /bin : /sbin : /bin "," myName=James
1 Bond","myJob=Agent secret"]

La variable d'environnement PATH n'est pas décrite directement par le Dockerfile,


mais appartient à l'image source. O n confirme ainsi l'accès aux variables parentes.

8.1.2 LABEL
L'instruction LA BEL permet d'ajouter des métadonnées à une image.
Le modèle est :

LABEL <name>=<value> ...

< na me> représente le nom du label.


< va l ue> représente la (nouvelle ) valeur souha itée pour le labe l.
Par exemple :

LABEL name="Mon app l i cation" version="l .O"


1 LABEL app . name="Mon appl i cat ion" "app . ve rsi on "="l. O"

l:J
Les noms peuvent contenir lettres, chiffres, points (.), tirets ( ~) et soulignés (_). Ils
0
c peuvent être encapsulés par les guillemets ( 11 ) ou non.
::J
0
\.0
Les valeurs des labels doivent être encapsulées par des guillemets ( 11 ) . Si elles
.-t
0 contiennent un guillemet ou un retour à la ligne alors ces derniers doivent être préfixés
N
@
par un antislash , par exemple :
.......
..c:
O'l
ï::::
>-
LABEL app .descr i pt i on= "Voic i la description de \ "Mon app l ica t ion\ " \

u
0..
0 1 sur plusieurs l i gnes . "

Tout comme pour l'instruction ENV, les labels créés (ou modifiés) sont disponibles
dans toute la descendance de l'image. Autrement dit, un conteneur Docker a accès
aux labels décrits par son Dockerfile et ceux décrits par le Dockerfile de l'image source
(et ce de façon récursive).
Si le label existe déjà, alors l'instruction LABEL remplacera simplement la valeur
existante.
8. 1 Dock erfile: quelques instructions supplém entaires - - - - - - - - - - - - - - - - 1 l s1I
So it le Dockerfile suivant:

FROMcentos :7
LABE L app . name= "Mon app l i cation " \
"app . version" ="l. O" \
app .descri ption="V oic i l a desc r i pt i on de \ "Mon appl ica ti on\ " \
sur plu sieurs l ignes . "
CMD echo "fi n"

C onstruisons l'image et démarrons un conteneur:

$ docker build -t l abel .


$ docker run -rm -name t est labe l
1 fi n

Tout s'est bien déroulé, toutefois les labels étant des métadonnées, on ne peut
rien constater à travers l'exécution d'un conteneur. O n peut cependan t utiliser la
commande do cker i ns pect sur l'image afin de lister les labels existan ts :

1 $docker i nspect -- format='1 1j son . Confi g. La be l s ll ' t est

json .[Link] sign ifi e que nous affichons uniquement les labels, et ce au
format JSON. « test » représente le nom du conteneur actif.
Le résultat retourné est :

l "app .descri ption" : "Vo i ci l a description de \ "Mon applic ation\ " sur pl usieurs
l ignes ." , "ap p.n ame ":" Mon appl i cation" , "app. vers i on ": "l .O","buil d-date ":"2015-
1 12 -23 ", "l i cense ": "GP Lv2 ", "name ": "Cen t OS Base Image ", "vendor ": "Cent OS" l

Les labels build~date, license, name et vendor sont fournis par l'image source.

"'Cl
0
c:: ~
,., 8.1 .3 WORKDIR
:::i
"O
0 [Link];
\.0
.-t ~
L'instruction WORKDIR permet de changer le ch emin courant (appelé dossier de
0 V
N V travail) pour les instructions RUN, C MD, EN TRYPO IN T, COPY et A OD. Elle peut
'&
@ ·c être utilisée plusieurs fois dans un fichier Dockerfile. Son effet s'applique à toute
....... B
:::;
..c:: CO instruction qui suit .
O'l c
0
ï::::: c
>- c Son modèle est :
o..
u
0 ·3ù
:::;
"O
0
....
c. WORKDIR <chemin>
~
~
:::;
rS Par exemple :
1
"O
0
c
8
(Ç) 1 WORKDIR /tmp
Chapitre 8. Usage avancé de Docker

Dans cet exemple, le chemin courant sera changé en /tmp, cela signifian t que pour
toute instruction RUN, C MD, ENTRYPO INT, COPY et A DD impliquant un chemin
relatif dans l'image, ce dernie r sera pris à partir de /tmp.

Il est important de comprendre que l'instruction WORKDIR change le chemin courant


dans l'image. Ainsi, lorsqu'un conteneur est démarré pour une image, le chemin
courant du conteneur sera également le chemin spécifié par le dernier WORKDIR.

En spécifiant un chemin relatif, alors ce dernier sera appliqué au contexte courant :

FROM centos : 7
WORKDIR / t mp
WORKDIR test
1 CMD pwd

C et exemple produira /tmp/test comme résultat du pwd (au démarrage du conte-


neur) . De ce fait, on constate que pour écrire WO RKDIR test nous devons connaître
le contexte courant (dans notre cas /tmp). Pour cet exemple, il n'y a pas d'ambiguïté
(le chemin courant est /tmp), par contre pour un Dockerfile conséquent, ou si l'image
source a modifié le WORKDIR, le contexte n'est plus si évident. Nous appliquerons
donc la règle suivante :

Le chemin de l'instruction WORKDIR doit toujours être spécifié en absolu.

L'effet d 'un WORKDIR est appliqué en cascade aux images enfants. Voyons cela
par un exemple. Soit le Dockerfile suivant :

#Dockerfile workdirsource
FROM centos :7
WORKDIR /var
"'Cl
RUN pwd > /tmp /chemi nCouran t
0
c:: CMO cat / tmp /chemi nCourant
:::i
0
\.0
.-t Dans cet exemple, nous changeons le chemin courant en /var, puis on sauvegarde
0
N immédiatement la valeur retournée par la commande pwd dans un fichier cheminCou-
@ rant déposé dans /tmp. Si nous construisons et démarrons le conteneur, nous affichons
.......
..c:: le contenu de ce fichier, c'est-à-dire:
O'l
·;::
>-
0..
u
0
1 /va r
Si maintenant nous surchargeons le point d'entrée afin d'exécuter directement la
commande pwd dans le conteneur démarré, soit docker run - - rm workdi rsource pwd ,
nous obtenons exacte ment le même résultat :

1 /va r
8. 1 Dock erfile: quelques instructions supplém entaires ----------------11891
C e qui démontre bie n que l'effet de l'instruct ion WORKDIR s'applique à l'image
et donc aux conteneurs qui en découlent.
C ontinuons l'exemple avec un autre Dockerfile :

1 CMDFROM pwdworkd i rsource


C e Dockerfile est très simple : nous utilisons l'image que nous ven ons de créer
comme source et nous affich ons le ch emin courant au démarrage du conteneur. Là
encore, le résultat est le même :

1 /var
C e qui démontre que l'effet d 'un WORKDIR s'applique bien aux enfants d'une
image.
De plus, l'effet de W ORKDIR /unChemin est équivalent à RUN cd /unChemi n &&
fai r eQuel queChose, mais l'utilisation de l'instruction WORKDIR offre deux avantages
non négligeables :
• tout d 'abord, un gain de lisibilité ; en effet , cela permet de voir directement la
véritable fonction d'un RUN ;
• ensuite, un gain en maintenabilité ; il suffit de changer une et une seule
instruction WORKDIR si nous décidons de modifier un chemin (un nom de
dossier, par exemple) impliqué dans plusieurs instructions RUN.

Il y a un dernier point au sujet de l'instruction W O RKDIR : elle permet l'utili-


sation de variables d'en vironnement créées par l'instruction ENV au sein du même
[Link]. C ela signifie qu'une variable d 'environnement provenant d'une image
source ou native à un système ne pourra pas être utilisée. Par exemple :

FROM cento :7
"'Cl
0 ENV chemi nCourant /tmp
c:: ~
,., WORKDIR $chemi nCourant/$unFi chier
0
:::i

\.0
"O
[Link]; 1 CMD pwd
.-t ~
0 V
N V
'&
Cet exemple produira /tmp/$unFichier comme résultat du pwd (au démarrage du
@ ·c
B conteneur). La variable $unFichier n 'existant pas dans le [Link], elle ne sera pas
....... :::;
..c:: CO
substituée, et ce même si le [Link] de l'image source con t ient une instruction du
O'l c
0
ï::::: c
>- c
genre EN V unFichier monFichier.
o..
u
0 ·3ù
:::;
"O
0
....
c. 8.1 .4 USER
~
~
:::;
Cinstruction USER permet de définir l'utilisateur qui exécute les commandes issues des
rS
"O
1 instructions RUN, CMD et ENTRYPOINT. Son effet s'applique à toute instruction
0
c qui suit et à toute image enfant.
8
(Ç) Le modèle est :
Chapitre 8. Usage avancé de Docker

USER<user>

<u se r> définit le nom d'utilisateur ou l'UID à utiliser.


Par exemple :

1 USER httpd

Un fichier Dockerfile peut contenir plusieurs fois l'instruction USER, cependant il


convient de ne l'utiliser qu'une seule fois, sauf en cas de besoins particuliers, afin de
simplifier la compréhension de fonctionnement des permissions dans l'image.

La spécification d'un utilisateur avec l'instruction USER est surtout utile, et même
indispensable du point de vue de la sécurité, dans le cycle de vie d'un conteneur. Par
contre, lors de la construction de l'image elle-même, c'est-à-dire avec les instructions
RUN, nous garderons l'utilisateur root. Pour résumer:
• une image non-finale, c'est-à-dire une image qui sera principalement utilisée par
d'autres Dockerfile comme source, ne contiendra en général pas d'instruction
USER;
• pour une image finale, les instructions RUN seront effectuées en root (c'est-
à-dire avant toute instruction USER), puis on spécifiera un utilisateur afin
d'assurer que le processus actif du conteneur n'est pas exécuté en root.

Voyons le fonctionnement de l'instruction USER dans un exemple:

FROM centos :7
RUN chown root : roo t /bi n/ t op && \
chmod 774 /bin / top
RUN groupadd -r mygroup && \
useradd - r -g mygroup my user
"'Cl
0 USER my user
c:: CMD /bin/top -b
:::i
0
\.0
.-t
0
Avec le premier RUN, nous nous assurons que le binaire /bi n/top (affichage des
N
processus en cours) appartient à l'utilisateur et groupe root et que seuls ces derniers
@
....... peuvent l'exécuter. Le deuxième RUN crée un utilisateur myuser, un group mygroup
..c::
O'l
·;:: et assigne l'utilisateur créé au groupe créé. L'option - b du binaire top définit que
>-
0.. ce dernier est exécuté en mode batch ; cela signifie que son exécution est toujours
0
u active avec un rafraîchissement régulier des processus en cours, jusqu'à ce qu'il soit
manuellement arrêté (dans notre cas, lors de l'arrêt du conteneur).
En construisant l'image et en démarrant le conteneur, nous obtenons :

$ docker bu i l d -t us er .
Send i ng build context to Docker daemon 2. 048 kB
1
8. 1 Dock erfile: quelques instructions supplém entaires -----------------El
Successful ly bu il t af7b2fa53d95
$ docker run --rm -- name user-con t eneur user
1 /bi n/sh : /b i n/to p: Permission denied

Étant donné que l'utilisateur courant est myuser (instruction U SER), n ous consta-
tons logiquement que le bina ire ! bi n/top n e peut être exécuté car seul root peut le
faire. Modifion s ma inten ant le Dockerfile :

FROM centos : 7
RUN chown root : root /bi n/top && \
chmod 774 /bin/top
RUN groupadd -r mygroup && \
useradd -r -g mygroup my user
RU N chown myuser :mygroup /bi n/to p
USER myuser
CMD /bi n/ t op -b

En reconstruisant l'image et en redémarrant le conten eur, le bina ire / bi n/ t op


s'exécute correctement car l'instruction RUN , qui a été ajoutée, définit l'utilisateur
du bina ire / bi n/top par myuser et son groupe par mygroup.
Il est également possible de v isualiser l'utilisateur courant du conten eur grâce à un
docker i nspect :

$docker i nspect -- format='( (json . Config . User} }' user -conteneur


1 "my user "

Repren on s [Link] ant l'exemple initial, et essayon s une autre approch e : n ous
allons autoriser les utilisateurs du groupe mygroup (soit l'utilisateur myuser) à exécuter
le bina ire /b i n/top comme super utilisateur (s ud o). N ous modifio ns le Dockerfile
ainsi:

FROM centos :7
RU N yum update -y && yum i nstall -y sudo
"'Cl
0
RUN chown root : roo t /bin/ t op && \
c::
:::i
~
,., chmod 774 /bin/top
0 "O
[Link]; RUN groupadd -r mygroup && \
\.0
.-t ~
useradd -r -g mygroup myuser
0
N
V
V
RU N echo '%myg roup ALL=NOPASSWD: / bin/top' >> /et c/sudoers
'& USER myuser
@ ·c
....... B
:::;
CMD sudo /bin/ t op -b
..c:: CO
O'l c
0
ï::::: c
>- c Le prem ier RU N va insta lle r le bina ire sudo (permettant la gestion de superu-
o..
u
0 ·3ù tilisateurs). Le dernier RUN va définir le groupe mygroup comme superutilisateur
:::;
"O
0
....
du bina ire / bi n/top, c'est-à-dire que tout membre pourra l'exécuter sans condition .
c.
~ Pour finir, n ous ajo utons sudo à l'instruction CMD pour dire que la commande sera
~
:::; exécutée v ia le binaire sud o.
rS
"O
1
Nous construisons l'image :
0
c
8
(Ç) 1 $ docker bui ld -t user .
Chapitre 8. Usage avancé de Docker

Puis nous démarrons le conteneur :

$ docker r un -- rm -- name user -conteneur user


1 sudo: sorry, you must ha ve a t ty to run sudo

Alors que la configuration semble correcte, cela ne fonctionne pas : le système nous
dit qu'on doit avoir un tty pour faire fonctionner su do (car C entOS 7 est configuré
ainsi par défaut pour su do). tty est une commande permettant d'afficher le nom du
terminal associé à l'entrée standard : dans notre cas, il n'y en a pas. Pour résoudre notre
problème, nous avons deux solutions : soit modifier la configuration de CentOS 7 afin
qu'elle n'ait pas beso in de tty pour sudo, soit configurer un terminal pour l'entrée
standard. La deuxième solution é tant complexe, nous utiliserons la première :

FROM centos :7
RUN yum update -y && yum i nsta l l -y \
sudo
RUN sed -i -e 's/requi retty/ ! requ i retty/g' /etc/sudoers
RUN chown root :root /bin/top && \
chmod 774 / bi n/ top
RU N groupa dd -r mygroup && \
useradd -r -g mygroup myuser
RUN echo '%mygroup AL L=NOPASSW D: /bi n/ t op ' » /etc/ sudoe rs
USER myuse r
CMD sudo / bi n/to p -b

N ous avons modifié la configuration de su do (dans le fichier /etc/sudoers) grâce à


sed en remplaçant requi re tty par ! requi r etty, signifiant simplement qu'il n'y a pas
besoin de terminal associé à l'entrée standard.
En construisant puis en démarrant le conteneur, nous constatons que cette fois,ci
cela fonctionne. Toutefois, cette dernière manipulation que nous avons dû effectuer
n'est pas intuitive ; on conclura donc cette section par cette bonne pratique :

Un Dockerfile ne doit pas contenir d'exécution de commandes avec un superutilisateur,


"'Cl
0
c:: autrement dit il ne contiendra pas de sudo.
:::i
0
\.0
.-t
0
N 8.1.5 ARG
@
.......
..c:: L'instruction ARG permet de définir des variables (appelées arguments) qui sont
O'l
·;:: passées comme paramètres lors de la construction de l'image. Pour cela, l'option
>-
0..
0
- -bu i 1d-a rg de docker bu i 1d devra être utilisée. Les arguments définis par ARG ne
u peuvent être utilisés que par des instructions de construction (RUN, AOD, COPY,
USER) de l'image elle,même, c'est,à,dire qu'elles ne sont pas disponibles dans les
images enfants ainsi que dans le conteneur.
Le modèle est :

ARG <name>C=<defaultValue>J
8.1 Dockerfile: quelques instructions supplémentaires ----------------11931
<name > représente le nom de l'argument.
<de f aul tVa l ue> représente la valeur par défaut. Ce paramètre est optionnel, s'il
n'est pas spécifié et que lors de la construction de l'image l'argument correspondant
n'est pas donné en paramètre, alors sa valeur sera simplement vide.
Par exemple :

ARG var l
ARG var2="ma valeur "
1 ARG var3=4

Si la valeur contient des espaces, alors elle doit être encapsulée par des guillemets.
L'utilisation d'un argument défini par l'instruction ARG dans un Dockerfile se fait
de manière similaire à l'utilisation d'une variable d'environnement, c'est-à-dire :

1 $(<name>[ : -<defau ltValue> J l


Les accolades« { » et«}» sont facultatives si defaultValue n'est pas donné.

Par exemple :

RUN echo $var l


1 RUN echo $(var2 : - "une autre va leu r "])

Dans le deuxième exemple, nous assignons une autre valeur à var2 si cette dernière
est v ide. S i sa création provenait de l'instruc tion ARG va r2= "ma va l eur ", alors va r2
ne serait jamais vide, et donc une autre valeur ne serait jamais assignée.

Il n'est possible d'utiliser un argument que s'il a été défini (par l'instruction ARG> avant.
Ainsi, nous veillerons à définir les arguments en début de Dockerfile.

"'Cl
0 C omme cela est mentionné plus haut, l'assignation des arguments définie par ARG
c:: ~
,.,
0
:::i
"O se fait lors de la construction de l'image, grâce à l'option - - bu i l d a rg qui fonctionne
[Link];
\.0 ainsi :
.-t ~
0 V
N V
'&
@
.......
..c::
·c
B
:::;
CO
1 -- build -arg <name>=<va l ue>
O'l c
0
ï::::: c
>- c Il est fortement déconseillé d'utiliser l'option - -bu i 1d-a rg pour passer des informations
o..
u
0 ·3ù sensibles, comme des clés secrètes ou des mots de passe, car les valeurs seront très
:::;
"O
0
.... probablement sauvées dans le cache des commandes exécutées dans le terminal.
c.
~
~
:::; Si nous souhaitons spécifier plusieurs arguments, alors n ous utiliserons plusieurs
rS
1 fois l'option , par exemple :
"O
0
c
8
(Ç) 1 $ docker build -- bui ld-arg var l=valeurl --bui ld -a rg var2="encore une valeur " .
Chapitre 8. Usage avancé de Docker

Les arguments donnés dans loption - - bui l d a rg doivent obligatoirement être définis
dans le Dockerfile. Si tel n'était pas le cas, une erreur serait retournée lors de la
construction de l'image.

Prenons un exemple, soit le Dockerfile suivant :

FROM centos :7
ARG varl
ARG varZ="ma valeu r"
RUN echo $varl > / t mp/va r
RUN echo $var2 >> /tmp/var
CMD echo $varl

Ce Dockerfile va simplement mettre le contenu des arguments var 1 et var2 dans


un fichier var dans tmp. Puis n ous afficherons le contenu de var 1 lors du démarrage
du conteneur.
N ous construison s l'image en spécifiant valeurl comme valeur pour varl et nous
laissons la valeur par défaut de var2 :

1 $ doc ker buil d - -bui l d-arg var l=valeurl -t arg .

N ous démarrons le conteneur :

1 $ doc ker r un --rm arg

N ous constatons que la valeur de var 1 est vide dans le con teneur, ce qui est normal
car la portée des variables définies par ARG ne s'étend pas au conteneur. Modifions
l'instruction C MD par:

"'Cl
0
1 CMD cat / t mp/var
c::
:::i
0
\.0 C onstruisons et démarrons le conteneur une nouvelle fois :
.-t
0
N
@
.......
$ doc ker buil d --build-a rg var l=valeurl -t arg .
..c::
O'l
·;:: $ doc ker r un - -rm arg
>-
0.. va l eurl
0
u ma valeur

Cette fois~ci nous voyons bien les valeurs attendues pour varl et var2 car leur ajout
dans /tmp/var a été fait lors de la construct ion.
Essayons maintenant de surch arger la valeur de var 2 lors de la construction de
l'image :
8. 1 Dock erfile: quelques instructions supplém entaires -----------------11951
$docker bui l d - -bui ld -arg var l=valeurl -- buil d-arg var2="une autre va l eur " -t
arg .

$ docker run -- rm arg


valeurl
une aut re valeur

var2 a bien pris la nouvelle valeur.


Comme cela est mentionné plus haut et démontré dans les exemples, l'utilisation
des arguments définis par ARG se fait de façon similaire à l'utilisation des variables
d'environnement ; mais alors qu'en est-il d'une utilisation conjointe d'un argument et
d'une variable d'environnement avec un même nom ?
Soit le [Link] suivant :

FROM centos :7
ARG var=argument
ENV var vari abl e
RUN echo $var > / t mp/va r
CMD ca t / t mp/var

N ous construisons l'image et démarrons un conteneur :

$ docker build -t arg

$ docker run --rm arg


1 variable
N ous constatons que la valeur de $var est « variable >>, ce qui peut sembler logique
car l'assignement de la variable d'environnement est placé après celui de l'argument.
Recommençons le même exemple en inversan t les assignations :

FROM centos :7
"'Cl
0 ENV var variab l e
c::
:::i
~
,., ARG var=argument
0 "O
[Link]; RUN echo Sv ar > / t mp/var
\.0
.-t ~
CMD ca t / t mp/var
0 V
N V
'&
@ ·c De no uveau, construisons l'image et démarrons le conteneur :
....... B
:::;
..c:: CO
O'l c
0
ï::::: c
>- c S docker bui l d -t arg
o..
u
0 ·3ù
:::; S docker run -- rm arg
"O

~
0
....
c. 1 variabl e
~
:::;
Le résultat est le même : $var vaut toujours « variable » . C e comportement est
rS
1 dû au fait que ENV prime sur ARG, quel que soit l'ordre des instruct ions; plus
"O
0
c précisément, le résultat sera le suivant :
8
(Ç) • si ENV est placé avant A RG : A RG sera ignoré ;
Chapitre 8. Usage avancé de Docker

• si ENV est placé après ARG : ARG sera valable jusqu'à ENV, puis, dès
l'instruction ENV, ARG sera remplacé.

Nous savons que l'exploitation d'un argument et d'une variable d'environnement


dans un Dockerfile se fait de façon équivalente, et que ENV est prioritaire sur ARG.
Voyons maintenant dans quel cas on utilise l'une ou l'autre instruction, voire les deux.
Le critère de choix de l'instruction à utiliser (ENV ou ARG) est défini par la portée
souhaitée:
• si l'on souhaite agir sur l'image et les conteneurs associés, alors il s'agit d'une
variable d'environnement (ENV) ;
• et si l'on souhaite agir uniquement sur les instructions de construction de
l'image, alors il s'agit d'un argument (ARG).

Il faut voir une variable d'environnement comme une configuration nécessaire


durant tout le cycle vie d'une application, c'est~à~dire de sa construction à son
exécution, typiquement, un chemin ou un port. Par contre, un argument est un simple
paramètre qui, selon sa valeur, fera varier la façon de construire une application, et
qui pourra potentiellement avoir un impact sur son fonctionnel, par exemple un nom
d'utilisateur.

Il n'est pas toujours évident d'identifier quels services utilisent telle ou telle variable
d'environnement; ainsi, l'utilisation de l'instruction ENV doit se faire avec précaution :
il convient de toujours vérifier que le nom d'une variable d'environnement que nous
souhaitons ajouter n'est pas déjà utilisé par un service dont l'application dépend.

Nous savons maintenant quelle instruction utiliser selon la portée souhaitée. Nous
avons également vu qu'il est possible de surcharger une variable d'environnement et
un argument. Toutefois, la surcharge se fait différemment :
• pour l'instruction ARG, la surcharge se fait logiquement lors de la construction
de l'image (docke r bui l d); en effet, cela n'aurait pas de sens de la faire lors du
"'Cl
démarrage d'un conteneur dans la mesure où un argument n'y est pas disponible ;
0
c::
:::i
• pour l'instruction ENV, la surcharge se fait lors du démarrage du conteneur
0 (doc ker run ), ce qui, dans certains cas, peut poser un problème de consistance :
\.0
.-t
0
imaginons une variable d'environnement utile lors de la construction d'une
N image, puis lors de l'exécution des conteneurs associés ; si l'on surcharge la
@
....... variable seulement lors du démarrage, alors nous aurons une valeur différente à
..c::
O'l la construction et à l'exécution.
ï:::::
>-
0..
0 La solution au problème de consistance de l'instruction ENV est représentée par
u
le cumul des instructio ns ARG et ENV. Voyons un exemple :

FROM cent os :7
ARG version
ENV vers i on ${version : -l .O}
RUN echo $version > / t mp/version
CMD ca t /tmp/vers i on
8.1 Dockerfile: quelques instructions supplémentaires -----------------11971
La valeur de la variable d'en vironnement est « ${version :- 1.0} », ce qui représente
la valeur de l'argument « version » s'il n'est pas vide, et « 1.0 » dans le cas contraire
(rappelons-nous qu'un argument placé avant une variable d'environnement est valable
jusqu'à cette dernière ).
Si l'argument « version » n'est pas surchargé lors de la construction de l'image, alors
ce dernier est vide et la variable d'environnement correspondante vaudra « 1.0 ».Et si
l'argument est surchargé, alors ce dernier n'est pas vide et la variable d'en vironnement
vaudra sa valeur.
Essayons le cas où l'argument « version » n'est pas surchargé :

$ docker build -t arg .

$ run -- rm arg
1 1. 0
La variable d'environnement vaut bien « 1.0 ». Surchargeons maintenant l'argu-
ment avec « 1.2 » :

$ docker build -- buil d-arg vers i on=l. 2 -t arg .

$ docker run -- rm arg


1 1. 2
Cela correspond bien au résultat souhaité.
À noter que l'utilisation de cette tech n ique n 'empêch e pas explicitement la
surcharge d'une variable d'en vironnement lors du démarrage d'un conteneur (le
problème d'inconsistance pourrait ainsi avoir lieu) , cependant il convient de toujours
documenter une image, notamment les variables d'env ironnement qui peuvent être
surchargées au démarrage d'un conteneur associé.

Une variable d'environnement, qui ne peut être surchargée lors de la construction


"'Cl de l'image, ne doit en aucun cas être utilisée par des instructions de construction de
0
c:: ~
,., l'image.
:::i
"O
0 [Link];
\.0
.-t ~
Pour terminer cette section, mentionnons que Docke r dispose d 'un ensemble
0 V
N V prédéfini d'arguments qui peuvent être utilisés sans être explicitement définis par des
'&
@ ·c instruc tions ARG dans un Dockerfile. En voici la liste :
....... B
:::;
..c:: CO
O'l c
0 • HTTP_PROXY
ï::::: c
>- c
o.. • http_proxy
u
0 ·3ù
:::;
"O
• HTTPS_PRO XY
0
....
~
c. • https_proxy
~ • FTP_PRO XY
:::;
rS • ftp_proxy
1
"O
0
c • N O _PROXY
8 • n o_proxy
(Ç)
J 1981 - - - - - - - - - - - - - - - - - - - - - Chapitre 8. Usage avancé de Docker

8.1.6 ONBUILD
L'instruction ONBUILD permet de définir des instructions qui seront exécutées
uniquement lors de la construction d'images enfants, ce qui signifie qu'elles ne seront
pas exécutées lors de la construction de l'image les contenant.

L'exécution des instructions ONBUILD n'est effectuée que dans les enfants directs.
Les éventuels enfants d'images enfants n'incluront pas ces instructions.

1mage source 1mage enfant

FROM centos:7 FROM source


RUN .. .
RUN .. .
ONBUILD .. .
ONBUILD .. . }

Figure 8.1 - Exécution d'instructions ONBUILD dans une image enfant

La figure 8.1 illustre l'emplacement où sont exécutées dans une image enfant
les commandes définies par des instructions ONBUILD dans une image source :
directement après l'instruction FRO M.
Le modèle de l'instruction O NBU ILD est :

ONBUILD <instruction>

-0
0
c:: <i ns tr uct i on> représente une instruction de construction (RUN, A OD, COPY,
:::i
0 USER et ARG).
\.0
.-t
0
Par exemple :
N
@
.......
..c:: ONBUI LD RUN mkd ir /tmp/test
Ol ONBUI LD COPY test* dossier Relatif/
ï:::::
>-
0..
0
1 ONBUI LD USER httpd
u
L'utilité de l'instruction ONBUILD n'est pas forcément évidente à comprendre,
et c'est pour cela que nous emploierons un exemple pratique pour illustrer un cas
d'utilisation réelle : il s'agira de construire une image permettant de compiler et
d'exécuter une application Python quelconque.

À titre d'information, Python est un langage généralement utilisé pour de la


programmation fonctionnelle, c'est-à-dire qui considère le calcul en tant qu'évaluation
8. 1 Dock erfile: quelques instructions supplém entaires ----------------11991
de fonctions mathématiques. Il peut être interprété ou compilé, et dans notre exemple
il sera compilé.

Pour commencer l'exemple, nous avons besoin d'une image source (appelée python-
app) capable de compiler et d'exécuter une application Python (dans notre cas, un
simple fichier .py) sans connaître cette dernière. N ous aurons le Dockerfile suivant:

#pyth on -app
FROM centos : 7
ONBU ILD ARG f ich ier="a pp . py"
ONBUILD COPY $f i chi er /a pp / ap p. py
ONBUILD RU N pyt hon -m py_compil e /a pp /a pp. py
ENTRYPOINT [ "python", "/ app / app . pyc "]

Les instructions ONBUILD vont copier un fichier Python (dont le nom par défaut
est [Link]) dans l'image et le compiler: le fichier Python dans l'image se nommera
dans tous les cas [Link].

Python est déjà présent dans l'image source CentOS 7, ainsi nous n'avons pas besoin
de le faire.

Comme cela est expliqué plus haut, les instructions ONBUILD ne sont jouées
que dans les images enfants; ainsi, l'argument fichier (défini par ARG) ne pourra,
si nécessaire, être surchargé que lors de la construction d'images enfants, ce qui
représente bien notre souhait dans la mesure où l'image source ne connaît pas
l'application Python.
L'instruction ONBUILD COPY $fichier /app/[Link] fera échouer la construction
de l'image enfant si le fichier décrit par l'argument « fichier » n'existe pas. Il n 'existe
pas de solution directe à ce problème, toutefois il convient de raguer avec le mot-clé
« onbuild »toute image incluant une ou plusieurs instructions ONBUILD. L'utilisateur
sera ainsi averti et devra prendre la peine de lire la documentation ou au moins le
"'Cl
0 Dockerfile de l'image source.
c::
:::i
~
,.,
0 "O
[Link]; Construisons maintenant l'image source en n'oubliant pas le tag « onbuild » dans
\.0
.-t ~ la version:
0 V
N V
'&
@ ·c
.......
..c::
B
:::;
CO
1 $ docke r build -t python-ap p: l .0-onbui l d .
O'l c
0
ï::::: c
>- c
o.. Nous avons maintenant notre image source python-app (en version 1.0-onbuild)
u
0 ·3ù
:::;
"O
permettant de compiler et d'exécuter un fichier Python dont le nom par défaut est
0
.... [Link].
c.
~
~
:::; Continuons l'exemple en exploitant l'image source python-app. Pour cela nous
rS avons besoin d'une application Python (qui sera appelée x2) : il s'agira d'un simple
1
"O
0
c programme dont le but est de multiplier une valeur (donnée en argument) par deux
8 et d'afficher le résultat. Voici son code :
(Ç)
J2ool Chapitre 8. Usage avancé de Docker

fi x2 . py
impo r t sys
x=int( sys .a rgv[ l ])
resu lt at=x*2
print (repr (x) +" * 2 = " +repr(resul ta t ) )

Commentons sommairement ce programme:


• import sys permet d'importer une librairie permettant d'exploiter les arguments ;
• x=int([Link][l]) signifie qu'on assigne à x le premier argument donné lors de
l'exécution de l'application;
• les autres lignes de codes sont relativement simples à comprendre.

Si nous exécutons l'application (sans la compiler pour simplifier l'explication) ,


nous obtenons :

$ python x2 . py 5
15*2 = 10

Créons maintenant le Dockerfile permettant d'exécuter notre application x2 grâce


à notre image source générique python-app :

FROM pyt hon-a pp: l .0-onbuil d


1 CMD [ "O"]
Nous avons défini une instruction C MD ["0"] car l'application x2 a besoin d'un
argument lors de son exécution (nous avons choisi arbitrairement 0). Pour rappel, il
est possible de combiner des instructions ENTRYPO INT et CMD, dans notre cas :

ENTRYPOINT ["pyt hon". "/a pp / app . pyc"]


1 CMD [" O" J

"'Cl produira python / app / app. pyc 0 où 0 pourra être surchargé lors du démarrage du
0
c:: conteneur.
:::i
0
\.0
.-t
L'image source introduit un argument « fichier » dans les images enfants dont la
0
N
valeur par défaut vaut [Link]. Dans notre cas, l'application est définie par le fichier
@ [Link] (placé au même endroit que le Dockerfile), et on devra surcharger l'argument
.......
..c:: lors de la construction de l'image :
O'l
ï:::::
>-
u
0..
0 1 $ docker bu i l d -- build -arg fichier=x2. py -t python-x2

Essayons maintenant de démarrer un conteneur :

$ docker r un --rm pyth on-x2


0 * 2 = 0
$ docker r un -- rm python-x2 17
1 17 * 2 = 34
8. 1 Dock erfile: quelques instructions supplém entaires - - - - - - - - - - - - - - - - - 1201 I
Tout fonctionne correctement : dans le premier cas, python,x2 utilise la valeur
d'exécution par défaut, soit 0, et dans le deuxième cas 17 qui représen te bien la
surcharge de l'instruction CMD.
Revenons un peu en arrière, au n iveau du résultat retourné lors de la construction
de l'image python,x2. La ligne suivante en faisait partie :

1 # Executi ng 3 bu i l d trigger s . ..
Cette ligne particulière est retournée uniquement lorsque l'image source con t ient
des instructions O N BU ILD : elle sert à attirer l'attention de l'utilisateur sur le fait que
des instructions qui ne son t pas dans le Dockerfile de l'image seront exécutées.
Pour terminer cette section, regardons ce qui se passe techniquement au niveau de
la construction d 'une image contenant une instruction ONBUILD :
1. À la lecture d'une instruction ONBUILD, le const ructeur Docker va créer
une mé tadonnée qu'il placera dans le manifeste de l'image au niveau de la clé
« OnBuild » . C ette mé tadonnée décrira l'instruction qui devra être exécutée
dans les images enfants. Il est possible de voir son contenu grâce à un docker
inspect sur l'image concernée. Par exemple, pour python ,app, nous obtenons :

$docker inspect - -format='{ {json .ContainerCon f ig .OnBuil d}} ' pytho n-app
[ "ARG fich i er=\ "app . py\ "", "COPY $fic hie r /a pp/app . py ", "RUN python -m
1 py_compile /ap p/app . py "J
2. Nous constatons bien que les trois instructions ONBUILD sont présentes dans
« O nBuild » .

3. A près la création de la métadonnée, le constructeur Docker a terminé son


travail pour l'instruction concernée.
4. Plus tard, lorsque l'image contenant l'instruction ONBU ILD est utilisée comme
source, le dé mon Docker lira le manifeste et constatera que des instructions
"'Cl provenant de l'image source doivent être exécutées : il exécutera ces instructions
0
c:: ~
,., au niveau de l'instruction FROM, et ceci dans le même ordre où elles ont été
:::i
"O
0 [Link]; ajoutées au manifeste, c'est,à,dire l'ordre dans le Dockerfile de l'image source.
\.0
.-t ~
V
S i l'une d'elle éch oue, alors c'est l'instruction FRO M qui échouera.
0
N V
'& 5. S i l'exécution des instructio ns provenant du manifeste est un succès, alors
@ ·c
B
.......
..c::
:::;
CO
le constructeur supprime les métadonnées concernées dans le manifeste et
O'l c
0 continue la construction de l'image à partir des instruct ions suivant le FRO M.
ï::::: c
>- c
o..
u
0 ·3ù
:::;
"O
0
....
8.1 .7 STOPSIGNAL
c.
~
~
:::;
L'instruct ion STO PSIGNAL permet de définir le signal à exécuter lors de l'arrêt d'un
rS conteneur. Un signal représen te une information impactant un processus, par exemple
1
"O
0 son arrêt immédiat.
c
8 Le modèle de l'instruction est :
(Ç)
J202I--------------------- Chapitre 8. Usage avancé de Docker

STOPSIGNAL <signal>

<signa l > est le signal à utiliser. Il est représenté soit par un nombre définissant sa
position dans la table syscall, soit par son n om au format SIGNAME.

Tableau 8 .1 - Extrait de la table syscall

Position Nom au format SIGNAME Description


1 SIGHUP Termine la session du processus.
2 SIGINT Interrompt le processus.
3 SIGQUIT Quitte le processus.
6 SIGABRT Annule le processus.
9 SIGKILL Termine le processus immédiatement.
10 SIGUSRl Signal utilisateur 1.
12 SIGUSR2 Signal utilisateur 2.
15 SIGTERM Termine le processus.

Tout signal, sauf SIGKILL et SIGTERM, peut être intercepté par un processus, ce qui
signifie que ce dernier le gérera comme il le souhaite.

Par exemple :

1 STOPSIGNAL 9
STOPSIGNAL SIGKI LL

Pour rappel, lors de l'arrêt d'un conteneur (docker stop), seul le processus de PID 1
est arrêté proprement par Docker ; c'est ce processus qui interprètera le sign al décrit
"'Cl par l'instructio n STOPSIGNAL (par défaut il s'agira de SIGTERM) . L'utilité de
0
c:: STOPSIGNAL est donc de changer ce signal et par conséquent le travail à accomplir
:::i
0 par le processus lors de l'arrêt du conteneur. À noter que le signal SIGKILL est
\.0
.-t également reçu par le processus après une certaine période (de 10 secondes par défaut)
0
N si ce dernier ne s'est pas terminé correctement.
@
.......
..c::
O'l
ï:::::
>-
..
0..
0
8.2 SECURISONS DOCKER
u
La sécurisation d'une architecture à base de conteneurs est un vaste sujet. Il existe
cependant deux cas d'usage relativement courants qu'il est ut ile de connaître :
• la sécurisation de la Docker Remote API avec SSL/TLS ;
• Docker Content Trust, le logiciel de la suite Docker dédié à la signature des
images.
8.2 Sécurisons Docker --------------------------12031
8.2.1 SSL/TLS pour la Remote API

L'API distante de Docker (en anglais Docker Remote API) a été présentée dans
le chapitre 3 de cet ouvrage. N ous allons rappeler ici brièvement comment elle
fonctionne et comment la configurer.
Le client Docker permet l'exécution des commandes Docker depuis un terminal.
Lorsqu'une commande est exécutée depuis le client, par exemple docker ps, une
requête HTTP REST correspondante est créée, en voyée et exécutée par le démon
Docker à travers un socke t. Le démon Docker expose donc toutes les commandes
Docker par le biais d'un socket. L'API Docker permet d'envoyer et d'exécuter des
requêtes au démon (via le socket) grâce à une interface REST /J SON.
Dans la configuration initiale du démon Docker, le socket par défaut est un socket
Unix localisé par /var/run/docke [Link]. A insi, en exposant ce socket U nix comme
un socket HTTP, on peut accéder à l'API. Regardons main tenant comment sécuriser
cette A PI. N ous allons pour cela devoir:
• créer une A utorité de certification (abrégé en C A en anglais) ; bien évidem-
ment, sur une véritable installation, nous utiliserions un certificat délivré par
une agence de certification ;
• créer et configurer un Certificate Signing Request (abrégé en C SR et traduit
par demande de signature de certificat) et une clé pour l' A PI de n otre démon
Docker;
• faire de même pour le client pour pouvoir ensuite interagir avec le démon
Docke r.

N ous utiliserons pour cela l'utilitaire opens s1 qui est disponible sur la plupart des
distributions Linux.

Création de notre Autorité de certification


Créons avant tout un répertoire où nous stockerons nos clés et certificats.
"'Cl
0
c::
:::i
~
,.,
0 "O
[Link]; $ mkd ir -/docker -ce r t
\.0
.-t
0
~
V
1 $ cd docker -cert
N V
'&
@ ·c C ommençons par créer la clé privée (private key) ca-key . pem de notre C A. Ce
....... B
..c::
:::;
CO sera une clé de 4096 bits et nous utiliserons l'algorithme de chiffrement symétrique
O'l c
ï::::: 0
c A ES256 :
>- c
o..
u
0 ·3ù
:::;
"O
0
$ echo 01 t ee ca . srl
1

....
c. $ openss l genrsa -aes 256 -out ca - key . pem 4096
~
~
Generating RSA private key, 4096 bit long modulus ... . ...... . . .. . ...... . . ++
:::;
rS . . ...... . .. ..... .. .. .. . .... . . . ...... . .. ..... . . . ... ...... . . . . . . .... . ... . .. ++
1
"O
0 e is 65537 (0x10001)
c
8 Ent er pass phrase for ca -key . pem:
(Ç) Verifying - Enter pass phrase for ca - key .pem :
Chapitre 8. Usage avancé de Docker

Notez bien la pass phrase (phrase secrète) que vous utilisez. C'est le mot de passe
de votre clé et nous en aurons prochainement besoin.

Vous avez sûrement noté une commande étrange: echo 01 tee ca . srl. Elle
1

contient un numéro de série qui est incrémenté chaque fois que nous utilisons
notre clé pour signer un certificat.

Nous pouvons maintenant générer notre certificat ca . pem :

$ openssl req -new -x509 -days 365 - key ca-key . pem -sha256 -out ca . pem
Enter pass phrase for ca -key .pem :
You are about to be asked to enter i nfo rmation that wi l l be incorporated
into your certi f i cat e request .
What you are about to enter i s what i s called a Distingu ished Name or a DN.
There are qui t e a few f i elds but you can leave some blank
For some fie l ds t he re wi l l be a de fau lt va lue,
If you enter '.' . t he fie l d wi ll be left bla nk.

Country Name (2 l et ter code) [X XJ: FR


State or Prov i nce Name (full name) [ ] : France
Loca li t y Name (eg , city) [Defa ult City ]:
Organiza ti on Name (eg , compa ny) [Defaul t Company Ltd] :
Organi zationa l Un i t Name (eg, sect i on) [ ]:
Common Name (eg , your name or yo ur server 's hostname) [ J:dunod-docker
Email Address [ ] :

Nous avons maintenant notre certificat CA valable une année. Utilison s le


maintenant pour créer le certificat de notre démon Docker et le sécuriser.

Sécurisation de /'API du démon Docker


Commençons par une clé server - key. pem pour notre serveur (c'est-à-dire notre
démon):
"'Cl
0
c::
::i $ openssl genrsa -out server - [Link] 4096
0 . . ++
\.0
.-t .++
0
N 1 e is 65537 (0x l 0001)
@
.......
..c:: Créons le CSR serve r . c sr pour notre serveur. Cette demande de signature de
O'l
ï:::::
>- certificat est propre à notre machine, si bien que vous ne devez pas oublier de remplacer
0..
0 $HOST (sous Linux, vous pouvez simplement l'obtenir avec la commande hostname )
u par le no m de la machine sur laquelle le démon Docker tourne.

1 openss l req -s ubj "/C N=SHOST" -sha256 -new -key server-key . pem -out [Link]

Il ne nous reste plus qu'à signer notre CSR pour générer le certificat de notre
serveur:
8.2 Sécurisons Docker l2osl

$ openssl x509 -req -days 365 -sha256 -i n server .cs r -CA ca . pem -CA key
ca -key .pem -out server -cert. pem
Si gna t ure ok
subj ect=/C N=l ocalhost . l oca l domai n
Getti ng CA Pr i va t e Key
Ent er pass phrase for ca -key . pem:

N ous avons maintenant tout ce qu'il nous faut pour sécuriser notre démon.
La procédure est identique à ce que nous avons déjà vu au chapitre 3 : il nous
faut éditer le fichier de configuration de Docker (disponible sous CentOS dan s le
fichier /usr/lib/systemd/system/[Link]) et adapter la ligne avec l'instruction
ExecStart:

$ sudo - i
$ vi / usr/li b/sys t emd/syst em/doc ker .se r vi ce

ExecSta r t =/ usr/bi n/docker daemon -H tcp : //0 .0.0.0:2376 ' -- t l sver i fy '
' - -tl scace rt=/home/vag rant /docke r -cert /ca . pem'
' -- tl scert =/ home/vagran t/docker -cer t/server -cert . pem'
' -- t lskey=/home/vag rant /docker -cert /server - key . pem' ...
$ exit

Redémarrons notre démon Docker :

$ sudo systemctl daemon - rel oad


1 $ sudo systemctl st art doc ker

Il ne nous reste plus qu'à créer un certificat et une clé pour n otre client afin de
nous connecter sur notre démon Docker maintenant sécurisé.

Configuration SSL du client Docker


"'Cl Le processus est presque identique à ce que nous venons de réaliser pour notre démon :
0
c::
:::i
~
,., création de la clé et d'un CSR clie nt, puis signature de notre C SR avec notre CA
"O
0 [Link]; pour générer le certificat :
\.0
.-t ~
0 V
N V
'&
@ ·c $ openssl genrsa -out key . pem 4096
....... B
:::;
..c::
1
CO
O'l c
0
$ openss l req -subj ' / CN=cl i ent' -new - key key. pem -out clie [Link]
ï::::: c
>- c
o..
u
0 ·3ù
:::; Il existe une petite différence avec la partie serveur: nous devons activer l'authen,
"O
0
....
c.
t ification client pour notre clé en rajoutant l'attribut SSL extendedKeyU sage :
~
~
:::;
rS
1
1 $ echo extendedKeyUsage = cl i entAuth > extfi l e .cnf
"O
0
c
8 et nous générons finalement notre certificat client :
(Ç)
Chapitre 8. Usage avancé de Docker

$ openssl x509 - req -days 365 -sha256 -i n client. csr -CA ca . pem -CAkey
ca- key . pem -out cer t . pem -extf i l e extfi l e . cnf
Sign at ure ok
s ubject=/C N=c l ient
Getti ng CA Pri vate Key
Ent er pass phras e for ca-key . pem :

Il ne nous reste plus qu'à passer en paramètre à notre client Docker les différents
clés/certificats que nous venons de créer :

$ doc ker -H=tcp : // $HOST:2376 -- t l sverify


-- t l scacert=/ home/vag ran t/docker- cert/ ca . pem
-- t l scer t =/home/v agr ant/doc ker -cert/ cer t . pem
1 -- t l skey=/home/va grant /docker -cert /key . pem i nfo

N'oubliez pas de remplacer $HOST par le nom de l'hôte sur lequel tourne le démon
Docker!

Et si nous essayons sans les paramètres SSL :

$ doc ker -H=tcp : // $HOST: 2376 i nfo


Get ht t p: // l oc al hos t : 2376/v l . 23/info: mal f ormed HTTP respo nse
"\ x15\ x03\ x01\x00\x02\x0 2". *A re you t ryi ng t o connect t o a TLS-enabled
1 da emon wi thout TLS?

Docker nous signale effectivement que nous ne pouvons pas accéder au démon.
Nous disposons maintenant d'un démon totalement sécurisé. Heureusement, comme
nous l'avons vu au chapitre 4, des outils comme Docker Machine permettent d'automa-
tiser cette configuration standard qui est fastidieuse si on doit la réaliser manuellement.

8.2.2 Docker Content Trust


"'Cl
0
c::
::i
En début de chapitre 7, nous avons listé les variables d'environnement utilisées
0 par le Docker Engine. DOCKER_CONTENT_TRUST et DOCKER_CONTENT_
\.0
.-t
0
TRUST_SERVER sont utilisées dans le cadre de Docker Content Trust .
N
@ Docker Content Trust est un mécanisme qui permet de signer puis vérifier une
.......
..c:: image qui se trouve dans un registry. Il se base pour cela sur le projet open source
O'l
ï::::: Notary 1 incluant un client et un serveur et permettant d'interagir avec des collections
>-
0..
0
de confiance.
u
Que cela peut-il bien signifier en pratique et quelles sont les conséquences sur la
création d'images? Le plus simple est, comme toujours, de prendre un exemple.
Activons tout d'abord temporairement Docker Content Trust:

1. h ttps://[Link] m/notary/
8.2 Sécurisons Docker --------------------------12011
1 $ export DOCKER_CONTENT_TRUST=l
C ette variable n 'est configurée que pour la session bash active. Si vous désirez
l'avo ir active en permanence, il vous faudra la définir de manière permanente pour
l'utilisateur, typiquement en la rajoutant dans votre-/ . bas hrc

Créons un Dockerfile minimal :

FROM al pi ne :3.l
1 CMD pi ng loca l host

C onstruisons notre image en la taguant de telle façon que nous puissions ensuite
la pousser sur le Docker Hub. Nous devons pour cela spécifier le n om du dépôt
( dunoddocker) :

$ docker bui l d -t dunodd ocker/cont ent _trus t :l ates t


Sending bu il d cont ext t o Doc ker daemon 3. 786 MB
Step 1 : FROM al pine :3. l
3. 1: Pul l ing fr om l i brary/alpine
40f9ed72912e: Pul l complet e
Di gest :
sha256 : f3d4fl0120752f738efeee4e639 d4767110a2ebl0c9632aa86lb5d 5eb5a f7e35
Status : Downloaded newer i ma ge for al pi ne :3. l
---> 885194f4c89a
Step 2 : CMD pi ng l oca lhost
---> Run ni ng i n 5l bf540dad6e
---> 6282600887dc
Removing inte rmediate container 5lbf540dad6e
Successful ly bu il t 6282600887dc

N ous avons maintenant une image prête à être poussée sur le Docker Hub. C'est à
"'Cl
0 partir d 'ici que les ch oses d iffèrent d'un push normal. Poussons notre image avec la
c::
:::i
~
,.,
0 "O commande standard docker push
[Link];
\.0
.-t ~
0 V
V
N
'& $ docker push dunoddocker/content_t rust :la t est
@ ·c
B The pus h refers to a r epos itory [docker. io/d unoddoc ker /content_t rust ]
....... :::;
..c:: 8f eüa3ef03d9 : Prepari ng
1
CO
O'l c
ï::::: 0
c unaut hori zed : au thenti cation requ i red
>- c
o..
u
0 ·3ù
:::;
"O
N ous avons effectivement oublié de nous identifier sur le Docker Hub. Utilisons la
0
....
c. commande docker login avant de pousser notre image :
~
~
:::;
rS $ docker logi n -u dunoddocker
1
"O
0
c
Pa ssword :
8 Log i n Succeeded
(Ç) 1 $ docker push dunoddocker/cont ent tr ust :l at es t
Chapitre 8. Usage avancé de Docker

Le push commence normalement et vous obtenez ensuite un message vous


demandant de créer une phrase secrète et cela de ux fois de suite.

Signi ng and pushing trust metadata You are about t o crea te a new root signing
key passphrase . Thi s passphrase wil l be used t o protect t he most sensi ti ve key
in your signing system . Pl ease choose a l ong , compl ex passphr ase and be
careful to kee p t he passwo rd and the key f ile i t self secure and backed up . It
i s hi ghl y recommended that you use a password ma nager t o generate the
passph rase and keep i t safe . There wi l l be no way to recover th i s key . You can
f ind t he key i n yo ur config di recto ry .
Ente r passphr ase for new root key wi t h ID b059adb :
Repeat passp hrase f or new root key wi t h ID b059adb :
Enter passphr ase for new repository key wi t h ID Ob06cba
(doc ker . io/dunoddocker/cont en t_trust) :
Repeat passp hrase f or new re posi tory key with ID Ob06cba
(docker . io/d unoddocker/content_trust) :
Fin i shed i ni tia l i zi ng "docker .i o/dunoddocker/cont en t_trus t"
Success f ully si gned "docker . io/ dunoddoc ke r/content_t r ust ":l atest

En effet, Docker Content Trust repose sur l'utilisation de deux clés distinctes :
• la clé de tagging : elle est générée pour chaque dépôt. Elle peut
facilement être partagée avec quiconque voudrait pouvoir signer
du contenu pour ce dépôt. Elle est stockée dans le répertoire
- / .docker/trust/private/tuf_keys/docker. io/<reponame> ;
• la clé offline : c'est la clé la plus importante car c'est la clé root. Il est donc
critique de bien la protéger, car au contraire des clés de tagging, il n'est
pas possible de la récupérer. On peut d'ailleurs la trouver dans le dossier
-/.docker/trust/private/root_keys.

En vérité, il y a même une troisième clé, dite de timestamp. Elle est stockée côté
serveur et permet de s'assurer de la fraîcheur de l'image.

"'Cl
0
c:: Ma intenant que nous avons une image sur le Docker Hub, tout utilisateur voulant
:::i
0 utiliser notre image aura la garantie que ce sera bien celle du publicateur (car « buildé »
\.0
.-t
0
par lui) . De plus, grâce au mécanisme de clé de timestamp, il aura aussi la garantie que
N ce sera la dernière image pour le tag.
@
....... Il y a cependant une contrainte à bien comprendre : si vous activez Docker Content
..c::
O'l
·;:: Trust et que vous désirez « puller » une image qui n'est pas signée, vous aurez un
>-
0..
0
message d'erreur du type :
u
Us in g defau lt t ag : lates t
Er ror : remote tr ust data does not exist for docker .i o/xxx /yyy :
1 notary .docker . io does not have tr us t data for docker . i o/xxx/yyy

L'astuce est de rajouter le paramètre --d i sable -content -tr ust à la commande
doc ker pu ll pour ignorer cette contrainte de manière ponctuelle.
8.3 Installer un registry privé ------------------------12091
Docker Content Trust est relativement récent (Docker 1.8), mais il répond à une
vraie attente : garantir l'intégrité des images, particulièrement lorsque celles-ci sont
distribuées via des réseaux non sécurisés tels qu'Internet. Toutes les images officielles
disponibles sur le Docker Hub sont d'ailleurs maintenant signées par Docker lnc .

..
8.3 INSTALLER UN REGISTRY PRIVE
Nous avons expliqué dans le chapitre 1 le principe de registry Docker. Nous avons
ensuite jusqu'ici (et nous le ferons encore dans les chapitres suivants) utilisé essentiel-
lement le registry public de Docker : le Docker Hub.
Cependant, nous avons aussi évoqué le fait qu'il était possible d'installer un registry
Docker privé. Dans cette section gui traite de cette fonctionnalité, nous utiliserons
l'image officielle Docker qui est disponible à l'adresse suivante : [Link]
corn/_}registry/

8.3.1 Mot de passe et certificats

Nous avons besoin de créer pour notre registry :


• un compte (login/password) ;
• des certificats SSL auto-signés pour sécuriser l'API du registry avec HTTPS.

Pour ce faire, nous allons utiliser un conteneur qui va générer ces fichiers dans des
volumes qu'il nous suffira ensuite de brancher sur notre registry.
Pour créer le login/password, nous aurons besoin de l'utilitaire htpasswd qui
permet de générer une entrée cryptée dans un [Link], qui sera ensuite utilisé pour
l'authentification (en mode http basic). Cet utilitaire est disponible dans le repository
EPEL https-tools.
Pour la création des certificats, nous emploierons de nouveau l'utilitaire open s s1.
"'Cl
0
c ~
,., Voici le Dockerfile de notre conteneur de configuration :
:::i
"O
0 [Link];
\.0
.-t ~
0 V FROMcentos : 7
N V
'ii
@ ·c
B #I nst al l e l e reposi tory EPEL
....... :::;
..c CO RUN yum i nst al l -y -- seto pt =t sf l ag s=nodocs epel- rel ease && yum cl ean al l
O'l c
0
ï::::: c
>-
o. c #Inst al l e l es deux uti li taires do nt no us avons bes oi n
u
0 ·3ù RUN yum i nst al l -y -- setopt =t sfl ags=nodocs httpd -t ool s opens sl &&yum cl ean
:::;
"O
0 a11
....
c.
~
~ #Identi f i e deux vol umes desti nés a recevo i r l es f i chi ers
:::;
rS RUN mkd i r -p /opt /cert s
1 RUN mkd i r -p /opt/ aut h
"O
0
c VOLUME /opt/ cert s
8 VO LUM E /opt/aut h
(Ç)
Chapitre 8. Usage avancé de Docker

COPY ent rypoint . sh /[Link]


RUN chmod +x /entrypoi nt . sh

1 ENTRY POINT /[Link]


Il fait usage d'un script ENTRYPOINT nommé [Link] que vous prendrez
soin de d isposer dans le même répertoire que le Dockerfile. Voici son contenu:

if!/bi n/bas h
ifCréa t ion du premier compte
echo "Creati on d'un compt e pour l ' uti 1i sat eur $REG_LOGIN "
htpasswd -Bbn $REG LOGIN $REGPASSWD > /opt/aut h/htpasswd
jfCréa t ion des certi f i cats
echo "Creati on des certif i cats SS L"
openss l req -new key rsa :4096 -nodes -sha256 - keyout /opt/certs/domain . key
-x509 -days 365 -out /opt /certs /domain . crt -subj ' /CN=l oca l host '

Notez l'usage de deux variables d'environnement REGLOGIN e t REGPASSWD.


Celles-ci devront être passées en paramètre du docker r un .

N ous pouvons maintenant construire notre image:

1 $ docker bui l d -t regconfig .

8.3.2 Exécution de notre conteneur de configuration

Nous allons maintenant créer deux volumes nommés qui vont recevoir les fichiers à
créer:
• un volume certs_volume qui va recevoir les clefs publiq ue et privée SSL ;
• un volume auth_volume qui recevra le fichier htpasswd contenant le
"'Cl
0
login/password encrypté.
c::
:::i
0 Voici les instructions requises :
\.0
.-t
0
N
@ $ docker volume create -- name=certs_vol ume
.......
..c::
1 $docker volume create --name=aut h_vol ume
O'l
ï:::::
>-
0..
Nous pouvons maintenant lancer notre conteneur avec la commande suivante:
0
u
$ docker r un -- rm -- env REG LOGIN=admi n -- env REG PASSWD=admin l234 -v
1 certs_volume : /opt/cert s -v auth_volume : /opt/auth regconfig
Voici quelques explications relatives à la ligne de commande ci-dessus :
• - - rm va faire en sorte que ce conteneur s'autodétruise après usage. Il s'agit
clairement d'un conteneur de type script ;
8.3 Installer un registry privé ------------------------El
• - -env spécifie les valeurs pour les deux variables d'environnement (REGLOGIN
et REGPASSWD) contenant respectivement le login et le mot de passe de notre
compte sur le registry ;
• nous associons les volumes nommés à des chemins du conteneur :
- certs_volume va être associé au chemin /opt/certs et il recevra les certificats
SSL générés par openssl,
auth_ volume va être associé au chemin /opt/auth et il contiendra le fichier
htpasswd.

S i vous regardez le fichier [Link] plus haut, vous verrez que les différents
fichiers sont bien créés dans les chemins qui pointent vers nos deux volumes.

Voici le résultat de l'exécution de notre conteneur:

$docker run --rm --env REG_LOGIN=admin -- env REG_PASSWD=admin l234 -v


certs_volume: /opt /certs -v auth_volume : /opt/aut h regconfig
Creation d'un compt e pour l ' util i sateur admin
Creation des certi f icats SSL
Generating a 4096 bit RSA pri vate key
........................................ ++
................... ++
wr it i ng new priva t e key to ' /o pt/certs/domain . key'

Nous pouvons maintenant créer un conteneur pour aller vérifier que nos deux
volumes contiennent bien les fichiers dont nous avons besoin :

$ docker run --rm -t -i -v cert s_vo l ume : /opt /certs -v auth_vol ume : /opt/a ut h
centos : 7 /bi n/bas h
[root @42bda61680f6 /]# l s /opt/certs/
"'Cl
domain .crt doma i n. key
0 [root@42bda61680f6 /J# l s /opt/auth/
c:: ~
,.,
:::i
"O
htpasswd
0 [Link];
\.0
.-t ~
0
N
V
V C'est effectivement le cas !
'&
@ ·c
....... B
:::;
..c:: CO
O'l
ï:::::
c
0
c
8.3.3 Lancement du registry
>- c
o..
u
0 ·3ù La création de notre registry repose sur la commande suivante :
:::;
"O
0
....
c.
~
~ docker r un -d -p 5000 :5000 --restart=a lways - -name reg i stry \
:::;
rS -v aut h_volume : /a ut h \
1 -v certs_vol ume : /cert s \
"O
0
c -e "REGISTRY_AUTH=htpasswd " \
8 -e "REGISTRY_AUTH_HTPASSWD_REALM=Reg istry Rea l m" \
(Ç) -e REGIST RY_AUTH_HT PASSWD_PATH=/ auth/ht passwd \
Chapitre 8. Usage avancé de Docker

-e REGISTRY_HTTP_TLS_CERT IFICATE=/ ce rts/[Link] \


-e REGISTRY_HTTP_TLS_KEY=/cert s/ doma in . key \
1 reg ist ry :2

Vous noterez :
• que nous associons le volume au th_ volume (qui contient le fichier htpasswd)
au chemin /auth ;
• que nous associons le volume certs_volume (qui contient les deux clefs SSL
[Link] et [Link]) au chemin /certs.

Le registry va aller puiser dans ces deux chemins pour y trouver le login/password
et les certificats SSL.
Une fois le registry lancé, vérifions que nous pouvons nous y connecter:

$docker login loca l hos t:5000


Username (admi n): admin
Password :
1 Logi n Succeeded

Rappel: le mot de passe défini précédemment est« adminl234 »

8.3.4 Pousser une image

Poussons, par exemple, notre image de script de configuration regconfig définie plus
haut dans notre nouveau registry.
Nous devons d'abord taguer notre image à l'aide de l'instruction suivante :

1 $docker t ag regconfig loca lhost :5000 /regconfig


"'Cl
0
c:: Celle-ci crée une nouvelle entrée associant l'image que nous avions précédemment
:::i
0 construite à un tag dont le nom est compatible avec notre registry :
\.0
.-t
0
N
@ $ doc ker i mages
.......
..c:: REPOSITORY TAG IMAGE ID CREATED
O'l SIZE
ï:::::
>- localhos t:5000/regconfi g latest eb33ef7afd99 21 minutes
0..
0 ago 235 . 1 MB
u regconfi g la test eb33ef7afd99 21 mi nutes
ago 235. 1 MB

Nous voyons clairement que la même image eb33ef7afd99 a maintenant deux


noms d ifférents dans notre cache local.
Nous sommes à présent prêts à pousser n otre image dans le registry:
8.3 Installer un registry privé ------------------------El
$docker push l oca l host : 5000/regconfig
The push ref ers to a r epository [l oca lh ost: 5000/ r eg con fi g]
fc2ea 32faa0a : Pu shed
9a04fce8334 f: Pus hed
2318cd41f c71 : Pushed
267a1753b916 : Pus hed
bd 70 29c a7d8e : Pu shed
21 d4ec20adbe: Pus hed
5f70 bf18a086 : Pus hed
6a6c96337be l: Pu shed
latest : di gest :
sha256 :445da39665 fe 0315f a3 ff 76e4ee4466e9e l 2bad0 l d6d7 f a370a852dd5c3alf27 size :
2397

Nous pouvons vérifier que l'image est bien présente en utilisant curl pour interroger
l'API REST du registry (sans oublier le login/password) :

$ cu rl - u admin :admi nl 234 -k https : // l oca l host: 5000/v2/_cat al og


1 l" re posi t or i es ": [ "regconf i g"Jl

Notre image est bien chargée !

Le flag - k de curl est nécessaire car nos certificats SSL sont selfsigned. Ils seraient
donc rejetés par curl sans ce paramètre.

En résumé
Les trois chapitres de cette partie vous ont permis d'apprendre à fabriquer des images,
mais aussi à piloter le Docker Engine au travers de sa ligne de commande.
Il est maintenant temps d'aborder des exemples plus complexes mettant en jeu des
concepts plus pointus.
"'Cl
0
c::
:::i
0
\.0
.-t
0
N
@
.......
..c::
O'l
·;::
>-
0..
0
u
ï:J
0
c::
:::i
0
\.0
r-1
0
N
@
......,
..s:::::
Ol
·;:
>-
0..
0
u
-.
QUATRIEME PARTIE

Exemples
d'architectures et
concepts avancés

Cette dernière partie comprend trois chapitres qui sont autant d'exemples de mise en
œuvre d'architectures à base de conteneurs.
-0 Outre leur sujet propre, ces chapitres nous permettent aussi d'expliquer des
0
c:: concepts avancés que nous n'avons pas encore pu complètement aborder.
:::i
0
\.0 A insi cette partie comprend les chapitres suivants :
.-t
0
N • le chapitre 9 traite des architectures multi~conteneurs et nous permet d'aborder
@
.......
l'usage d'outils comme Supervisor, mais aussi de comprendre en détail la gestion
..c:: du réseau avec Docker (et plus spécifiquement du réseau de type bridge) ;
O'l
·;::
>-
0..
• le chapitre 10 montre comment utiliser Docker dans le cas d'un environnement
0
u de développement « intégration continue» . Il nous permet d'aborder l'usage
des conteneurs comme outils de déplo iement, mais aussi la notion de Docker
API, conteneur nécessaire pour utiliser Docker depuis un conteneur ;
• le chapitre 11 expose un exemple de mise en œuvre de la solution Docker
Swarm (que nous avons décrite dans le ch apitre 2). Il permet d'aborder le
dernier modèle de réseau Docker: le modèle overlay.

Chaque chapitre s'appuie sur des cas pratiques mettant en œuvre l'environnement
que vous avez créé dans le chapitre 3.
ï:J
0
c::
:::i
0
\.0
r-1
0
N
@
......,
..s:::::
Ol
·;:
>-
0..
0
u
9
Application multi-conteneurs

Rendre modulaire son infrastrudure


L'objectif de ce chapitre est d'expliquer comment utiliser Docker pour le dévelop,
pement d'application. Nous lèverons au passage le voile sur les communications
intrn,contene11rs.
À l'issue de ce chapitre, vous aurez compris les bases du réseau Docker, ainsi que
différentes techniques pour tirer tous les bénéfices d'une infrastructure « dockerisée » .

Tout au long de ce chapitre, nous allons travailler avec une application web basée
sur le fra mework PHP Symfony2 1. N ous aurons besoin pour cela :
"'Cl
0 • d'un serveur web. Nous utiliserons Nginx que vous avez déjà rencontré dans les
c
:::i chapitres 3 et 5 ;
0
\.0
.-t
• de PHP,fPM 2 pour exécuter notre application. PHP Fast Process Manager
0
N est une implémentation FastCGI PHP spécialement adaptée aux sites à forte
@ charge;
.......
..c
O'l
• et d'une base de données MariaDB3 pour la persistance .
'i:
>-
0.
0 Nous allons suivre plusieurs approches pour « dockeriser » notre application :
u
• tout d'abord, nous n'utiliserons qu'un conteneur et verrons rapidement les
limitations de ce modèle pour un environnement de production ;
• n ous répartirons ensuite nos différents moteurs d'exécution sur plusieurs conte,
neurs, afin de mettre en place une architecture de micro,services ;

1. [Link]
2. [Link]
3. [Link]
Chapitre 9. Application mufti-conteneurs

• nous terminerons ensu ite avec le meilleur des deux mondes en découvrant
Docker Compose 1.

À l'occasion , nous découvrirons aussi quelques astuces qui nous permettront de


mieux appréhender tous les avantages à utiliser un tel environnement, aussi bien pour
le développement que pour la mise en production d'une application.

9.1 UN SEUL CONTENEUR, PLUSIEURS PROCESSUS


La première idée que nous allons mettre en œuvre est la suivante : fabriquer une image
Docker fournissant tous les services nécessaires à notre application (Nginx, PHP-FPM
et MariaDB).
Schématiquement, le conteneur résultant aura cet aspect :

/. localhosl

Container lemp-symfony '

'-
NGUllX --
9000
-- Nil~""I ~
3306 M
#aoB
~ '~
4~ 80

-- ' ' ~

-- ...
........,
.;":.==·- --- ··· Volume Volume
-·-
l:l=-::.=--:;.. app bd
~ ~

Figure 9.1 - Application m ono-conteneur


"O
0
c
::i
0 Q uelques explications s'imposent:
\.0
.-t
0 • nous aurons donc un seul conteneur LEMP2 qui exposera le port 80 de Nginx .
N
Les autres ports nécessaires à notre application ne seront pas exposés sur notre
@
....... mach ine hôte ;
.c
O'l
ï::::: • nous utiliserons deux volumes: un qui contiendra le code source de notre
>-
0. application et un autre pour les fichiers de notre base de données.
0
u
Avec cette configuration, nous pourrons détruire/reconstruire/modifier notre conte-
neur sans risque de perdre des informations. En effet, notre code source et notre base de

1. [Link]
2. LEMP: Linux, Nginx, MySQL/MariaDB, PH P
9. 1 Un seul conteneur, plusieurs processus --------------------12191
données seront accessibles pour notre machine hôte et faciliteront le développement
de n otre application.
S i ce n 'est déjà fait, récupérez les fichiers nécessaires avec la commande suivante :

1 $gi t clone http s : //git hub. com/dunod-dock er/app l icat i on-mul ti-co nt eneurs . git

Tous les fichiers dont nous aurons besoin sont disponibles dans le réperto ire
supervisor. Nous allons décomposer petit à petit le Dockerfile qui va nous permettre
ensuite de créer l'image de notre futur conteneur.

9.1.1 Installation des moteurs d'exécution

Le Dockerfile que nous allons utiliser se trouve directement à la racine du réperto ire
superv isor. N otre image sera basée sur une distribution C entOS 7. Nous utiliserons
pour cela l'image officielle fournie par le Docker Hub:

1 FROM centos :7
N ous utilisons ensuite yum pour :
• installer le dépôt EPEL. Celui~ci nous permet d'obten ir des versions plus
récentes des différents programmes qu'en utilisant le dépôt standard de
C entOS;
• mettre à jour les paquets déjà présents sur notre image;
• installer Nginx, les différents paquets PHP nécessaires à Symfony dont PHP~
FPM, MariaDB (serveur et client) et finalement Supervisor. Nous verrons un
peu plus lo in ce qu'est Superv isor.
"'Cl
0
c::
:::i
~
,.,
0 "O # Dockerfile
[Link];
\.0 RUN yum i nst al l -y epel- releas e && \
.-t ~
0 V
V
yum updat e -y && \
N
'& yum i ns ta l l -y mariadb-server mariadb -client\
@ ·c
....... B
:::;
ngi nx \
..c::
O'l
CO
c
php -common php -cl i php -fpm php -mysq l php -apcu php -curl
ï::::: 0
c php-i nt 1 ph p-mb s tr i ng \
>- c superv i sor && \
o..
u
0 ·3ù yum cl ean al l
:::;
"O
0
....
c.
~
~
:::;
C ette façon d'écrire n otre Dockerfile suit les bonnes pratiques de Docker. Elle offre
rS un juste milieu entre lisibilité et nombre de couches pour notre image finale.
1
"O
0
c Maintenant que n ous avons installé nos moteurs d'exécution , il ne nous reste plus
8 qu'à les configurer. C ommençons tout d'abord par Nginx.
(Ç)
J22ol-------------------- Chapitre 9. Application mufti-conteneurs

9.1.2 Nginx
La façon dont Nginx et ses différents processus fonctionnen t est déterminée via des
fi chiers de configuration. Nous aurons besoin de deux fichiers :
• le fichier principal de configuration de Nginx. Par défaut, ce fichier qui se
nomme [Link], est présent dans le répertoire /etc/nginx/ sous C entOS 7 ;
• un fichier de configuratio n par site web, soit, dans notre cas, un fichier
symfony .conf qui contiendra la configuration Nginx propre à notre application .

Nous allons tout d'abord créer n otre propre fichier [Link] qui remplacera
ensuite celui créé lors de l'installation de N ginx :

worker_proc esses 2;
pi d /var/run/ng i nx . pid ;

event s { l

htt p {
sendfi l e on ;
def ault_type applicat i on/octet-st ream ;
i nc l ude /etc/ng i nx/mi me. t ypes;
i nc l ude /etc/ng i nx/si t es-enabled/* ;
access_log /var/log/nginx/access . log ;
error_l og /var/ log/ngi nx /error . l og;

L'explication exhaustive du contenu de ce fi chier dépassant nettement le périmètre


de cet ouvrage, nous n 'en expliquerons que les parties pertinentes :
• notre serveur Nginx utilisera deux processus pour répondre aux requêtes
(worker _processes 2; ) ;
• la configuration de notre serveur Symfony (le fichier [Link]) sera dispo-
nible dans le répertoire /etc/nginx/sites-enabled/. Nous le déclarons donc via un
include pour que N ginx tienne compte de ce répertoire lors du démarrage.
"'Cl
0
c
:::i Symfony propose une configuration minimale 1 pour Nginx que nous allons utiliser
0
\.0 dans notre fichier [Link]. Elle se base sur la capacité de Nginx à définir des server
.-t
0
N
blacks (l'équivalent des hôtes virtuels sous Apache) :
@
.......
..c server {
O'l
ï::::: listen 80 ;
>-
0.
0
server name symfony;
u root /var/www/my_app/web ;

loca t i on I { try_f i le s $uri /app . php$ i s_args$args ;

locat i on - A/ (app_dev lconfig)\ . php (/l$l


fas tcg i _pa ss 127 . 0. 0.1:9000;

1. [Link] nx
9. 1 Un seul conteneur, plusieurs processus - - - - - - - - - - - - - - - - - - - - 1221 I
f astcg i_split_pat h_i nfo -( .+\ . php)(/ .*)$;
i nclude f astcgi_params;
f astcgi_param SCR IPT_FI LENAME Srea lpa th_rootS f astcgi _script_name ;
f astcgi _param DOCUMENT_ROOT Srea l path_roo t;

l ocation - ·;app\ . php(/ ISl {


f astcgi_pass 127 . 0. 0. 1:9000 ;
f as tcgi_split_pa t h_info -( .+\ . php)(/ .*)$ ;
i nclude f as t cgi_params ;
f as tcgi_par am SCRIPT_FILENAME Srea lpath_rootS f astcgi_script_name;
f astcg i_param DOCUMENT_ROOT Srea l path_root ;
i nternal;

error_l og /var / l og/n gi nx/symfony_error . log ;


access_log /v ar/log/ ng i nx /symfony _access . log;

N ous voyons que :


• notre application sera disponible sur le port 80 de notre conteneur ;
• le dossier qui servira de réperto ire racine sera /var/www/my_app/web, notre
application Symfon y devant donc être disponible dans ce dossier ;
• dès qu'une requête HTTP sera émise à destination de l'application , elle sera
déléguée à PHP-FPM à l'adresse 127.0.0.l (ou localhost) sur le port 9000.

Nos deux fichiers sont ensuite copiés dans notre image, dans les réperto ires
standards de configuration de Nginx, via les instructions COPY du Dockerfile. Il
ne nous reste plus qu'à rendre notre site disponible (en créant un lien symbolique de
notre [Link] [Link] du répertoire sites-enabled vers sites-available ) grâce à une
commande RUN et créer notre réperto ire racine :

CO PY ngi nx/ng i nx . conf /etc /ng i nx/nginx . conf


CO PY ng i nx/symfony.c onf /etc/ngi nx/sites -ava i l abl e/
"'Cl
0
RUN mkd i r -p /et c/ ng inx/s i tes-enabl ed/ && \
c::
:::i
~
,., l n - s /etc/nginx/s i t es-available/symfony . conf
0 "O
[Link]; /etc/nginx/sites -enabled/symf ony && \
\.0
.-t ~
mkd i r -p /var/www /
0 V
N V
'&
@ ·c
B
.......
..c::
:::;
CO
9.1 .3 PHP-FPM
O'l c
0
ï::::: c
>- c La configuration de PHP-FPM suit la même logique que pour N ginx. Nous allons tout
o..
u
0 ·3ù d'abo rd créer, puis copier les fichiers de configurat ion dans le conteneur, à savoir :
:::;
"O
0
.... • un fichier de configuration propre à Symfony: [Link];
c.
~
~
:::; • un fi chier de configuration pour le processus PHP-FPM, [Link].
rS
1
"O
0
Symfon y impose d'avoir le paramètre da te . t i mezone défini au niveau de PHP.
c
8 l.:installation de PHP ne le fournissant pas par défaut, il nous faut donc le rajouter via
(Ç) notre fichier [Link].
J222I Chapitre 9. Application mufti-conteneurs

1 date . timezone=Europe/Paris
Ensuite, nous devons créer un autre fichier [Link], propre à PHP-FPM,
qui contient la configuration du processus qui traitera les demandes transmises par
Nginx. À nouveau, nous n e décrivons ci-dessous que les parties intéressantes :

[ symfony]
user = apache
group = apache

l isten = 0. 0.0. 0: 9000

catc h_wor kers_output = yes

php_admin_value[error_log] /v ar/log/ php- f pm/symfony_error .l og


php_admi n_flag[ log_errors] on

php_v al ue[session . save_handler] =files


php_val ue[ses sion .s ave_path] = /var /l i b/ php/s essi on

Nous remarquons que :


1
• notre processus utilisera l'utilisateur « apache » ;

• toute requête arrivant sur le port 9000 sera acceptée et traitée par ce pool de
connexion;
• nous définissons un fichier de log propre à notre application
(symfony_error.log) ;
• nous plaçons les fichiers de sessions qui seront créées par notre application dans
un réperto ire dédié.

Occupons-nous maintenant de n otre Dockerfile :


• n ous allons copier nos deux fichiers de configuration dans n otre image avec la
commande COPY ;
"'Cl
0
c:: • nous supprimons le fichier de configuration par défaut de PHP-FPM [Link]
:::i
0 puis créons le réperto ire pour stocker les données des sessions Symfony
\.0
.-t
(/var/lib/php/session), et donner les droits à l'utilisateur apach e (de sorte que le
0
N processus PHP-FPM puisse y accéder);
@
.......
• n ous terminons en récupérant l'installateur Symfony (il n ous sera utile pour
..c:: initia liser notre application) et en le rendant exécutable .
O'l
ï:::::
>-
0..
0 Voici la section du Dockerfile résultante :
u

1. Cet ut ilisateur, qui est créé par l'installation de PHP-FPM, est utilisé par défaut. Nous avons donc
choisi de le garder.
9.1 Un seul conteneur, plusieurs processus --------------------12231
#Ada ptati on de 11UID du user apac he
RUN usermod -u 1000 apache

#Copie de la confi guration php pour Symfony


CO PY php -fpm/symfony . i ni /et c/ php . dl
CO PY php- f pm/symfony. pool .con f /etc/ php -f pm. d/
RUN rm -rf /etc /php -f pm. d/www. conf && \
mkdi r -p /var/ l ib/php/session && \
chown -R apa che :apac he /va r / l i b/php
RUN curl -LsS ht t ps: //symfony . com/ i nsta l ler -o / usr/ l ocal / bi n/symfony && \
chmod a+x /usr/ l oca l /bi n/ symf ony

Certains auront remarqué que nous n'avons pas expliqué la commande usermod -u
1000 apache. Il s'agit d'une modification indirectement imposée pour assurer une
communication correcte entre le conteneur et son hôte au travers des volumes.
Nous y reviendrons en temps voulu.

9.1.4 MariaDB

La configuration de MariaDB est relativement rapide : nous lançons le script standard


d'installation (mysql_install_db) qui crée les schémas ainsi que l'utilisateur de base
et rajoutons les droits à l'utilisateur mysql (l'utilisateur par défaut de MariaDB) sur le
répertoire où sont stockées les données.

RUN /usr/ bi n/mys ql_i nst al l _db > /dev/null && \


1 chown -R mysq l :mysql /var/l i b/mysql/

9.1.5 Ports et volumes

Il ne n ous reste plus qu'à exposer le port 80 de Nginx et à définir deux volumes :
• un pour le code de notre application (/var/www/) ;
-0
0
c • un pour nos données MariaDB (/var/lib/mysql) .
:::i
0
\.0
.-t
0
N EXPOS E 80
@ 1 VOLUME [" /va r / l ib/mysq l / ", "/var/www/ "J
.......
..c
O'l
ï::::: Voilà ! Nous avons nos trois programmes installés et configurés. Il ne nous reste
>-
0. plus qu'à ajouter une commande CMD (ou ENTRYPOINT). Mais laquelle? N ous
0
u allons nous h eurter à une limitation de Docker : un seul processus peut tourner en
mode foreground (bloquant) par conteneur.
Comment donc faire tourner nos serveurs Nginx, PHP~FPM et MariaDB?
Pour ce faire, il nous faut utiliser un gestionnaire de services : nous allons employer
Supervisor1.

1. h ttp://[Link]/
J224I-------------------- Chapitre 9. Application mufti-conteneurs

9.1.6 Supervisor

Supervisor (ou plus précisément son démon supervisord) est, comme son nom
l'indique, un superviseur de processus. C'est lui qui sera le processus bloquant unique
du conteneur (celui avec le PID 1). Il va devoir démarrer, puis contrôler tous les autres
processus à savoir Nginx, PHP~FPM et MariaDB.
Sa configuration est stockée dans le fichier [Link]:

[supervisord]
nodaemon=true
l ogfile=/var/ l og/supervisor/supervisord .l og

[ program :php -fpm ]


command=/usr/sb i n/php- f pm -c / etc /php-fpm.d
auto restart=t r ue

[ program :n ginx]
command=/usr/sb i n/nginx -g "daemon of f; "
autorest art=tr ue

[ program :mysq l J
command=/usr/bin/mysq l d_safe

Nous définissons dans les blocs [ program] les processus que Supervisor devra
gérer. Sans entrer dans les détails, le paramètre comma nd correspond à la commande
qui va lancer le processus fils. Notez qu'il est possible de demander à Supervisor de
redémarrer automatiquement un processus qui se serait arrêté avec la commande
autorestart=true.
Il ne nous reste plus qu'à copier ce fichier et à configurer notre conteneur pour ne
lancer que Supervisor au dé marrage, le laissant ensuite démarrer et gérer les autres
processus:

AOD supervis or /s uperv isord . conf / etc/s upe r vi sor/conf . d/superv isord . conf
"'Cl
0
c:: CMO [" / usr/ bin /supervis ord", · -n·. ·- c·.
0
:::i

\.0
1 "/etc/superv i sor /conf .d/superv iso [Link] nf "]
.-t
0
N
@ 9.1.7 Notre code source
.......
..c::
O'l
·;::
Nous avons maintenant une image totalement fonctionnelle. Avant de la fabriquer à
>-
0.. l'aide de la commande docker bu i l d, il nous reste une dernière ch ose à faire: créer
0
u sur notre machine de développement le répertoire qui sera utilisé comme volume.
Nous les créons simplement avec la commande:

1 $ mkdir -p -/symfony -app/code

Il est maintenant temps d'expliquer pourquoi nous avons changé l'UID de


l'utilisateur apache un peu plus haut.
9.1 Un seul conteneur, plusieurs processus ---------------------l22sl
La gestion des droits entre hôte et conteneur
Dans notre exemple, le processus qui va lire notre code source pour le présenter
à travers l'interface HTTP de notre application est PHP-FPM. Nous avons vu
précédemment que celui-ci tournait avec l'utilisateur apache. Il est donc nécessaire
que cet utilisateur ait des droits en lecture sur les fichiers PHP (le code source).

L'utilisateur de PHP-FPM qui


va lire les fichiers PHP est
«apache» (UID:1000)

Container lemp-symfony
/var/www/

apache Volume monté dans le


L'utilisateur de l'hôte qut va conteneur.
«éditer» les fichiers PHP est Les fichiers PHP placés
«vagranl» (UID:1000)- c'est dans le répertoire de
l'utilisateur que nous avons l'hôte sont
défini dans le chapitre 3 pour vagrant automatiquement visibles
notre environnement de travail Volume app dans le conteneur

Figure 9.2 - Gestion des droits des fichiers dans les volumes montés

Nous avons décidé de créer un volume entre notre hôte et notre invité afin de
pouvoir modifier le code source depuis l'extérieur du conteneur.
C'est là que la question de l'UID entre en jeu. Le nom de l'utilisateur importe peu,
mais il est essentiel que les deux utilisateurs, vagrant à l'extérieur et apache à l'intérieur
aient le même UID pour disposer des mêmes droits d'accès. Dans le cas contraire,
les fichiers édités par notre utilisateur vagrant seraient illisibles pour notre utilisateur
apache.
"'Cl
0
c:: ~
,., O r sur notre hôte, la commande suivante nous apprend que l'utilisateur vagrant est
:::i
0 "O
[Link]; associé à l'U ID 1000 :
\.0
.-t ~
0 V
N V
'& $ cat /etc/passwd ]grep vagra nt
@
.......
..c::
·c
B
:::;
CO
1 vagrant :x: lOOO : lOOO : : / home/vagrant : /bin/bash
O'l c
0
ï::::: c Par défaut, l'utilisateur apache créé par le processus PHP-FPM dans le conteneur
>- c
o..
0 ·3ù est associé à l'UID 48 :
u :::;
"O
0
....
c.
~ [root@93llce834a53 /J
~
:::; # cat /etc/passwd ] grep apache
rS 1 apache :x:48:48:Apache : / usr/share/ httpd : /sbin/nol ogin
1
"O
0
c
8 Ceci explique la raison pour laquelle nous lançons la commande suivante dans
(Ç) notre Dockerfi le :
J226I Chapitre 9. Application mufti-conteneurs

1 RUN usermod -u 1000 apache

Celle-ci fait simplement en sorte que l'utilisateur apache puisse lire les fichiers
produits par notre utilisateur vagrant.

Création de l'image et lancement du conteneur


Construisons maintenant notre image :

$ docker bui l d -- tag=lemp -symfony .


Send i ng build co ntext to Docker daemon 14 .34 kB
Step 1 : FROM centos :7
--- > c8a648134623
Step 2 : MAINTA INER docker-ecosysteme@d un od . com
--- > Run ning i n d67413cdcb4f
--- > 5bc8b8e0c35f
Removing i nt ermediate conta i ner d67413cdcb4f
Step 3 : RUN yum i nsta ll -y epel - release && yum update -y && yum
instal l -y mariadb-server mariadb-cl ient nginx
php-common php-cl i php- fpm php-mysql php-apcu php-curl php-intl php-mbstring
supervisor && yum clean all
---> Run ning i n 7b5592 f42f3d

Nous pouvons vérifier que cette nouvelle image est effectivement disponible grâce
à la commande doc ker images , avec comme paramètre le nom de notre image (lemp-
symfony):

$ docker images l emp -symfony

REPOSI TORY TAG IMAGE ID CR EATED VIRTUAL SIZE


1 l emp -symfony l atest e7d3ca4528df 57 seconds ago 435 .4 MB

Lançons notre conteneur multiprocessus :


"'Cl
0
c::
:::i
0 $ doc ker run -d -p 8000 :80 -v $HOM E/symfony-app/code/ : /var/www/ -- name=l emp
\.0
.-t
0
1 l emp -symfony
N
@ Nous exposons le port 80 de Nginx sur le port 8000 de notre hôte. Nous montons
.......
..c:: aussi le volume pour notre code source $HOME/symfony-app/code sous /var/www.
O'l
ï:::::
>-
0..
0 Attention, le nom du chemin vers le répertoire de l'hôte dépend de l'endroit où
u
vous avez exécuté la commande mkdi r -p symfony-app/code. Ici nous supposons
que vous avez suivi nos instructions et ce répertoire devrait se trouver dans le home
de l'utilisateur vagrant.

Les données de MariaDB seront stockées dans un volume Docker non exposé à
l'hôte. Nous aurions aussi pu choisir de définir un volume nommé afin de ne pas perdre
les données en cas d'arrêt ou de destruction du conteneur. Nous nous contenterons de
cette approche simplifiée pour les besoins de cet exercice.
9. 1 Un seul conteneur, plusieurs processus

Voyons si tout est en ordre en visualisant l'arbre des processus à l'intérieur du


conteneur grâce à la commande suivante :

$ docker exec -it l emp ps axf


PID TTY STAT TIME COMMA ND
182 ? Rs+ 0:00 ps axf
1 ? Ss 0:00 /usr/bi n/python / usr/bin/s upervisord -n -c /etc/super
8 ? S 0:00 ngi nx : mas te r process /usr/sbi n/ngi nx -g daemon of f ;
71 ? S 0:00 \_ nginx : wor ker process
72 ? S 0:00 \_ nginx : worker process
9 ? S 0:00 php -fpm : mas t er process (/etc/p hp -fpm. conf)
116 ? S 0:00 \_ php -f pm : pool symfony
117 ? S 0:00 \_ php- fpm : pool symfony
10 ? S 0:00 /bi n/sh /usr/bin/mysq l d_safe - -port=3306
158 ? Sl 0:00 \_ /us r / l ibexec/mysqld --basedi r=/ usr -- datadir=/var

Nous avons:
• un processus supervisord avec le PID 1, ce qui signifie qu'il officie comme
processus racine (celui qui est géré par Docker) ;
• nous avons ensuite un processus N ginx avec deux processus fils (les deux workers
de notre configuration) ;
• un processus PHP, FPM avec deux workers (valeur du paramètre pm.start_servers
de [Link]) ;
• un processus mysqld_safe (MariaDB) qui n 'a qu'un unique worker.

Superviser peut exposer un socket TCP sur laquelle un serveur HTTP écoute et permet
de contrôler le processus supervisord depuis une interface graphique.
Pour l'activer, il faut rajouter une section au fichier de configuration [Link] :
[ i net_ht tp_server]
port=9001
et ensuite exposer ce port via une commande EX POSE 9001 dans notre Dockerfile.
Le serveur supervisord est ensuite disponible via [Link] (pour peu
"'Cl
que vous ayez ajouté -p 9001 :9001 à la commande docker run au lancement du
0
c conteneur).
:::i
0
\.0
.-t Superviser Status - Mozilla Firefox D lC
0
N .J • Supervisor Status x \...+
@
.......
~localhost:9001_ _ _ _ _ _ _ _ _ _ __ ~ ~ Rech_er_ch_er_ _
..c
O'l
'i:
>-
Supervisor statuS

0.
0
u 1UFRESH 11 ~ESTART All 11 STOi' All 1

State Descnpnon Uame Ac non

nrnng pld 9, uptime O:OO:ll


rlnling pid 7, uptime 0.00:11 Restart ~ ~ Tail ·f

pid 8, uptime [Link] Restart ~ Qllr....!..Q.g Tail ·f

~3.1.3 C 2006·2016 Ageodafess Consu!mg and Coœrbaors

Figure 9.3 - Interface de Supervisor


J22sl-------------------- Chapitre 9. Application mufti-conteneurs

Ajout du code applicatif


Notre conteneur est prêt. Nous devons maintenant init ialiser notre application.
Pour ce faire, Symfony dispose d'un installateur (que nous avons copié dans notre
conteneur). Lançons la commande suivante:

$docker exec - i -- user=apac he lemp /bi n/bas h -c 1cd /var/www/; symfony new
my_app 2. 81
Downloading Symfony ...

0 . 00 BI 5 . 17 MB :)}:)}:))}:))))}:)}:)}:)}(}:)))))))}:))}:):(}:)):)}:))}()}
................... . ....... . ................... . ...... . ....... . ............ . ................ . ...... . ....
0%
15 . 40 KB/ 5 . 17 MB .}. .}.. '.}{}' . } } )}'.}{}'. } '. }})'.}})) } '. }'.} '.}}}'.}'.)'.)}'.{ }})}{}{) }
. .. ... . ..... . . . . . . . . . . . . . . . .. .. ........ . .. .. . . . . . . . . . . ... . ......... .. . .. . .. .. . . . . .. .. ... .... . . ... . .
0%
31 . 40 KB/5 . 17 MB .}))}})})'.)'.}/{}}}}'.}'.}'.}' . }{}'.}'. }'.)}}})}}}}}'.}{}{}}}}
. .. . . .. . .. . ... .. .... . .. . . ... . .. . . .. . ... ... . . . .. . .. . . . .. . .... . .. ... .. . . .. . .. . . .. . .. . . . .. . .. . . . . . . . ... . ..
0%
4 7 . 40 KB / 5 . 17 MB :}{}{}:}})}:}{{}}}}):}}}:}{}:}{)}{}}}:} :}}}:} :} } }:} :: 0%
63 . 40 KB I 5 . 17 MB :)}}:/:(::(/((}:}}:}:(}}}:}:}}:)((}:}}:(}:}}:)}()}:/:(}}:}}::::
. . . .. . .. ... . ..... . . . . . . . . . . . . . . .. . ... ....... . .. .. . . . . . . . . . . . . . . ......... . .. .. . .. .. ... . .. .. ... .... . . . . . . .
1%
79 . 40 KB/5 .1 7 MB :}:} :}:}:}}}:}:} :):):}:}:}:}}):}:}:}:}:):}:}:}:}}}}}}}:}:)}}} 1%
95 40 KB/ 5 17 MB . -:-:-:-:-:·:-:-:·:-:-:-:·:-:-:·:-:-:-:·:-:-:-:·:-:-:-:-:-:-:·:-:-:·:-:-:-:-:-:-:·:-:-:·:-:-:-:-:-:-:·:-:-:·:-:-:-:-:·:-:-:-:-:-:·:-:-:·:-:-:·:-:-:-:·:-:-:·:-:-:-:-:-:-:-:·:-:-:·:-:-:-:·:-:-:·:-:-:·:- 1%

i~ ~ ::~ ~~ ~ ~ :i; ~ ~ 11if!iii!i!iii fiii!ii!f1iiiii!iiii!f!iii1i!iiiiiiiii!iiif!iiiiiii!!!iif!iii!ii!ii!iiiii!i!f iiiiii!iii!!i!iii iiiiiiiiiif!i i1iiiii!iii i1i i!i1i!iii!i!iiiifiiiiiiiiiii!i!iiiiiiiiiiiii!!iiiiii!fi!i ~ ~


1 1 1 1 1 1 11 1

Q ue fait~elle ?
Elle se connecte à notre conteneur et lance la commande symfony à l'intérieur
du conten eur. C ela a pour conséquence qu'il n'est pas nécessaire d'avoir l'installeur
Symfony ni même PHP sur notre machine hôte !
Elle va ensuite télécharger le code de Symfony et initialiser notre application dans
le répertoire /var/www/. C e répertoire étan t mon té sur notre hôte, n otre code source
est d irectement éditable.

localhost

lemp-symfony

-0
0
c::
:::i
0
\.0
.-t
0
N
@
....... s_cJocker exec - Volume
..c:: 1 user=apache
O'l -/symfony_
ï:::::
>- app/code
0..
0
u

Figure 9 .4 - docker exec symfony

Nous pouvons le vérifier aisément :


9. 1 Un seul conteneur, plusieurs processus

$ cd -/symf ony -app/code/my_app/


1s -1
t ota 1 96
drwxr -xr -x. 6 vagra nt 48 4096 21 jan v. 15 :53 app
drwxr -xr -x. 2 vagra nt 48 83 21 jan v. 15 :53 bi n
-rw- r- - r -- . 1 vagrant 48 2299 21 janv . 15: 53 [Link]
-rw- r -- r -- . 1 vagrant 48 75496 21 janv. 15: 53 composer . lock
-rw-rw-rw- . 1 vagrant 48 71 21 janv . 15 :53 README . md
drwxr-xr-x . 3 vagrant 48 38 21 jan v. 15:53 src
drwxr -xr -x. 15 vagrant 48 4096 21 janv . 15:53 vendor
drwxr-xr-x . 3 vagrant 48 4096 14 janv . 13:25 web

Dans notre commande docker exec, nous prec1sons que nous voulons que la
commande soit lancée en tant qu'utilisateur apache (- -user=apache ). Si nous ne
le faisons pas, Docker utilisera l'utilisateur root pour créer les répertoires de notre
application. Nous aurons alors un problème de permission sur notre volume (notre
utilisateur vagrant ne pourra pas accéder aux fichiers et donc les modifier).

Vous pouvez maintenant voir votre application tourner depuis votre hôte sur l'URL
[Link]

W ..c ....1- Mozllh Flreto11

+ IOC~ftOU

Welcome to
Symfony 2.8 . 2
.... Î vou1 oppucauon 1s reaay to start [Link] on 1t at:
Y" /var/w.M./my_app/

What ' s next?

Re:ad Symrony documenta Uon to learn


How to create your U r et page in symfony

"'Cl
0
c
:::i
~
,.,
"O
0 [Link];
\.0
.-t ~
0
N
V
V
, ,.
'ii
@ ·c
....... B
..c
:::;
CO Figure 9 .5 - Notre application totalement fonctionnelle
O'l c
0
ï::::: c
>-
o. c
0 ·3ù Pour finaliser la mise en place de notre environnement, créons le schéma dans
u :::;
"O
0
notre base de données avec la commande suivante :
....
c.
~
~
:::; $ docker exec -i -- user=apache l emp php /var/www/my_app/app/console
rS doctrine :database:create
1
"O
0
c
1 Crea ted database 'symf ony ' f or connection named defaul t
8
(Ç)
J23ol-------------------- Chapitre 9. Application mufti-conteneurs

Vous vous demandez sûrement comment notre application Symfony a pu


créer un sch éma sans que nous ne configurions les paramètres de connexion.
C ela est tout simplement dû au fait que les paramètres par défaut de Symfony
(my_app/app/config/[Link]) correspondent à ceux de notre configuration
de MariaDB (user root sans mot de passe tournant sur le même hôte).

Ajout du code applicatif


Pour éviter d'avoir à taper chaque fois la longue commande doc ker ex ec nécessaire
à l'exécution des instructions Symfony, il suffit de créer un alias dans le ~[Link] de
l'utilisateur courant ( vagrant dans notre cas) avec la commande suivante :

$ ec ho -e "\ nal ias symf ony='docker exec -i --u ser=apache l emp php
1 /var/www/my_a pp/ app/conso l e'" » -! .bashrc

Maintenant, quand vous voudrez utiliser la ligne de commande de Symfony, il


[Link] de taper, par exemple, pour vider le cache dans l'environnement de production:

1 $ symfony cache : cl ear -- env=prod -- no -de bug

comme si Symfony était installé en local sur votre machine (n'oubliez pas de
relancer votre terminal pour prendre en compte l'alias symfony) .

9.1.8 En conclusion
Nous avons donc notre environnement de développement prêt et fonctionnel sans
avoir installé un seul mote ur d'exécution sur notre machine. Si vous avez besoin de
mettre à jour PHP ou de changer de base de données, une simple modification du
Dockerfile et un build suffiront pour mettre à niveau votre environnement.
Cependant, cette approche a quelques inconvénients :
-0
0
c::
:::i
• nous ne pouvons pas profiter des images du Docker Hub (si ce n'est l'image de
0 base de notre OS) ;
\.0
.-t
0 • notre configuration n'est pas en ligne avec une architecture micro,services
N
comme nous l'avons expliqué au chapitre 1 : elle n'est pas facilement scalable,
@
....... elle crée des dépendances fortes entre les processus et elle n e nous permet donc
..c::
O'l
ï:::::
pas de changer faci lement les caractéristiques de déplo iement.
>-
0..
0
u Voyons comment résoudre ces inconvénients avec une approche orientée micro,
services.

9.2 APPLICATION MULTl-CONTENEURS


Nous allons maintenant rendre modulaire notre application.
9.2 Application mufti-conteneurs ------------------------12311
Pour cela, n ous utiliserons quatre conteneurs comme l'illustre la figure ci-dessous :

localhost

NGIVIX d
MariaDB

80

li

"9f«Wy"l l l

~ -:.==-- Volume Volume


c: =·:::::·: .;:-- app bd

Figure 9.6 - Application multi-conteneurs

Chaque conteneur aura donc son propre Dockerfile (à l'exception de MariaDB car
nous utiliserons l'image officielle disponible sur le Hub Docker).

Tous les fichiers que nous allons utiliser dans le cadre de ce paragraphe sont
disponibles dans le répertoire micro-service . Par convention, nous avons utilisé un
sous-répertoire par conteneur qui contient le Dockerfile et les fichiers nécessaires à
la fabrication de l'image correspondante.

9.2.1 Nginx
Nous utiliserons maintenant l'image de base de Nginx que nous étendons en intégrant
"'Cl
0
nos spécificités :
c::
:::i
~
,.,
"O
0 [Link];
\.0 FROM ng i nx
.-t ~
0 V
N V
'&
·c
CO PY ngi nx .conf /etc/ ngi nx/ [Link]
@
....... B
:::;
COPY symfony .conf /etc/ ng i nx /sites·available/
..c::
O'l
CO
c
RUN mkd i r -p /etc/nginx/s i tes-enabled/ && \
ï::::: 0
c mkd ir -p /var/www/ && \
>- c
o.. l n - s /etc/nginx/s i tes -ava ilable/symfony .conf
u
0 ·3ù /e t c/nginx/s i tes -enab l ed/symfony
:::;
"O
0
....
c.
~ Comme vous pouvez le constater, notre Dockerfile est beaucoup plus simple que
~
:::; dans notre version initiale :
rS
"O
1
• il contient uniquement les informations nécessaires à Nginx ;
0
c
8 • nous n'avons plus besoin de nous occuper d'installation, d 'exposition du port,
(Ç) etc. Tout est déjà inclus et optimisé dans l'image de base.
12321-------------------- Chapitre 9. Application mufti-conteneurs

Dès que vous le pouvez, utilisez les images du Hub Docker ([Link]
en particulier les images officielles. Elles vous permettent de bénéficier des meilleures
pratiques et d'accélérer la mise en œuvre de solutions courantes.

9.2.2 PHP-FPM

Notre Dockerfile pour le conteneur PHP-FPM est relativement simple car il reprend
les mêmes commandes que dan s notre exemple précédent. La différence principale
réside dans la ligne CMD qui lance PHP-FPM et non plus Supervisor.

FROM centos :7

MAINTA INER docker -ecosysteme@dunod . com

RU N yum i nsta ll -y epel -re l ease && \


yum update -y && \
yum i nstall -y php -common php -cl i php- f pm php- mysql php-apc u php -c url
php -i nt l php -mbst r i ng && \
yum clean all

COPY php -fpm/symfony .i ni /etc/php . d/


COPY php -fpm/symfony . pool . conf /etc/php-fpm .d/
RU N rm - rf /etc/php -fpm.d/www . conf
mkdir -p /var/www/ && \
mkdir -p /var/l i b/php/session && \
chown -R apache :apac he /var/lib/p hp

RUN curl - LsS https : //symfony . com/i nstal l er -o /usr/loca l /bin /symfony && \
chmod a+x /usr/ l ocal/ bi n/symfony

EXPOSE 9000

CMD [ "/usr/sbin/php -fpm ", "-c /etc/php -f pm .d"J


"'Cl
0
c
:::i
0
\.0
.-t
9.2.3 Notre code source
0
N
@ Pour suivre les bonnes pratiq ues de gestion des volumes, notre code sera d isponible
....... via un data container, c'est-à-dire un conteneur qui n'exposera qu'un volume. En effet,
..c
O'l
'i: ce conteneur n'a pas de C MD ou d'ENTRYPO INT. Ce n'est pas un conteneur destiné
>-
0.
0
à exécuter un processus, mais simplement le conteneur qui va gérer les données via le
u volume qu'il spécifie.
N ous le lierons ensuite aux conteneurs Nginx et PHP-FPM.

FROM busybox :glibc

1 VO LUME /var/www
9.2 Application mufti-conteneurs ------------------------12331
Ce conteneur sera basé sur l'image busybox 1• C'est une image de taille minimale,
mais qui est largement suffisante pour ce conteneur.

Depuis la version 1.9 de Docker, il est possible d'utiliser des volumes nommés,
c'est-à-dire de créer des volumes (avec la commande docker volume) puis de les
associer à divers conteneurs. Cette alternative sera probablement à privilégier à
l'avenir, mais de nombreuses architectures utilisent encore le principe des data
containers. Il est donc utile de connaître ce pattern Docker.

9.2.4 Assemblons tout cela


Il ne nous reste plus maintenant qu'à fabriquer nos images :

$ do cke r bui ld -t symf ony- ngi nx ngi nx

$ docker bui ld -t symf ony-php php -f pm

$ docker build -t symf ony-code symfony-code

Ces commandes doivent être lancées depuis le réperto ire -/application,multi,


conteneurs/micro,services. Chacune indique en paramètre le répertoire workdir
pour la construction de l'image correspondante.

Nos images étant prêtes, nous pouvons maintenant les utiliser pour nos conteneurs.
Démarrons déjà n otre data container qui va contenir le code source de notre application
(et être par la suite lié aux conteneurs Nginx et PHP,fPM) :

1 $ docker create -v $HOM E/symfony -ap p/code/ : /var/www/ -- name code symfony-code

"'Cl
0 Nous ne faisons que créer ce conteneur, sans le démarrer, avec la commande
c
:::i
~
,., docker cr eate. Nous montons ensuite le répertoire où se trouve le code source de
"O
0 [Link];
\.0 notre application.
.-t ~
0 V
N V Démarrons ensuite Nginx et PHP,fPM en les liant à notre data container car ils
'ii
@ ·c vont tous les deux avoir besoin d'y accéder.
....... [Link];
..c CO
O'l c
0
ï::::: c
>- c N'oubliez pas d'arrêter le conteneur lemp créé lors de l'exercice précédent avec
o.
u
0 ·3ù doc ke r st op 1emp, sinon vous obtiendrez un message d'erreur indiquant que le port
:::;
"O
0
....
8000 est déjà en cours d'utilisation.
c.
~
~
:::;
rS
1
"O
0
c
8
(Ç) 1. [Link]
12341-------------------- Chapitre 9. Application mufti-conteneurs

$ docker r un -d -p 8000 :80 - -volumes -from code -- name nginx symf ony -nginx
ea 53c8 l fd485357732 b05c0400346769282240d9940ec93f 53c92af46648a l 58
$ docker r un -d --volumes -f r om code --name php symfony-php
1 Obc7a35166afb91a01d5c0433dl83e2bf5 1ebla3a6f8b460a8cce0e4978c9f18

Il ne nous reste plus qu'à démarrer notre conteneur MariaDB. Cette fois,ci,
nous utilisons le conteneur officiel MariaDB. Ce dernier nécessite une variable
d'en v ironnement contenant le mot de passe de l'utilisateur root pour démarrer.

1 $docker r un -d -e MYSQL_ROOT_PASSWORD=root --n ame ma ri adb ma riadb : l O. l

Ouvrons n otre navigateur et saisissons l'adresse [Link] pour nous


apercevoir que nous obtenons un message d'erreur!
Si nous regardons les logs de notre conteneur Nginx, la raison est claire :

doc ker exec -i nginx cat /var/ l og/nginx/symfony_error . log


2016/01/28 21 :28 :25 [error ] 6#6 : *l con nect() fa il ed (11 1: Connection ref used)
while con necting to upstream . cl ient : 172 .17 .0. 1, server : symfony , reques t:
1 "GET I HTTP/1 .1", upstream: "fastcgi : //127 .0.0. 1:9000 ", host : "l oca l host :8000 "

Nous avons mainten ant plusieurs conteneurs et nos moteurs d'exécution ne


peuvent donc plus communiquer librement comme s'ils étaient installés sur le même
hôte. Chaque processus est isolé des autres.
Nous devons donc utiliser les fonctionnalités du réseau Docker.

..
9.3 LE RESEAU DOCKER
La communication entre conteneurs est un élément clé du succès de l'architecture
micro,serv ices et par conséquent de Docker. Elle repose sur la librairie libnetwork 1
qui est n ée de la volonté d'extraire le système de gestion du réseau du moteur. Elle
-0
0 implémente le modèle CNM (Container N etwork Madel) que nous allons brièvement
c
:::i présenter pour bien comprendre ensuite les différents types de réseaux que fournit
0
\.0
Docker.
.-t
0
N N ous lèverons finalement le secret sur la gestion d'iptables par Docker et la gestion
@ du ONS.
.......
..c
Ol
ï:::::
>-
0. 9.3.1 Libnetwork et le modèle CNM
0
u
Le modèle CNM est véritablement une abstraction pour la communication inter,
conteneurs (potentiellement déployés sur des h ôtes différents).
Elle repose sur trois composants principaux qui permettent de couvrir toutes les
topologies de réseaux.

1. h ttps://[Link]/docker/1ibn etwork
9.3 Le réseau Docker ----------------------------12351
Hôte 1 Hôte 2

Container

Sandbox

Figure 9 .7 - Modèle CNM

N ous avons:
• le sandbox : il contient la configuration réseau du conteneur. Elle inclut les
interfaces réseau (ethO... ), les tables de routage et les configurations ONS. Dans
le cas de Docker, il y en a une par conteneur et son implémentation est un
namespace 1 network de notre machine hôte ;
• le endpoint : il permet de relier un sandbox à un network. Dans n otre cas, ce
sera typiquement une paire veth. Un endpoint n'est lié qu'à un sandbox et un
network. U n conteneur aura donc autant de endpoints que de network auquel il
est connecté ;
• le network: c'est un ensemble de endpoints qui peuvent communiquer ensemble.
Il n 'est au final qu'une abstraction sur une implémentation d'un pilote (driver)
qui fournit les fonctionnalités de connectivité.

Libnetwork fournit plusieurs drivers que nous retrouvons plus lo in dans ce chapitre
car certains sont utilisés par Docker :
• null : c'est un driver un peu particulier qui signifie « pas de réseau » . Il est là par
souci de rétrocompatibilité au niveau de Docker ;
• overlay : ce driver est pour l'instant le seul qui permette une communicat ion
"O
0 entre plusieurs hôtes. Nous l'utiliserons dans le chapitre suivant qui est consacré
c ~
,.,
:::i
"O
à Docker Swarm ;
0 [Link];
\.0 • host: permet de rendre disponible la configuration de la machine hôte à notre
.-t
0
.,.,
~
conteneur ; le conteneur pe ut donc directement accéder à toutes les ressources
N
'1;:
@ ·c de l'hôte ;
....... [Link];
.c
O'l
CO
c • remote : ce n'est pas à proprement parler un driver, mais un proxy pour un driver
distant. Il permet d'intégrer des drivers externes tels que Weave2 ou Openstack
ï::::: 0
>- c
o. c
0 ·3ù Kuryr3 ;
u :::;
"O
0
....
c.
~
~
:::;
rS
1
"O
0 l. Pour plus d' information sur la notion de namespace, vous pouvez vous reporter au ch apitre l.
c
8 2. [Link] works/products/weave-net/
(Ç) 3. [Link] ub .com/openstack/k uryr
Chapitre 9. Application mufti-conteneurs

• bridge : ce driver se base sur un bridge Linux 1• Il n'est disponible qu'à l'intérieur
d'un même hôte.

Le driver bridge, qui est le driver historique de Docker, est encore celui qui est
utilisé par défaut. Nous allons voir en détail comment il fonctionne, maintenant que
nous avons une représentation claire du CNM.
Par volonté de simplicité, nous utiliserons de manière égale les termes réseau et
driver.

Notez que, tout comme pour les volumes, Docker propose à des tiers de fabriquer
des plugins pour des systèmes externes de gestion de réseau. Nous verrons donc
prochainement des spécialistes des équipements de routage et de sécurité proposer
des plugins pour gérer les réseaux de conteneurs.

9.3.2 L'interface dockerO et le réseau bridge

Pour lister les réseaux disponibles pour nos conteneurs au niveau de notre démon
Docker sur notre hôte, nous utilisons la commande suivante :

$ docker networ k ls
NETWORK ID NAME DR IVER
b2d747bcd553 hast hast
8998ee49ca35 bridge bridge
758827c4904b none null

En fait, Docker est installé par défaut avec trois sous-réseaux :


• none : ce réseau utilise le driver null de libnetwork, et il n'a donc pas d'interface
réseau. Tout conteneur en faisant partie n'aura donc pas d'accès réseau et
ne pourra pas être connecté à un autre conteneur. Les cas d'utilisations sont
rares (définition du sous-réseau avec des outils tiers comme pipework2 ou un
l:l
conteneur temporaire qui fait une action et s'arrête) et nous ne les couvrirons
0
c pas dans ce livre ;
:::i
0 • hast: ce sous-réseau permet de rendre disponible la configuration de notre
\.0
.-t
0
machine hôte à notre conteneur. La commande i f conf i g dans un conteneur
N et sur notre hôte donnerait les mêmes résultats. Ce type de réseau simplifie la
@
....... communication du conteneur avec l'hôte, mais au détriment de la lisibilité des
..c
O'l liens réseau. On l'utilisera essentiellement pour la mise au point des conteneurs
ï:::::
>-
0.
ou lorsqu'on se trouve dans une architecture mixte conteneur et hôte;
0
u • bridge : c'est le sous-réseau historique de Docker qui permet de connecter
plusieurs conteneurs.

Regardons-le plus en détail avec la commande suivante :

1. [Link] [Link]/collaborate/workgroups/n etworking/bridge


2. [Link]
9.3 Le réseau Docker ---------------------------12371

$ docker networ k inspect bridge


[

"Name ": "bridge ",


"Id " :
"9df329 fa 52975a8af8cf33042 a48561087c7 e7d60a2b694eaf7a7b4b6d969d4e",
"Scope" : "local " ,
"Driver" : "b ri dge",
"En abl eIPv6 ": fa l se ,
"IPAM" : t
"D river ": "defa ul t",
"Options ": null,
"Confi g": [
{
"Subnet ": "1 72 . 17.0.0/16 "

},
"Options ": (
"com .docker . network . bri dge .default_bridge ": "tr ue",
"com .docker . network . bri dge .enab l e_i cc ": "t r ue " ,
"com .docker . networ k. bri dge .enabl e_ip_masquerade ": "t r ue",
"com .docker . network . bri dge . host_binding_i pv4": "[Link]",
"com .docker . network . bri dge . name ": "doc kerO " ,
"com .docker . networ [Link] iv er .mt u": "1500"
}

Nous voyons que ce réseau est bien de type bridge et qu'il dispose des adresses
IP 172.17 .0.1/16. Lors de l'installation de Docker, ce dernier a créé un pont virtuel
Ethernet, n ommé dockerO sur notre machine h ôte. La commande i fconfi g nous
permet de voir les détails de cette interface :

$ i f confi g dockerO
"'Cl dockerO : f l ags=4099<UP , BROADCAST , MU LTI CAST> mtu 1500
0
c:: ~
,., i net 172. 17 .0.1 netmas k 255 . 255 .0.0 broadcas t 0.0. 0.0
:::i
0 "O i net6 fe80 : :42 :4ff :fe06 :bldd pre f ix len 64 scopei d Ox20<lin k>
[Link];
\.0 et her 02 :42 :04 :06 :bl :dd t xqueuel en 0 (Ethernet)
.-t ~
0 V RX pa ckets 2489 byt es 116961 (114 .2 Ki B)
N V
'& RX errors 0 drop ped 0 ove rr uns 0 f rame 0
@ ·c
....... B TX packets 2549 bytes 29591068 (28 . 2 MiB)
:::;
..c:: CO TX errors 0 dropped 0 over ru ns 0 ca r ri er 0 col l isions 0
O'l c
0
ï::::: c
>- c
o..
u
0 ·3ù Cette interface est elle~même connectée ensuite à l'interface réseau de l'h ôte et
:::;
"O
0
.... permet aux conteneurs de communiquer entre eux ainsi qu'avec l'extérieur.
c.
~
~
:::;
Au démarrage d'un conteneur, Docker crée une interface v irtue lle sur l'hôte avec
rS un nom du type veth4bdf012 et assigne une adresse IP libre. Cette interface est ensuite
1
"O
0
connectée à l'interface ethO de notre conteneur.
c
8
(Ç)
Chapitre 9. Application mufti-conteneurs

Dans le cas de notre application, nous aurons une configuration similaire à la figure
ci~dessous.

localhost

NGllllX Maria DB

Figure 9.8 - Réseau bridge

Vous pouvez lister toutes les interfaces virtuelles connectées sur notre interface
dockerO avec la commande suivante :

$ sudo brct l show dockerO


bridge name bridge id STP enabled i nterfaces
dockerO 8000 . 02422bl d4dda no ve t h96 fl da3
vethece49e7
vethf cef3c4

Pour connaître la configuration réseau d'un de notre conteneur ph p, il suffit


d'utiliser la commande suivante:

"'Cl $docker inspect php 1 j q . [ [Link]


0 {
c::
:::i
0 "Bridge ": "",
\.0 "Sa ndboxID " :
.-t
0 "820b96e0b448 l dfe f dd4d8d2fc09 10cd45dca5969b668d896df 254lbaa33d5a2 " ,
N
"Hairpi nMode " : fa l se ,
@ "Li nklocalI Pv6Address ": " ",
.......
..c:: "Li nk LocalIPv6Pre fi xlen ": O.
O'l
ï::::: "Por t s" : {
>-
0.. "9000/tcp ": nul 1
u
0
} .
"SandboxKey " : "/var/run/docker/netns/820b96e0b448 " .
"SecondaryI PAddresses " : nul 1.
"Secondary! Pv6Addresses ": nu l l .
"Endpo i nt ID ":
"9ladcfec7ea5cac6cfde9lc7b297 l b6feddc2c35e669b2edf90d49ee733 f 8aad " ,
"Ga t eway" : "172 . 17. 0 . l",
"Gl obal !Pv6Address ": '"' ,
"Gl obalIPv6 Prefixlen ": 0 ,
9.3 Le réseau Docker ---------------------------12391
"IPAddre ss ": "172. 17. 0. 3" ,
"IPPref i xLen ": 16,
"I Pv6Ga t eway ": "",
"MacAddress " : "02:42 :ac : ll: 00 :03 " ,
"Networks " : (
"br i dge ": (
"I PAMConfi g": nul l ,
"Lin ks ": null .
"Al i ases ": nul l ,
"Networ k!D" :
"9df329fa5297 5a8a f8c f33042a48 561087c 7e7d60a2b694ea f 7a7b4b6d969d4e" ,
"Endpoi nt ID " :
"91adcfec7ea 5cac6cf de9 1c7b29 71 b6feddc2c35e669b2ed f 90d49ee733f 8aad " ,
"Gat eway ": "172 . 17 . 0. l " ,
"I PAddress " : "172 .1 7. 0. 3" ,
"I PPrefix len" : 16 ,
"!Pv6Gat eway": "",
"Gl oba l ! Pv6Address ":
"Gl oba l! Pv6Pref i xl en" : 0,
"MacAddress ": "02 :42:ac :l l :00 :03 "

Nous retrouvons bien l'adresse de la gateway (172.17 .0.1) assignée automatique-


ment par Docker et l'adresse IP de n otre conteneur (172. l 7.0.3) est aussi présente
dans le sous-réseau de notre réseau bridge.

Le Networkld, SandboxID et le Endpo intlD correspondent à ceux présentés dans


le modèle C NM au chapitre précédent.

Nos conteneurs sont don c tous sur le même réseau. Cela ne signifie pourtant pas
qu'ils se connaissent, qu'ils puissent être jo ints depuis l'extérieur du réseau ou qu'ils
puissent accéder à Internet.

"'Cl
0
c:: ~
,., 9.3.3 Communication entre conteneurs
:::i
"O
0 [Link];
\.0
.-t ~
La communication de nos conteneurs entre eux et avec le monde extérieur est
0 V
N V contrô lée à deux niveaux :
'&
@ ·c
....... B
:::;
• En premier lieu, au niveau de la machine h ôte : permet-elle le transfert des
..c:: CO
O'l c
0
paquets IP ?
ï::::: c
>- c • Ensuite par la configuration d'iptables qui gère le dialogue avec le monde
o..
u
0 ·3ù
:::; extérieur.
"O
0
....
c.
~
~
Transfert des paquets IP
:::;
rS Le fait que les paquets IP soient transmis (forwarded ) par la machine hôte est gouverné
1
"O
0
c
par la variable système (kernel) net.ipv4. conf. [Link]. Sa valeur courante est
8 simple à obtenir avec la commande suivante :
(Ç)
J24ol Chapitre 9. Application mufti-conteneurs

$ sysct l net . ipv4. conf. [Link]


net . i pv4. conf .all . forward i ng = 1
#Pour changer sa val eur si cette dern i ère es t égale à 0 c .à.d. non act i vée
1 $ sudo sys ct l net . i pv4. conf. al l . forward i ng=l

Si le forwarding n'est pas activé, les conteneurs ne peuvent ni communiquer entre


eux, ni atteindre un réseau externe comme Internet.
Il est possible de surcharger la valeur système dé[Link] au démarrage du démon
Docker par le paramètre - - i p-fo rwa rd (par défaut à true).
Attention , dans le cas improbable où vous voudriez le désactiver, le paramètre
- - i p-fo rwa rd=f al se n'aurait aucun effet si la valeur de net.ipv4 .[Link] est
à 1, c'est-à-dire activée au niveau système.

Docker et lptables
Iptables est un pare-feu logiciel présent par défaut dans la grande majorité des
distributions Linux. Il serait plus juste de parler d'iptables/[Link] car iptables n'est
finalement qu'un moyen de configuration de netfilter1 qui réalise effectivement le filtre
des paquets réseau au niveau du kernel Linux.
Le réseau Docker bridge (ainsi que tous les autres types de réseaux Docker) se base
sur iptables pour autoriser/refuser les connexions entre conteneurs.

Si vous désirez ne pas laisser Docker modifier votre configuration iptables ou si


vous disposez, par exemple, d'autres outils pour le faire, vous pouvez l'empêcher en
passant le paramètre - - i pt ab l e s=f al se au démarrage du démon Docker.

Regardons maintenant comment Docker utilise iptables pour certains cas courants.

Accès à d'autres réseaux


-0 Pour sortir d'un sous-réseau géré par Docker, il est n écessaire que notre gateway
0
c implémente du masquage d'adresses IP (nos IP privées n'étant pas routables sur
:::i
0 Internet). Par défaut, le démon Docker démarre avec le paramètre - - i p-masq=t rue
\.0
.-t qui a pour conséquence de rajouter des règles dans notre configuration iptables. Nous
0
N pouvons le voir facilement avec la commande suivante:
@
.......
..c
Ol
'i: $ sudo i pt abl es -t na t -L -n
>-
0.
u
0 Cha i n POSTROUTING (pol i cy ACC EPT)
target prot opt so urce des ti nation
MASOU ERAD E all 172 . 17 .0.0/16 [Link]

l. [Link] [Link]/
9.3 Le réseau Docker ----------------------------12411
Dans ce cas, notre réseau bridge ( 1 72.1 7 .0.0/16) pourra accéder à toute IP en dehors
de ce réseau. Il est bien sûr possible de bloquer l'accès des conteneurs à l'extérieur de
ce réseau en passant le paramètre - - i p - masq=f a1 se au démarrage du démon Docker.

Communications inter-conteneurs
Nous devons ici bien séparer deux types de réseau bridge Docker :
• nous avons le réseau prédéfini qui se nomme « bridge » et qui utilise le driver
libnetworl<. de type bridge. C'est le réseau historique de Docker;
• nous pouvons aussi créer un nouveau réseau privé de type bridge. Celui-ci résout
les limitations du réseau historique.

Quelles sont donc les différences ?

Tableau 9.1 - Différences entre les deux réseaux bridge

Réseau bridge via dockerO Réseau de type bridge


Créé par défaut au démarrage du démon Docker. Doit être créé manuellement avec la corn-
mande docker networ k create.
Utilisation du pont internet prédéfini dockerO. Création d'un nouveau pont ethernet
propre au réseau br-xxx.
Tout nouveau conteneur est automatiquement Connexion manuelle du conteneur sur ce
connecté à ce réseau si aucun réseau n'est spécifié. réseau avec la commande doc ker networ k
connect ou en passant le paramètre - - net=
à la commande do cker run.
Si - - i cc=f a 1se, nécessite la déclaration explicite via Le paramètre - - i cc est ignoré et tous
des links pour connecter les conteneurs entre eux via les conteneurs du même réseau peuvent
le paramètre - -1 i nk de la commande doc ker run. communiquer ensemble par défaut.
Si un conteneur lié via un link est supprimé, il faut Si un conteneur est supprimé et recréé avec
recréer tous les conteneurs qui avaient un lien vers le même nom, les conteneurs qui en ont
ce conteneur. En effet, sans DNS, l'adresse IP à besoin le trouveront toujours.
laquelle est lié ce conteneur peut changer (et aura
probablement changée) au démarrage du nouveau
conteneur.
"'Cl C'est la plus grosse limitation des links Docker.
0
c
:::i
~
,., Si un lien est créé entre deux conteneurs, Docker crée Plus nécessaire.
"O
0 [Link]; automatiquement des variables d'environnement sur
\.0 le conteneur ciblea concernant son nom.
.-t ~
0 V
N V Ne peut être supprimé. Peut être supprimé avec la commande
'ii
@ ·c do cker networ k rm.
....... [Link];
..c CO
O'l c
0 a. [Link] engine/userguide/networking/default_network/dockerlinks/
ï::::: c
>-
o. c
u
0 ·3ù
:::;
"O
Vous l'aurez compris, le n ouveau système de réseau est plus flexible et plus
0
.... configurable que le réseau bridge historique avec son système de liens. Docker conseille
c.
~
~ d'ailleurs fortement de passer sur le nouveau modèle de réseau car les liens seront
:::;
rS dépréciés dans une future version de Docker.
1
"O
0
c Nous allons donc regarder la communication inter-conteneurs avec un nouveau
8 réseau. Tout d'abord, déconnectons nos conteneurs du réseau bridge par défaut.
(Ç)
J242I -------------------- Chapitre 9. Application mufti-conteneurs

$ docker network disconnect br id ge ngi nx


$ docker network disconnect bridge php
1 $ docker network dis connect bridge mariadb

Créons un nouveau réseau my_net et connectons-y nos conteneurs :

$ docker network crea t e -d br i dge my_net


a34441233b8ded3e9fdd56a9e33e5lc3115e56e623832a9689c2f241d6f7a8b0
$ docker netwo rk connect my_net ng i nx
$ docker networ k connect my_net php
$ doc ker network connect my_net mariadb

Nous précisons que nous voulons un type de réseau bridge avec l'option -d
(optionnelle car c'est la valeur par défaut). Docker crée automatiquement un pont
Ethernet et un sous-réseau.

NB : La commande doc ker network create accepte des paramètres qui permettent
de définir l'IP de la gateway ( - -gateway), le sous-réseau ( - -s ubnet au format CIDR)
et la plage d'IP ( - -i p-range ).

Nos conteneurs sont maintenant sur le même réseau et peuvent communiquer


entre eux soit par IP, soit en utilisant le nom du conteneur comme nom d'hôte. Les
ports exposés par le conteneur sont eux aussi disponibles. Pour nous en convaincre,
connectons-nous dans le conteneur php (nous installerons le logiciel nmap pour
obtenir un peu plus d'information) :

$ doc ke r exec -i t php / bi n/bash


[r oot@1844d7 f5 d5e6 /]# yum instal l -y nmap
[r oot@1844d7 f 5d5e6 /J# nmap -T4 mariadb

St arti ng Nmap 6.40 ( htt p: //nmap . org l at 2016 -01 -27 16:26 UTC
"'Cl
Nmap sca n report for mariadb (172 . 18 . 0.4)
0
c:: Host is up (0 . 000014s l atency) .
:::i Not shown: 999 cl osed ports
0
\.0
PORT STATE SERV ICE
.-t
0
3306/ t cp open mysq l
N MAC Address : 02 :42 :AC : l2 :00 :04 (Un known)
@
.......
..c:: Nmap done : 1 IP address (1 host up) scanned in 0. 35 s
O'l
ï::::: [r oot@1844d7 f 5d5e6 /]# nmap -T4 ng i nx
>-
0..
u
0 Starti ng Nmap 6.40 ( htt p: //nmap . org l at 2016-01-27 16:27 UTC
Nmap sca n report for nginx (172 .18. 0. 3)
Host is up (0 . 000014s l atency) .
Not shown : 999 cl osed ports
PORT STATE SERV ICE
80/tc p open http
MAC Address : 02 :42 :AC : l2 :00 :03 (Un known)

Nmap done: 1 IP address (1 host up) scan ned in 0. 14 seconds


9.3 Le réseau Docker ---------------------------12431
Nous voyons que notre conteneur nginx a l'IP 172. 18.0.3 et expose son port 80,
mariadb ayant l'IP [Link] et exposant le port 3306.
Reste un mystère pour que tout soit totalement transparent : comment notre
conteneur réussit, il à résoudre les noms mariadb ou nginx ?
Depuis la version 1.10 de Docker, un serveur DNS a été intégré au démon. La
résolution des adresses IP peut donc aussi s'appuyer sur ce serveur DNS, qui en principe
est automatiquement ajouté à la liste des serveurs DNS du conteneur. Néanmoins,
Docker, dans sa documentation la plus récente indique que le mode de résolution
de nom de domaine peut varier en fonction des implémentations de Docker. À ce
titre, Docker lnc. recommande de ne faire aucune hypothèse sur le conteneur des
fichiers /etc/hasts ou /etc/[Link]. Regardons cela après avoir installé les utilitaires
bind,utils :

r oot@bca409b26400 : /# yum inst al l -y bi nd-utils


r oot@bc a409b26400: /# dig ng i nx
; <<>> Di G 9. 9. 4-RedHat -9. 9. 4-29 .el7_2 .3 <<>> ngi nx
global options : +cmd
Got answer :
-»HEADER«- opcode: OUERY . status : NO ERROR . i d: 22562
flags : qr rd ra ; OUERY : 1, ANSWER : 1, AUTHOR ITY : 0, ADDIT IONAL : 0

QUESTI ON SECTION :
;nginx . INA

; ; ANSWER SECTION :
ngi nx . 600INA172. 19 . 0.4

Query ti me : 0 msec
SERVER: 127 . 0.0.1 1#53(127. 0. 0. 11)
WHEN : Sun J un 26 09 : 09 : 09 UTC 2016
MSG SIZE rcvd : 44

Nous voyons que le serveur DNS a l'adresse [Link] , ce que nous confirme le
"'Cl
0 [Link] /etc/[Link]:
c::
:::i
~
,.,
"O
0 [Link];
\.0
.-t ~ r oot@bc a409b26400: /# cat /etc/re [Link]
0 V
N V search home
'&
·c nameserver 127 . 0.0.1 1
@
.......
..c::
O'l
B
:::;
CO
c
0
1 options ndots :O
ï::::: c
>- c
o.. U tilisons ce que nous venons d'apprendre pour faire fonctionner notre application
u
0 ·3ù
:::;
"O
Symfony.
0
....
c.
~
~
:::;
rS 9.3.4 Mise en œuvre sur notre application Symfony
1
"O
0
c
8 Ayant déjà créé notre réseau au chapitre précédent, il ne nous reste plus qu'à adapter
(Ç) nos fichiers de configuration pour qu'ils l'utilisent.
Chapitre 9. Application mufti-conteneurs

Nginx
Pour notre serveur N ginx, il faut que nous configurions la localisation de PHP,fPM :
au lieu de nous connecter à localhost, nous devons utiliser le conteneur php.
Éditons no tre fichier [Link] et remplaçons simplement l'IP [Link] par
ph p (le nom de notre conteneur) :

$ vi $HOME/ap plication-mul t i -contene urs/micro -services/ngi nx/symfony . conf


fi DEV
locat i on~ -;(app_dev lconfig)\ . php(/l$l (
f astcg i _pass php: 9000 ;
f astcg i_spl i t_path_i nfo A( .+\ . php)(/ .*)$ ;
i nclude fastcgi_params ;
f astcg i_param SCR I PT_FILENAME $realpath_root$ f as t cgi _sc r ipt _name ;
f as t cg i _para m DOCUMENT_ROOT $rea lpat h_root;

Il PROD
loca t i on~ A/app\ . php(/l$l
f as tcgi_pass php:9000 ;

Il suffit ensuite de relancer la création de notre image, de supprimer l'ancien


cont eneur nginx et de démarrer un nouveau conteneur en le connectant bien à notre
nouveau réseau my_net :

$ docker bui l d -t symfony -ngi nx ng i nx


$ doc ker rm -f ngi nx
$ docker r un -d -p 8000 :80 -- net my_net --volumes-from code --name nginx
1 symfony-ngi nx

PHP-FPM

"'Cl
Ici, nous n'avons que le fichier de connexion de base de données à modifier :
0
c::
:::i
0
\.0
$ vi $HOME/symf ony -app/code/my_ap p/a pp/con fi g/paramet ers .yml
.-t
0
N Il This f i le is auto-generated duri ng the composer instal l
@ parameters :
.......
..c:: data base_host : mari adb
O'l
·;:: database_port : 3306
>-
0.. data base_name : symf ony
0 database_user : root
u
database_password : root
ma il er_transport : smt p

Redémarrons n otre conteneur avec docke r restart ph p pour que notre configura,
tion soit prise en compte ; nous avons mainten ant une application utilisant tous les
bénéfi ces du réseau Docker :
9.4 Orchestration avec Docker Compose --------------------12451
• nous pouvons remplacer n'importe lequel de nos conteneurs, et il ne sera pas
nécessaire de reconfigurer les autres à partir du moment, où, bien sûr, son nom
ne change pas ;
• n ous n'avons plus à lier nos conteneurs manuellement lorsque n ous les démar~
rons.

N ous avons beaucoup progressé depuis notre première tentative avec un seul
conteneur. Nous pouvons cependant faire encore mieux. En effet , pour construire et
démarrer tous nos conteneurs, il faut un nombre important de commandes Docker et
nous devons n ous rappeler à chaque fois tous les paramètres à utiliser (port à exposer,
volumes, réseaux ... ).
H eureusement, Docker propose une solution pour documenter tout cela, Docker
C ompose.

9.4 ORCHESTRATION AVEC DOCKER COMPOSE

Docker C ompose vous permet de définir dans un fichier de configuration toutes


les dépendances de votre application multi~conteneurs. Ensuite, avec une seule
commande, il vous perme t de démarrer tous les conteneurs de votre application.

Docker Compose est le module d'orchestration de la suite Docker. Nous l'avons


déjà évoqué dans notre chapitre 2. À noter que d 'autres solutions CaaS, comme
Kubem etes, disposent de leur propre module d'orchestration. Docker C ompose
reste néanmo ins très utilisé par la communauté en raison de sa simplicité.

Regardons comment mettre cela en œ uvre pour notre application Symfony.

"'Cl
0
c::
:::i
~
,., 9.4 .1 Introduction et premiers pas avec Docker Compose
"O
0 [Link];
\.0
.-t
0
~
V C ompose nécessite bien sûr que Docker soit installé sur votre hôte. Il peut être utilisé
N V
'&
·c
sous Mac OS X (inclus par défaut dans Docker ToolBox) et sous Linux, mais n'est pas
@
....... B
:::; encore pris en charge sous W indows.
..c:: CO
O'l c
ï::::: 0
c L'installation se fait en récupérant l'exécutable depuis le dépôt GitHub avec curl:
>- c
o..
u
0 ·3ù
:::;
"O
0
.... $ sudo su
c.
~ $ curl - L ht tps : //g it hub . com/docker/compose/releases/download/1. 7. 1/docker -
~
:::;
compose -' uname -s ' - ' uname -m' >
rS /usr/local/bi n/docker-compose
"O
1
$ chmod +x /u sr/ l ocal/bin/docker -compose
0
c $ /usr/loca l /b i n/docker -compose - -version
8 docker-compose version 1. 7. 1, build Oa9ab35
(Ç)
Chapitre 9. Application mufti-conteneurs

Docker Compose recherche par défaut un fichier de configuration dans le répertoire


courant, nommé [Link], au format YAML 1. Ce fichier est le descripteur
de notre application, il permet de définir :
• les conteneurs avec leurs relations, les volumes qu'ils utilisent, les ports qu'ils
exposent;
• les réseaux nécessaires à votre application (même si Docker Compose en crée
un par défaut si vous n'en spécifiez aucun) ;
• les volumes éventuellement partagés entre les différents conteneurs.

Il est tout à fait possible de fournir à Docker Compose un fichier avec un autre nom
à l'aide du paramètre - f . Il peut même accepter plusieurs fichiers de configuration :
dans ce cas, il fusionnera leur contenu.

Docker Compose utilise aussi la notion de projet. Il faut voir un projet comme une
instance de votre application. Par défaut, le nom du projet sera celui du répertoire
courant. On peut bien sûr en passer un autre avec le paramètre - p.
Mettons tout cela en œ uvre.

9.4.2 Notre application

Nous allons utiliser la version 2 du format du fichier Docker Compose. En effet, Le


format a changé avec la version 1.6 et nécessite au moins le Docker Engine 1.10. Les
raisons principales de ce changement sont liées au support des volumes et des réseaux.

Vous trouvez l'intégralité du fichier [Link] de notre application dans


le répertoire -/applica tion-multi-conteneurs/docker-compose.

"'Cl ver sion: '2'


0
c
::i
0 serv ices :
\.0 code :
.-t
0 bui l d:
N
context : symfony-code
@
.......
cont ai ner_name : code
..c
O'l
vo l umes :
ï::::: - $HOME/symf ony -app/code/ : /var/www/
>-
0.
0
u ng i nx:
bui l d:
context : ngi nx
conta i ner_name : ng i nx
depend s_on :
- php

l. [Link]
9.4 Orchestration avec Docker Compose ---------------------12471
ports:
- 8000 :80
volumes_from:
- code

php :
build :
con t ext: php -fpm
conta iner_na me : php
vol umes_from :
- code

db :
image : mariadb :lO . l
conta iner_name : db
env i ro nment :
MYSOL_ROOT_PASSWORD : root

Nous retrouvons :
• le fait que nous utilisons la version 2 du format Compose ;
• un bloc servi ces : qui contient la définition de nos quatre conteneurs;
• pour ch aque conteneur, nous avons un paramètre bui l d qui permet de spécifier
le chemin du répertoire à utiliser comme contexte de création. Docker Compose
fabriquera une nouvelle version de notre image si nécessaire ;
• nous spécifions aussi le no m de nos conteneurs avec le paramètre
con t ai ner _na me . S i nous ne le spécifions pas, Docker Compose générera
automatiquement un nom à partir <lu nom <le projet et <lu nom <lu bloc (par
exemple, pour notre conteneur nginx, ce sera dockercompose_nginx_l) ;
• le paramètre depends_on permet de nous assurer que le conteneur php sera
disponible lors du démarrage de nginx. Si nous n 'avons pas ce paramètre, le
conteneur nginx s'arrête s'il démarre avant le conteneur php ;
• le reste des paramètres est relativement simple à comprendre et correspond dans
"'Cl leur syntaxe aux paramètres de la ligne de commande Docker.
0
c::
:::i
~
,.,
0 "O
[Link];
Démarrons notre service (il faut lancer la commande depuis le réperto ire qui
\.0
.-t ~ contient notre fichier docker~[Link]) :
0 V
N V
'&
@ ·c
.......
..c::
B
:::;
CO
1 $ /usr/local/ bi n/docker -compose up -d
O'l c
0
ï::::: c
>- c
o.. Cette commande va:
u
0 ·3ù
:::;
"O
0
.... • créer les images de nos services à partir de nos différents Dockerfile ;
c.
~
~
• pour ch aque image, démarrer un conten eur basé sur la configuration (ports,
:::;
rS volumes ... ) de notre fichier docker~[Link]. Le paramètre - d est iden tique
"O
1
à celui de Docker : nos conteneurs seront démarrés en mode démon ;
0
c
8 • créer un réseau (de type bridge) avec le nom de notre projet (ce que nous
(Ç) pouvons vérifier, après lancement, grâce à la commande docker network l s) .
Chapitre 9. Application mufti-conteneurs

Un des avantages majeurs de Docker Compose est qu'il est possible d'utiliser
la commande docker-compose up de manière répétée. Si la configuration de notre
application (c'est-à-dire notre fichier [Link]) ou une de nos images a
changé, Docker Compose va arrêter et redémarrer de nouveaux conteneurs. Et si nos
anciens conteneurs avaient des volumes, ces derniers seront attachés aux nouveaux,
garantissant que notre application soit toujours fonctionnelle sans perte de données.

Vous pouvez passer à la commande docker-compose up les paramètres


-- no -r ecreate ou (à l'opposé) -- force -r ecreate pour respectivement ne pas
recréer/forcer la recréation systématique de tous les conteneurs.

Docker Compose fournit un ensemble de commandes similaires aux commandes du


Docker Engine, ce qui simplifie d'autant plus son utilisation. Ces commandes affectent
tous les conteneurs de notre projet.

Tableau 9.2 - Commandes Docker Compose

Commande Résultat
docker-compose ps Liste les conteneurs de notre application.

docker-compose logs Affiche une vue agrégée de tous les logs de notre
application.
docker-compose start /docker-compose stop Démarre/arrête l'ensemble des conteneurs de
notre application.
docker-compose pause / docker-compose Met en pause/relance les processus qui tournent
un pause dans les conteneurs de notre application.
docker-compose rm Supprime tous les conteneurs de notre application.
Le paramètre -v permet de forcer la suppression
même si les conteneurs sont démarrés.

-0
0
c:: En résumé
:::i
0
\.0
Ce chapitre nous a permis de suivre pas à pas la création d'une application
.-t
0 multi-processus. Nous avons vu comment combiner plusieurs processus au sein d'un
N
@
même conteneur avec Supervisor. Même si la chose n'est pas recommandée, elle est
.......
..c::
toujours couramment pratiquée. Nous avons ensuite vu comment implémenter une
O'l
·;:: application à base de micro-services et, notamment, comment en configurer le réseau.
>-
0.. Enfin, nous nous sommes penchés sur Docker Compose, l'outil d'orchestration de la
0
u suite Docker pour centraliser et automatiser la création de nos services.
10
Intégration continue avec
Docker

Dans ce chapitre, n ous allons mettre en place un système d'intégration continue


(dont l'acronyme anglais est C I, pour Continuous Integration) reposant sur des
contene urs Docker. D 'une part, nous utiliserons ces derniers pour déployer les
outils nécessaires à notre CI entièrement « dockerisée » , puis n ous construirons
et packagerons une application dans un conteneur afin de la déployer ensuite dans
plusieurs environnements (développement, test et production dans notre cas).

10.1 AVANT DE COMMENCER


10.1.1 Quelques mots sur l'intégration continue
"'Cl
0
c::
:::i
~
,., Un système d'intégration continue permet de supporter le cycle de v ie complet
"O
0 [Link]; d'une application , de sa conception à son déplo iement. Il a pour objectif de mettre à
\.0
.-t
0
~
V
disposition dans un en vironnement de C I une version fonctionnelle de l'application
N V
'&
·c
à chaque instant (c'est,à,dire généralement après chaque modification du code source
@
....... B
:::; ou de la configuration de l'application).
..c:: CO
O'l c
0
ï::::: c
>- c Pour aller encore plus loin, certaines entreprises mettent aujourd'hui en œ uvre
o..
u
0 ·3ù des approches de type déplo iement continue (continuous delivery ou CD) où des
:::;
"O
0
....
c.
versions de l'application sont déployées en production plusieurs fois par semaine,
~
voire par jour.
~
:::;
rS
1
"O
0
Dans ce chapitre, n ous allons mettre en œ uvre une version simplifiée, mais
c
8 fonctionnelle de cette approche qui nous permettra de comprendre les apports des
(Ç) conteneurs à ces pratiques de plus en plus courantes.
J2sol ------------------ Chapitre 10. Intégration continue avec Docker

Pour cela, nous aurons besoin des outils suivants :


• un outil d'intégration continue permettant la construction applicative (par
exemple, la compilation d'une application Java) afin de produire des artefacts
logiciels (dans notre cas, une image Docker). Nous l'utiliserons aussi pour
les déplo iements dans nos divers environnements. Pour notre exemple, nous
utiliserons Jenkins 1 ;
• un outil de gestion de code source permettant de versionner le code d'une
application. Pour notre exemple, nous utiliserons G iLab 2 qui repose sur Git et
offre une interface graphique proche de celle de GitHub ;
• un outil de suivi des exigences (issues tracking en anglais) perme ttant de
créer des ticke ts décrivant les besoins e t anomalies d'une application. Nous
ne présenterons pas cet aspect dans notre exemple, toutefois GitLab ferait très
bien l'affaire ;
• un outil de dépôt des artefacts logiciels permettant de centraliser les compo-
sants issus de la phase de construction applicative (compilation et condition-
nement). Comme pour l'outil de suivi des exigences, nous n'aborderons pas
les détails de ce composant. C ependant, un registry privé Docker, ou encore le
Docker Hub lui-même, pourrait convenir à cet usage.

Regardons maintenant conc rèteme nt les conteneurs outils nécessaires à notre


environne ment d 'intégration continue.

10.1.2 Les conteneurs outils

Rappelons tout d'abord les objectifs de notre système d'intégration continue :


• construire automatiquement une image Docker générique après toute modifi-
cation (commit) du code. Par générique, nous entendons déployable dans tout
en v ironnement ;
• mettre en place trois environnements : le premier pour le développement, le
"'Cl deuxième, qui sera déployé automatiquement, pour le test, et pour finir, le
0
c troisième pour la production. Ce dernier permettra de déployer des versions
:::i
0 release du code (c'est-à-dire considérées comme testées et stables) ;
\.0
.-t
0
• gérer un cycle de versions, c'est-à-dire être capable de taguer un code afin de le
N
mettre en production.
@
.......
..c Le schéma ci-contre illustre l'architecture globale qui sera mise en place, aussi bien
O'l
ï:::::
>-
0.
nos conteneurs outils que ceux embarquant l'application :
0
u

1. [Link] io/
2. [Link]
10.1 Avant de commencer - - - - - - - - - - - - - - - - - - - - - - - - - - l2s 1 I

Localhost

GltHub

0
Dép6t
"./hello-world

Web Hook

Docker API , - - - - - . . Jenklns


API Docker
dla tant

j L =mJ

1 HeloWorld Job: Build
[JOb: Deploy Te&t )
Jo~ Deploy Prad J

(

Figure 10.1 - Notre architecture cible

Gitlab
G itLab est un conteneur qui intègre notamment l'outil de gestion de version Git.
N ous commencerons par forker le dépôt h ello;world présent dans le dépôt GitHub
de cet ouvrage. Ensuite, Gitlab sera utilisé comme source pour les builds Jenkins
et permettra de versionner l'application en définissant des tags correspondant aux
versions stables de l'application.

Le fork de l'application hello-world depuis GitHub est réalisé afin d'obtenir directement
"'Cl
0 une application fonctionnelle et correctement configurée. Cette opération n'est faite
c:: ~
,.,
0
:::i
"O qu'une seule fois et aucun push vers GitHub ne sera effectué.
[Link];
\.0
.-t ~
0 V
N V Le code de l'application sera touj ours « pushé » dans la branche master, ainsi cette
'&
@ ·c dernière contiendra en tout temps la dernière version de l'application . C omme cela
....... B
:::;
..c:: CO
est mentionné plus h aut, n ous utiliserons les tags pour marquer l'application à livrer
O'l c
0
ï::::: c en production.
>- c
o..
u
0 ·3ù
:::;
"O
0
.... Le Git flow
c.
~
~ L'utilisation de Git se fait généralement en respectant certaines conventions, notamment
:::;
rS au niveau des branches. Une convention communément utilisée est le Git flow.
1
"O
0
Le Git flow est représenté par deux branches principales, master et develop, ainsi que
c
8 par des branches secondaires pour la réalisation des fonctionnalités et la correction
(Ç) des anomalies (feature branches).
J2s2I------------------ Chapitre 10. Intégration continue avec Docker

La branche master représente la code base qui est actuellement en production, aucun
push n'y est directement effectué. La branche develop représente la code base incluant
les dernières fonctionnalités considérées comme développées. Lors d'une release, la
branche develop est ainsi fusionnée dans la branche master (afin que cette dernière
contienne la code base de production}.
Pour chaque nouvelle fonctionnalité ou anomalie, un développeur crée une branche
temporaire dans laquelle il « pushera » ses modifications. Une fois le développement
terminé, il demandera la fusion de sa branche dans la branche develop (et supprimera
généralement sa branche}. C'est ce qu'on nomme une pull request.
Par souci de simplification, nous ne respectons pas dans notre exemple le Git flow,
mais nous ne pouvons que vous encourager à le faire dans le cadre de vos projets.

N ous configurerons un webhook dans GitLab afin de déclencher automatiquement


un build dans Jenkins après chaque push, c'est-à-dire après toute modification de
l'application. Ce webhook utilisera la branche master.

Jenkins
Jenkins est utilisé pour construire (build en anglais) l'application sous la forme d'une
image Docker (en s'appuyant sur Gradle 1 , comme nous le verrons un peu plus lo in),
puis pour la déployer dans nos deux environnements, un de test et un autre de
production. Pour cela, nous aurons besoin de trois jobs :
• Build : ce job clonera la code base de l'application selon la version souhaitée
(c'est-à-dire soit la branche master, soit un tag représentant une version) et
con struira une image D ocke r contena nt n o tre application. Il d é léguera cette
tâche au conteneur Docker API ;
• Deploy test: ce job invoquera aussi l'API Docker distant (du conteneur Docker
API) afin d'instancier un conteneur basé sur l'image créée par le job Build.
Il utilisera touj ours l'image basée sur la branche master e t sera déclenché
automatiquement après tout build ;
• Deploy prod : ce job est assez similaire au précédent, à la différence qu'il faudra
"'Cl
0
c spécifier la version de l'image à utiliser (un tag dans notre cas).
:::i
0
\.0
.-t
Docker API
0
N
@
Docker API est un conteneur qui contiendra une API Docker distant (autrement dit
....... un « Docker dans Docker »). Il construira les images à la demande du job Jenkins
..c
O'l
ï:::::
Build, et démarrera des conteneurs à la demande des jobs Deploy test et Deploy prod.
>-
0.
0 Ces derniers seront ensuite embarqués directemen t dans le conteneur Docker APL
u

l. h ttp://[Link]/
10. 1 Avant de commencer -------------------------12531
Environnement de développement
L'environnement de développement est un conten eur, associé à un volume dev qui
contient une copie (ou p lutôt un clone ) du code, permettant de tester rapidement un
nouveau développement con çu localement. Le développemen t, à proprement parler,
sera quant à lui directement effectué depuis la mach in e h ôte.

10.1.3 Notre application HelloWorld

N otre application sera un simple « H ello World » développé grâce au framework


SpringMVC 1 (Java) e t qui utilisera le serveur d 'application SpringBoot 2 . En termes
du code de l'application , il n'y a pas grand-ch ose à dire : il s'agit d 'un contrô leur (au
sen s MVC du terme pour Model View Controller) définissant une unique action et
produisant une vue qui affich e un « H ello, {name} » , {name} étant un paramètre que
1'on peut donner à la route de n otre action .

Le code de l'application Hello W orld est fourni grâce à un fork dan s GitHub que
n ous ferons un peu p lus tard

L'application n 'aura aucun état si bien qu'aucune base de données ni volume n e


seront nécessaires.
N ous utiliserons Gracile pour « builder » n otre application. Il faut voir ce dernier
comme un interpréteur de fichiers décrivant comment con struire n ot re application
(au même titre que make ou M aven). Le fi chier principal se n omme par con vention
[Link] et indiq uera :
• que n otre application repose sur le framework SpringMVC ;
• qu'elle do it être comp ilée en Java ;
• que le résultat de la comp ilation doit être embarqué dan s un serveur d'applica-
tion SpringBoot ;
"'Cl • qu'une image Docker doit être construite afin de pouvoir démarrer notre serveur
0
c
:::i
~
,., d'application qui, lui-même, exécute l'application Java.
"O
0 [Link];
\.0
.-t ~ Ainsi, en interprétant ce fameux fichier Gracile, n ous auron s en entrée le code
0 V
N V
'ii source Java et des fichiers de configuration , et en sortie un e image Docker. Cette
@ ·c
....... B dernière repose sur un fich ier Dockerfile.
:::;
..c CO
O'l c
0 Regardons un peu plus en détail ces deux fichiers.
ï::::: c
>-
o. c
u
0 ·3ù
:::;
"O
0
....
c.
~
~
:::;
rS
1
"O
0
c
8 1. [Link] g. io/guides/gs/serving-web-content/
(Ç) 2. h t tp://[Link]. io/spring-boot/
J2s4I ------------------ Chapitre 10. Intégration continue avec Docker

Le fichier [Link]
Ce fichier contient, tout d'abord, les librairies à utiliser : SpringBoot (qui inclut
également le framework SpingMVC ) et GradleDockerPlugin qui perme t d'appeler
une API Docker distant :

bui ldscript {
repos i tories
mavenCentral ()

dependenc ies f

cl asspath("org .spring framework .boot : spring-boot-grad l e-pl ug i n: l .3.3. RELEASE ")


cl asspa t h("com .bmuschko :grad l e-doc ker -plugin :2.6.7")

Ensuite, nous listons les actions à effectuer: compiler le code Java, mettre en place
le serveur d'application SpringBoot et utiliser l'API Docker distant :

appl y pl ugi n: 'java'


appl y pl ugi n: 'spring-boot'
1 ap ply pl ugin : 'com . bmusc [Link]-remote-api'

A fin de simplifier la lecture, nous ajoutons des « import » utiles aux tâches Gradle
ci~dessous :

import com . bmusch [Link] . doc ker . tas ks . image . Docker f i l e


1 import com . bmusch [Link] . doc ker . tas ks . image . DockerBui l dlmage

Nous créons un argument qui devra être donné lo rsque le script Gradle sera
invoqué. Cet argument décrit la version de l'application (par exemple, master ou
alors le numéro d'une version) :
"'Cl
0
c::
:::i
0
\.0
1 def appVersion = project . get Property( "appVersion" )
.-t
0
N
N ous indiquons le nom du jar souhaité pour la compilation Java. N ous omettons
@
....... volontairement la version , car celle~ci sera traitée au niveau de l'image Docker :
..c::
O'l
ï:::::
>-
0..
0 jar
u baseName "hellowor l d"
1
N ous spécifions la version de Java à utiliser :

sourceCompat i bi l i ty 1 .8
1 targetCompa t i bi l ity 1 .8
10. 1 Avant de commencer - - - - - - - - - - - - - - - - - - - - - - - - - - l2ssl
N ous ajoutons les librairies ut iles au démarrage du serveur d'application SpringBoot
(pour l'en v ironnement de développement):

repositories {
mavenCentral ()

dependencies {
compil e("[Link] ramework . boot : spr i ng-boot-starter -thyme l eaf ")
compile( "org .spri ng f ramework . boot : spr i ng- boot -devtoo ls "J

N ous donnons l'adresse de l'A PI Docker distant (nous verrons plus tard comment
démarrer le conteneur exposan t cette A PI) :

docker {
url = ' http : //doc ker -api :2375 '
1
Nous créons un e tâche qui va simplement copier le fichier Dockerfile au niveau
du répertoire contenant le résultat de la compilation Java. Il s'agit ici de simplifier les
chemins dans le Dockerfile :

task copyTask(type : Copy) (


from 'src/main /reso urces/docker/Doc kerf il e'
int o 'buil d/l i bs '
1
Pour finir, n ous créons une tâche qui va construire l'application et l'image Docker
à partir du Dockerfile :

task buildimage( type : DockerBuil dimage)


dependsün build, copyTask
in putD i r = f i le( 'bui l d/libs ')
"'Cl
t ag = "hellowo rld :" + appVersion
0
c::
:::i
~
,.,
"O
0 [Link];
\.0
.-t ~
Le fichier Dockerfile
0 V
N V
'& Le fich ier Dockerfile décrit comment construire l'image de notre application . C e
@ ·c
....... B
:::; fichier sera ut ilisé par le fic hie r [Link] ;
..c:: CO
O'l c
ï:::::
>-
0
c L'image sera basée sur un CentOS 7 :
o.. c
u
0 ·3ù
:::;
"O
0
....
c.
1 FROM centos :7
~
~
:::;
Nous installons Java 8 afin de pouvoir démarrer l'applicat ion :
rS
1
"O
0
c RUN yum -y i nsta l l wget
8 RUN wget --no-cookies - -no-check-cer tifi cate --header "Cook i e:
(Ç) 1 oracle license=accept-sec urebac kup-cooki e"
J2s6I------------------ Chapitre 10. Intégration continue avec Docker

"http: //downl oad .orac l e. com/otn -pu b/jav a/ j dk/8u77 -b03/ j re -8u77-li nux -x64 . rpm"
-0 / t mp/jdk-8-lin ux -x64. rpm
RUN yum -y ins t al l /tmp/jd k-8-l inux -[Link]
1 ENV JAVA_HOM E /usr/ j av a/l atest

Pour finir, nous copions et démarrons l'application :

RUN mkdir /opt/ he l l oworl d


COPY hel lowor l d.j ar / opt / hellowo rld/
1 ENTRYPO INT [" java ", "-ja r ", "/opt/ hel l oworld/ he ll oworld . jar "J

Notons que l'application est conditionnée sous la forme d'un JAR unique qui inclut
le serveur d'application SpringBoot.

-
10.2 LA PREPARATION DES CONTENEURS
Dans cette section nous allons mettre en place les conteneurs nécessaires à notre
système d'intégration continue. Comme nous l'avons vu précédemment, nous aurons
besoin de quatre conteneurs :
1. GitLab;
2. Jenkins;
3. Docker A PI ;
4. environnement de développement.

10.2.1 Prérequis

Avant tout, nous avons besoin de configurer un réseau afin que nos conteneurs puissent
communiquer les uns avec les autres. Pour cela, nous créons un réseau de type bridge
"'Cl
0
dont le nom est my_ci:
c::
:::i
0
\.0
.-t
1 $ docker network crea te -d bri dge my_ci
0
N
@
....... 10.2.2 Le conteneur dépôt de code Gitlab
..c::
O'l
·;::
>-
0..
Nous utiliserons Git avec GitLab comme outil de gestion de code source. Ce dernier
0 étant très courant, une image Docker existe déjà sur le Docker Hub, et il nous suffit
u
de la démarrer :

$ docker r un -- detach
--net my_ci \
--hostname git l ab \
-p 8180 :80 -p 8122 :22 \
- -name gitl ab \
10.2 Lo préparation des conteneurs ---------------------12571
-- rest art al ways \
-- vol ume /home/vagrant/vo l umes/gi t la b/confi g: /et c/gi t la b \
--vol ume /home/vag rant/vo l umes/gi t l ab/ l ogs : /var/ l og/g i tlab
-- vol ume /home/vagrant/vol umes/gi t l ab/dat a : /var/opt/g i t l ab
gi t la b/git l ab- ce :8 .5.8-ce .O

Il est également possible de mapper le port 443 afin d'accéder à Gitlab via HTIPS;
nous avons volontairement omis ce mappage car nous ne l'utiliserons pas dans notre
exemple et nous souhaitons éviter les tracas liés à la gestion des certificats SSL.

N ous remarquo ns que trois volumes sont nécessaires :


• config : pour stocker la configuration de GitLab, par exemple les utilisateurs ;
• logs : pour stocker les logs ;
• data: pour stocker les données applicatives, c'est~à~dire les dépôts G it.

La création de volumes permet de mettre à jour GitLab avec une nouvelle image
sans perdre les données.
A près le démarrage du conteneur, nous devons configurer l'URL de G itLab ainsi
que le timeout pour l'exécution des webhooks (car la valeur par défaut est trop faible
pour notre CI). Pour cela, nous ouvrons un terminal sur le conteneur ainsi lancé :

1 $ docker exec -i t gitl ab /bi n/bas h

Puis n o us édito n s le fichier /etc/gidah/[Link] ~ l':::iide , p:::ir exe mple , d e l'11tilit:::iire


V l:

1 root@g i tla b: /# vi /etc/gitlab/g it l ab . rb

Nous pouvons alors ajouter les lignes suivantes :

"'Cl
0
c:: ~
,., ## Latest optio ns l isted at htt ps : //g i tlab . com/gi t l ab-org/omnibus -
:::i
0 "O gi tl ab/ blob/master /fi les/g i t l ab -confi g-temp l at e/gi t l ab . rb . template
[Link];
\.0
.-t ~
0 V fffl Ur 1 on whi ch Git Lab wi 11 be r eac hab1e .
V
N
'& ##For more det ai l s on conf i guri ng ext ern al_url see :
@ ·c
B ## ht tps : //gi t lab .com/git l ab -org/omn i bus-
....... :::;
..c:: CO gi t l ab/blob/629def0a7a26e7c2326566f0758d4a27857b 52a3/README .md#configuring -t he -
O'l c
ï::::: 0
c exter na l -url -for -gi t l ab
>- c ff ext erna l_ur l 'G ENERATEO_EXT ERNAL_URL' ff default : htt p: / /hostname
o..
u
0 ·3ù externa l _url 'http: //gitlab: 8180'
:::;
"O
0
gitl ab_rail s['webhook_t i meout' ] = 30
....
c.
~
~ ##Note : conf ig ura t i on set ti ngs be l ow are optiona l.
:::;
rS ## Uncomment and change t he va l ue .
"O
1 #ff#ffffffff#ff#######/f#/l####/f####
0
c # git l ab. yml confi guration ff
8 ####ff#fffffl#ffflffffflffff#lllf#ll#flll##ll
(Ç)
J2ssl------------------ Chapitre 10. Intégration continue avec Docker

N ous pouvons terminer la connexion avec le conteneur en entrant simplement la


commande exit :

1 root@gitlab : /# ex i t

Notons que puisque le dossier /etc/gidab du conteneur est un volume monté sur un
répertoire de notre hôte, nous aurions aussi pu faire cette modification directement
depuis l'hôte. Néanmoins nous aurions dû prendre garde aux problèmes de droits
que nous avons déjà évoqués dans le chapitre 9. Le résultat est , quoi qu'il en soit,
identique.

Finalement, nous devons redémarrer le conteneur pour qu'il prenne en compte ces
modifications :

1 $docker restart git la b

10.2.3 Le conteneur d'intégration continue Jenkins

Nous utiliserons Jenkins comme outil d'intégration continue. Tout comme pour
G itLab, une image standard du Docker Hub, prête à l'emplo i, peut être utilisée.
Dé marrons un conteneur :

$ docker r un --detach
-- net my_c i \
-- hostname j enk i ns \
-u root \
-p 8080 :8080 -p 50000 : 50000 \
-- name jenk ins \
--volume /home/vagrant/volumes/ j enk in s : /var/jenki ns_home \
jenk i nsci/jenk i ns:2 . 0-beta -l
-0
0
c::
::i Comme nous pouvons le voir dans la dernière ligne ci-dessus, nous utilisons
0
\.0
une version beta de Jenkins. N ous avons fait ce cho ix afin de présen ter la dernière
.-t
0 mon ture de Jenkins qui sera tout prochainement disponible. Il est évident que pour
N
@ une vraie application ce ch o ix ne serait pas judicieux, néanmo ins cela ne porte pas à
.......
..c:: conséquence pour notre exemple .
O'l
ï:::::
>-
0..
u
0 10.2.4 Le conteneur d'API Docker distant Docker API

L'API Docker représente un Docker dans Docker. Ici aussi, une image est déjà
existante ; démarrons-la :

docker run -- det ac h \


- -net my_c i \
1 --hostname docker-api \
10.2 Lo préparation des conteneurs ----------------------12591
-- pr i vi l eged \
- -name docker-a pi \
1 doc ker : l .1 0-di nd

- -pr i vi l eged est nécessaire pour qu'un Docker dans Docker fonctionne correc-
tement, cependant il est important de comprendre que cette option donne un accès
complet à l'hôte, si bien qu'elle doit être utilisée avec une grande précaution .

10.2.5 Les conteneurs d'environnement de développement

Pour notre environnemen t de développement nous avons beso in de deux conteneurs :


le premier pour tester les développements réalisés, et le second pour le vo lume (où
sera le code source).
Commençons par l'environnement qui permettra de tester les développements.
Nous avon s besoin de Java pour compiler le code et de Gracile pour déployer
localement l'application. A insi, nous utilisons le Dockerfile (Dockerfile_deven v)
suivant:

FROM centos :7

RUN yum -y install 111get unzip

RUN wget -- no-cooki es -- no -chec k-ce r tifi cate -- header "Cook i e:


oraclel i cense=accept -securebackup -cookie "
"htt p: //downl oad . oracle . com/otn-pub/java/jdk/8u//-b03/jdk-8u//- l inux-x64. r pm"
-0 /tmp/ j dk-8- l inux -x64 . rpm
RUN yum -y i nst al l /tmp / j dk-8-l i nux -x64 . rpm
ENV JAVA_HOME /us r / j ava/ l at es t

RUN wget -N https : //services . gradle . or g/d i stributions/gradl e-2 .1 2-a l l . zi p


RUN mkd i r /opt/ gradl e
RUN unz i p gradle -2. 12-all . zip -d /o pt/gradle
"'Cl RUN l n -s fn /opt/g r ad l e/grad l e-2. 12 /opt/gradl e/latest
0
c:: ~
,., ENV GRADLE_HOME /opt / gradl e/ lat est
:::i
"O
0 [Link];
\.0 WORKD IR /v ar/hel lo-world
.-t ~
0 V
V
N
'& ENTRYPOINT [ "/opt/grad l e/latest/bin/gradle ". "cl ean " , "bootRun " ,
@ ·c
B "-PappVersion=master "J
....... :::;
..c:: CO
O'l c
0
ï::::: c
>- c
o.. Le dernier paramètre du ENTRYPOINT (-PappVers i on=master) ne sera, dans notre
u
0 ·3ù
:::;
"O
cas, pas employé, car nous utiliserons le code présent dans le volume. N éanmoins, ce
0
.... paramètre est obligatoire, aussi l'avons-nous ajouté avec la valeur arbitraire master.
c.
~
~
:::;
rS C onstruisons mainten ant l'image ainsi spécifiée :
1
"O
0
c
8
(Ç)
1 $ docker build -t devenv .
J26ol------------------ Chapitre 10. Intégration continue avec Docker

Continuons avec le volume : nous utilisons pour cela le Dockerfile (Docker,


file_devenv,volume ) suivant qui permet de spécifier un data container, c'est;à;dire un
con teneur dont la seule raiso n d'être est de garder un lien sur un volume :

FROM busybox :gl ibc


1 VOLUME /var/ hel lo- wor l d
N ous pouvons construire l'image :

1 $ doc ker bui l d -t devenv-vo lume .

C réons maintenant un conteneur pour notre volume :

$ doc ker crea t e -v /home/vagrant /vol umes / devenv/he l lo -wor l d/ : /var/hel l o-world/
1 -- name=devenv-vol ume devenv -vo l ume

Nous lierons n otre volume à notre en vironnement de développemen t lors du


démarrage de ce dernier, cette étape sera faite ultérieurement. A insi, n otre en viron;
nemen t est prêt. Nous verrons par la suite comment l'utiliser, et n ous commencerons
no tamment par cloner le code base depuis Gitlab (qui lui; même contiendra un fork
d 'un projet GitHub) dans /h ome/vagrant/volumes/deven v/hello;world.

10.2.6 Mise à iour du fichier I etc/hosts sur notre machine hôte


Notre réseau Docker est déjà en place. Regardons sa composition :

$ docker network i nspect my_c i


[

"Name ": "my_ci ".


" Id" :
"'Cl "b29cüed96b3e l 867eacb4f 7d2e9f2 77 l e4193de967f53a2b8cd236429ec39868 " ,
0
c:: "Scope": "l ocal ",
:::i
0 "Dr i ver ": "bri dge ",
\.0 " I PAM" : (
.-t
0 "Driver ": "de f aul t",
N "Opt i ons ": null .
@ "Con fi g": [
.......
..c:: {
O'l
ï::::: "Su bnet ": "172 .18.0.0/ 16",
>-
0.. "Gateway": "172 . 18 . 0 .1/16 "
0
u
}'
"Conta i ners ": {
"652792cüaüd4a f 5baf99f92cd28cb55c63ada4a9cf683d62a86c9eeclfa5fd l d":

"Name ": "j enkin s ",


"Endpo i ntID ":
"Ob710a84dceefbbc64dlf9a2f 9f92975e693ecf1903d33597dac3a4237cab51c " ,
10.2 Lo préparation des conteneurs ----------------------12611
"MacAddress " : "[Link] : l2 : 00 :03" ,
"IPv4Address ": "172. 18.0 . 3/16".
"I Pv6Address ": ""
l.
"6e2c6048defa78la97ab55f3a9878b3fdc8a00438854652de5 l f400a f6bl045 0":

"Name " : "docker-api " .


"End po int !D" :
"22ac569a88b7189f04d26e7d8f575b5c59daa46d0f6 l ca70e3fb0bacf3db44d8" ,
"MacAddress" : "02 :42 : ac : l 2: 00 :04 " ,
"IPv4Address ": "172 . 18 . 0.4/16 ",
"I Pv6Address ": '"'
} .
"b222b70940d6476a9da57 32fl df7aa6fd0224886 597c5926090ee5d 56529 l l lf ":

"Name " : "g itlab ".


"End po int !D" :
"8b83b7afaldb47cl912bfa23adce76e46fl da565cl45dlfüf4a aeabbb6eeec66 ".
"MacAddress " : "02 :42 : ac : l2 : 00 :02 ",
"IPv4Address ": "172. 18 . 0. 2/16",
"IPv6Address ": ""

} .
"Options " : {}

Docker a automat iquement configuré tous les conteneurs afin qu'ils se connaissent
les uns les autres. Toutefois, ce n'est pas le cas de notre mach ine h ôte. Celui~ci peut
accéder aux conteneurs par l'intermédiaire de leur adresse IP, mais nous préféron s
permettre un appel via un nom de domaine.
N ous allons donc modifier la configuration de n otre hôte à cet effet :

1 $ sudo vi /etc/hasts

"'Cl
0 Nous ajoutons les lignes suivantes (en fin de fichier) :
c::
:::i
~
,.,
"O
0 [Link];
\.0
.-t
0
~
V
17 2. 18. 0. 3 jenk i ns
N V
'& 172 . 18 . 0. 4 docker -api
@
.......
·c
B
:::;
1 17 2. 18 . 0.2 gi t l ab
..c:: CO
O'l c
0
ï::::: c
>- c
o.. Attention, il convient de vérifier les IP en fonction des conteneurs (celles-ci étant
u
0 ·3ù
:::;
"O
allouées dynamiquement par Docker) selon le résultat de la commande docker
0
....
c. networ k ins pect my_ci .
~
~
:::;
rS Nous pouvons maintenant tester que l'A PI Docker fonctionne correctement:
1
"O
0
c
8
(Ç)
1 $ cur l http : //docker -api : 2375/images/json
J262I------------------ Chapitre 10. Intégration continue avec Docker

10.3 CONFIGURATION DE NOTRE Cl


10.3.1 Initialiser Gitlab pour l'application HelloWorld

La première étape est de récupérer le code de l'application depuis GitHub. Pour cela,
nous commençons par initialiser GitLab.
Depuis un navigateur, allez à l'adresse suivante :

1 http ://gitl ab :8180

Et connectez-vous avec l'utilisateur suivant:


• Nom d' utilisateur : root
• Mot de passe: SiveUfe

Après la première connexion, GitLab nous propose de changer de mot de passe


root, et nous utiliserons arbitraireme nt un mot de passe simple : rootl 234. Après la
modification, nous devons nous reconnecter.
Créons maintenant notre projet hello-wo rld (figure 10.2) :
1. C liquez sur New project.
2. Sous Project path, saisissez « hello-world ».

3. Pour Import project from, choisissez Any repo by URL.


4. Sous Git repository URL, saisissez [Link]
git.
5. Pour Visibility Level, choisissez Public.
6. C liquez sur Create Project.

10.3.2 Testons l'application


"'Cl
0
c
:::i Nous pouvons maintenant tester l'application localement. Pour cela, nous allons
0
\.0
utiliser notre environnement de développement.
.-t
0
N Commençons par cloner le code depuis GitLab :
@
.......
..c
sudo mkdir -p / home/vagran t/vol umes / devenv

i
O'l
'i:
>- sudo chown vagra nt: vagran t /home/vagrant/volumes/devenv
0.
0 cd / home/vagrant/volumes /dev env
u 1 gi t clone htt p: //g it l ab :8180/root/hel lo -wor l d.g it

Nous pouvons maintenant démarrer notre conteneur d'environnement de déve-


loppement en l'attachant au volume deven v-volume :

$ docker run -- rm -p 8090 :8090 --v ol umes -f rom=devenv -vo l ume --name=devenv
1 devenv
10.3 Configuration de notre Cl ----------------------------12631
NewProject

Project path httpo//gitlab,8180/ root .. / hello-worid

Want to hou se several depende nt p<OJKts u nder th@ sa me na~ce? Create a group

Import project from (") GitHub fi Bitbucket • [Link] [Link]'g G Google Code A l=ogbugz git Any repo by URL

Git [Link] URL https.://[Link]/docker--ecosysteme/hello-world.g1t

• Therepositorymustbeaccessibteover http ~ //, https :// or git://.


• If your HTIP re~tory is not publicly accessibte, add authentication information to the URL: https : / /usernarne: password~itlab, COtl'flany, co111
/group/[Link].
• The import witl timeout after 15 [Link]. For repositorie$ tl'lat takelonger, use a clone/push combination.
• To migra le an SVN repository, check out thisdocument

Description (optional)

Visibility Level(?) V Q Pfivate


Project access mu~ be granted explicitly to each user.

0 '(J Internai
The projed can becloned by any logged in user.

S ~ PubUc
The proJect can becloned without any authentication.

1§1§@• Cancel

Figure 10.2 - Configuration de Gitl ab

Notre application est maintenant directement disponible à l'adresse


[Link] ?name=John.
Po llf finir, ;:irrê ton s le conten ellf (é rnnt d onné l'optio n - - rm p;:issée m1 d ém;:irrnge
du conteneur, ce dernier sera également supprimé ) :

1 $ docker stop devenv

L'avantage d'une telle approche est évident: il n 'est pas nécessaire d'avoir à
installer sur notre poste de travail G racile ou Java, ces derniers étant fournis par n otre
"'Cl
0
conteneur de développement.
c
:::i
~
,.,
"O
0 [Link];
\.0
.-t ~
10.3.3 Configuration de Jenkins
0 V
N V
'ii
@ ·c N ous allons mainten ant configurer Jenkins, notamment les plugins à utiliser et la
....... B
..c
:::;
CO gestion des permissions.
O'l c
0
ï::::: c
>-
o. c
0 ·3ù Installation des plugins et création de /'utilisateur admin
u :::;
"O
0
.... Depuis un navigateur, allons à l'adresse suivan te :
c.
~
~
:::;
rS 1 htt p: //jenki ns :8080/
1
"O
0
c L'écran suivant est affi ché :
8
(Ç)
Chapitre 1O. Intégration continue avec Docker

Getting Started

Unlock Jenkins
To ensure Jenkins is securely set up by the administrator, a password has been
generated and written to the file on the Jenkins server here:
Ivar /jenk ins_home/sec rets/1n1 t ialAdminPasswo rd

Please copy the password and paste it below.


Administrator [Link]

Figure 10.3 - Premier démarrage de Jenkins


-
Nous devons saisir le mot de passe d'administration qui a été créé par défaut lors
du démarrage du conteneur. Ce mot de passe ayant été sauvegardé dans un fi chier,
affichons ce dernier :

$ sudo ca t /home/vag rant /vo l umes/jen ki ns/secrets/ ini tialAdmi nPa ssword
1 e5f 5c2489a454e229f7 l f019494 fbc49
Dans notre cas, le mot de passe est « e5f5c2489a4 54e229f7lf019494fbc49 » , et il
suffit de le saisir dans l'écran, puis de cliquer sur Continue.
Le système nous demande ensuite le type d'installation que nous souhaitons.
Nous choisissons lnstall suggested plugins, en cliquant simplement sur le bouton
correspondant :

"'Cl Getting Started X


0
c::
::i
0
\.0
.-t
Customize Jenkins
0 Plug1ns extend Jenki ns with add1tional features to support many d1fferent needs.
N
@
....... lnstall suggested 1 Select plugins to
..c:: plugins install
O'l
ï:::::
>-
0.. lnstall plugins the Jenkins Select and install plugins
0 communityfmds most most suitable for your needs.
u useful

1 J

Figure 10.4 - Installation des plugins Jenkins


10.3 Configuration de notre Cl -------------------------12651
L'installation des plugins est alors effectuée, cette opération pouvant durer quelques
minutes.
À la fin de l'installation, le système nous demande de créer un premier utilisateur ;
nous utiliserons :
• N om d'utilisateur: admin
• Mot de passe : adminl234
• N om: A dministrateur
• Email : votre adresse email

Connectons~nous à Jenkins avec les informations saisies ci~dessus.

Installation de Gradle
A fin de pouvo ir construire notre application , nous devons configurer Gradle :
1. C liquez sur Administrer Jenkins (dans le menu à gauche).
2. Cliq uez sur Global Tool Configuration.
3. Descendez dans la page au niveau du titre Gradle.
4. C liquez sur Add Gradle.
5. Sous Name, saisissez« Grad le 2.12 ».

6. Cochez lnstall automatically.


7 . S o us Version, saisissez 2.12 » (il se p eut éga lem e nt qu' il s'agisse d'une list e
«

déroulante, dans ce cas choisissez Gradle 2 .12).

Gradle

Installations Gradle Gradle


name Gradle 2.12

~ lnstall automatlcally

"'Cl lnstall from [Link]


0
c::
:::i
~
,., Version Gradle 2 12

"O Suppmner 1111 111sti\llF1te11r


0 [Link];
\.0
.-t ~ Ajouter un installateur ....
0 V
N
@
V
'&
·c MHH!ii'*
....... B
:::;
AjouterGradte

..c:: CO tlomb1• d'il'[Link] G1dl1 1ur u 1)'1tim1


O'l c
0
ï::::: c
>- c
o.. Figure 10.5 - Configuration des jobs Jenkins
u
0 ·3ù
:::;
"O
0
....
c.
~ 8. C liquez sur Save (en bas de page).
~
:::;
rS 9. Retournez dans l'administration Jenkins et choisissez Gestion des plugins.
1
"O
0
c 10. Cliquez sur l'onglet Avancé.
8 11. Tout en bas, cliquez sur V érifier maintenant.
(Ç)
Chapitre 1O. Intégration continue avec Docker

Création de /'utilisateur git/ab


Nous allons maintenant ajouter un utilisateur gitlab afin que ce dernier puisse exécuter
des builds automatiques (grâce à un webhook que nous configurerons dans le prochain
chapitre) :
1. Cliquez sur Administrer ]enkins.
2. Cliquez sur Gérer les utilisateurs.
3. Cliquez sur Créer un utilisateur, et saisissez les informations suivantes :
Nom d'utilisateur: gitlab
Mot de passe: gitlab l234
Nom complet: GitLab
Adresse courriel : une adresse email de votre choix

Créer un utilisateur
Nom d'utilisateur: gitlab

Mot de passe:

Confirmation du mot de passe: ••••••••••

Nom complet: Gitlab


Adresse courriel: me@[Link]

Creer un ut1hs"'teu1

Figure 10.6 - Création d'un utilisateur Gitlab

4. C liquez sur Créer un utilisateur.

Assignation des permissions


Pour finir, nous configurons la gestion des permissions Jenkins:
"'Cl
0 1. Cliquez sur Administrer Jenkins.
c::
::i
0 2. Cliquez sur Configurer la sécurité globale.
\.0
.-t
0
3. Sous Contrôle de l'accès/Autorisations, sélectionnez Stratégie d'authorisation matri~
N
cielle basée sur les projets.
@
....... Sous Utilisateur/group à ajouter, saisissez « admin », cliquez sur Ajouter, puis
..c::
O'l
ï:::::
cochez toutes les cases.
>-
0.. Sous Utilisateur/group à ajouter, saisissez « gid ab », cliquez sur Ajouter, puis
0
u cochez Read sous Global.
4. Plus bas, décochez l'option Se protéger contre les exploits de type Cross Site Request
Forgery.
5. C liquez finalement sur Enregistrer.
6. Nous avons maintenant tout ce qu'il nous faut pour passer à la création des
différents jobs nécessaire à la Cl.
10.3 Configuration de notre Cl ----------------------------12671
[Link]

0 Les utilisateurs connectés peuvent tout faire

0 Mode legacy

0 Stratégie d'authorisation matricielle basée sur les projets

Global Credentials Agent

Utilisateur/groupe

AdministerConfigureUpdateCenterReadRunScriptsUploadPluginsCreateDeleteManageOomainsUpdateViewBuildConfigureConnectCreateOel•
a admin li!' li!' l>I!/ l>I!/ li!' li!' li!' li!' li!' li!' li! li!' li!' l>I!/
a gitlab 0 D li! D 0 0 0 D 0 0 D D D 0 C
Anonyme 0 D D D 0 0 0 0 0 0 D 0 0 0 c

Figure 10.7 - Configuration des droits sur les jobs Jenkins

10.3.4 Création des iobs Jenkins et Web Hook

N ous allons mainten ant préparer les trois jobs décrits précédemment: celui pour
la construction de l'image et ceux traitant du déplo iement de l'application (sous la
forme de conteneurs) pour l'environnement de test et celui de production. Nous
créerons également le webhook dans GitLab qui déclenchera le build et le déploiement
automatiques sur l'environnement de test.

Le job Build
Nous créons dans Jenkins le job qui construira notre application:
1. C liquez dans le menu à gauche sur Nouveau Item (sic).
2. Sous New item name... , saisissez« hello~world » .

3. Choisissez Construire un projet free~style.


4. C liquez sur OK.
5. Pour l'onglet General:
Cochez Activer la sécurité basée projet.
"'Cl
Sous Utilisateur/groupe à ajouter, saisissez « gitlab » et cliquez sur Ajouter, puis
0
c:: coch ez Build et Read sous Job.
:::i
0
\.0
.-t ~Activer la sécurité basée projet
0
N 0 Block 1nhentance of global authonzat1on matnx

@ Credent1als Job Historique des Gestion de

....... Utihsateur/groupe bu1lds version


..c:: CreateDeleteManageOomainsUpdateViewBuildCancelConfigureDeleteOiscoverMoveReadWorkspace Delete Updar:e Tag
O'l
·;:: i grtlab u Cl CJU ~ Cl Cl .,,, Cl Cl
>-
0..
Anonyme [J u ü Cl u u [J lJ u
0
u Uullsateur/groupe â ajouter:
Ajouter

Figure 10.8 - Configuration du job de build

Plus bas, cochez Ce build a des paramètres, et créez deux paramètres de type
Paramètre String :
Nom: appVersion ; Valeur par défaut: master
N om: gitPath ; Valeur par défaut : *
Chapitre 1O. Intégration continue avec Docker

>iif Ce build a des paramètres

Param ètre St ring

Nom appVersion

Valeur par défaut master

Description

(Plain text) Prévisualisation

Param ètre String

Nom gitPath

Valeur par défaut •

Description

(Plain text) Prévisualisation

Ffli!lllE Apply Ali


Ajouter un paramètre •

Figure 10.9 - Configuration du job de build

Ces deux paramètres nous permettront de définir la bran ch e ou le tag dans


GitLab à utiliser comme base code. Par défaut, il s'agit de la branche master.
6. Pour l'onglet Gestion de code source, ch oisissez G it et remplissez avec les
informations suivantes :
Repository URL : [Link] l 80/root/hello,[Link]
Branch Specifier (blank for 'an y') : $gitPath/$appVersion

Gestion de code source

0 Aucune

8 Git

Repositories
"'Cl Repository URL [Link]
0
c
0
:::i Credentials . none . .:J .. Add

..
\.0
.-t Avancé ...
0
N Add Reposltory
@
.......
..c Branches to build
O'l Branch Specrtier (blank for 'any') $gitPath/$appVersion
'i:
>-
0. Add Branch
0
u
Navigateur de la base de code (Auto)

Additional Behaviours Ajouter •

Q [Link]

Figure 10.1 0 - Paramétrage du lien avec le repository Git


10.3 Configuration de notre Cl ---------------------------12691
7. Pour l'onglet Ce qui déclenche le build, cochez Déclencher les builds à distance (Par
exemple , à partir de scripts).
Sous Jeton d'authentification, saisir « abcdef » .

Ce qui déclenche le build

~Déclencher les builds à distance (Par exemple, à partir de scripts)

Jeton d'authentification abcdef


Utilisez l'URL qui suit pour lancer un build à distance : JENKI NS_URL/job/hello·world/build?toKen=TOKEN_NAME ou
/buildWithParameters?toKen=TOKEN_NAME
Optionnellement , ajoute le suffixe &cause=Cause+Tex t pour fournir du texte qui sera inclu dans la cause
enregistrée pour le build.

0 Construire après le bulld sur d'autres projets

0 Construire périodiquement

D Build when a change is pushed to GitHub

0 Scrutation de l'outil de gestion de version

Figure 10. 11 - Configuration du WebHook

Nous avons choisi volontairement un jeton très simple, ce dernier devant


être donné comme paramètre lors de la création du webhook. Il convient
logiquement de choisir une valeur complexe dans un vrai environnement.
8. Pour l'onglet Build ([Link] 10.1 2):
C liquez sur Ajouter une étape au build et choisissez Invoke Gradle script, puis
Invoke Gradle.
Pour G radle V ersion , choisissez G radle 2 .12 .
Sous Tasks, saisissez:

cl ean
bui ld lma ge
1 -PappVersion=$ appVersion

"'Cl
0 cl ea n permet de nettoyer le résultat d'une précédente exécution G radle,
c:: ~
,.,
:::i
"O
bui l dimage exécute la tâche du même nom présente dans le [Link] de [Link]~
0 [Link];
\.0 ration Gradle, et - PappVe r s i on=$ap pVers i on permet de spécifier la version de
.-t ~
0 V
V
l'image Docker qu i sera créée ; logiquement, cette dernière est alignée avec la
N
'& branche ou le tag (pour une release) utilisés dans GitLab.
@ ·c
....... B
:::;
..c:: CO
9. C liquez sur Sauver (en bas de page) .
O'l c
0
ï::::: c
>- c
o..
u
0 ·3ù Le webhook dans Gitlab
:::;
"O
0
.... Le webhook dans GitLab permet le déclen chement automatique d'un build Jenkins
c.
~
~
:::;
après tout push dans G it. Sa création se fait ainsi :
rS 1. O uvrez le projet he llo~world dans G itLab.
1
"O
0
c 2. C liquez sur Edit project ([Link] 10.13 ).
8
(Ç) 3. Dans le menu de gauche, cliquez sur Web Hooks.
Chapitre 1O. Intégration continue avec Docker

Build

lnvoke Cr adle script

l.:J lnvoke Gradle

Gradle Version Gradle 2.12

0 Use Gradle W rapper

Build step description

Switches

Tasks clean
buildlmage
-PappVerslon=S appVerslon

Root Build script

Build File

Specify Gradle build 1ile to run. Also. some environment variables are available to the build
illiJ1!

to use workspace 0
BjiifiiE ~A_PP_'Y_AH~
Figure 10.12 - Définition du script de build <appel Gradle)

Edit Proiect

Leave Project

Figure 1O.1 3 - Édition du projet Gitlab

4. Sous URL, sa1s1ssez [Link] 1234@jenkins:8080/job/hello,world/


"'Cl
0
c
buildWithParameters ?token=abcdef&appVersion=master&gitPath = *.
:::i
0 Nous devons spécifier les paramètres du build (dans notre cas appVersion et
\.0
.-t
gitPath) ; dans notre exemple, il s'agit simplement de la branche master de
0
N GitLab car le webhook concerne l'environnement de test qui doit toujours
@ contenir la dernière version du code base.
.......
..c Vous pouvez également remarquer que nous devons spécifier un utilisateur et
O'l
ï:::::
>- un mot de passe dans l'URL. Nous avons logiquement choisi l'utilisateur gidab
o.
u
0 qui dispose de l'unique droit de build pour le job hello,world.
5. Pour Trigger, cochez uniquement Push events.
6. Pour SSL Verification, décochez Enable SSL verification.
7. Finalement, sauvez avec Add Web Hook.
10.3 Configuration de notre Cl - - - - - - - - - - - - - - - - - - - - - - - - - 1211 I
Nous allo ns tester que le Web H ook fonctionne correctement, et, pour cela, il
suffit de cliquer sur le bouton Test Hook e t de vérifier qu'un nouveau Build a bien eu
lieu dans Jenkins pour notre application hello,world et qu'il a fonctionné.
Le résultat devrait être similaire à celui,ci :

+ 11.t jenkins 8080/job/hello-world/

'8 Jenkins
Jenkins hello-world

• Retour au tableau de bord

État
Projet hello-world
:;;. Modifications

Répertoire de travail

§) Build with Parameters


Espace de travail
CS) Supprimer Projet
-(t Configurer
~j,.. Move
/i1' Changements récents

Liens permanents
Historique des builds tendance =
• Dernier build (#10) il y a J mn JO s
• Dernier build stable (#10) il y a J mn JO s
'~d ~ • Dernier build avec succès (#10) il y a J mn JO s
• Last completed build (#10) il y a J mn JO s
tt1 3 avr. 2016 11:21

~ RSS des builds ~ RSS des échecs

Figure 10.14 - Résultat d'un build dans Jenkins

-0
0
c:: Le job de déploiement de /'environnement de test Deploy test
::i
0
\.0 N ous créons ensuite dans Jenkins le job qui démarrera un conteneur pour notre
.-t
0
N
environnement de test. Pour rappel, ce conteneur sera localisé dans le conteneur
@ docker,api, et sera créé grâce à l'API Docker distant présente dans ce dernier:
.......
..c:: 1. C liquez dans le menu à gauche sur Nouveau Item (sic) .
O'l
·;::
>-
0.. 2. Sous New item name .. . , saisissez« deploy,test,hello,world ».
0
u
3. Choisissez Construire un projet free,style.
4. Cliquez sur OK.
5. Pour l'onglet Ce qui déclenche le build :
C liquez sur Construire après le build sur d'autres projets (afin de déployer automa,
tiquement l'environnement de test après tout push dans G itlab).
Sous Projet à surveiller, saisissez « hello,world ».
Chapitre 1O. Intégration continue avec Docker

Ce qui déclenche le build

0 Déclencher les builds à distance (Par exemple, à partir de scripts)

~Construire après le build sur d'autres projets

Projet à surveiller hello-world

0 Déclencher que si la construction est st able


O Déclencher même si la construction est Instable
O Déclencher même si la construction échoue
0 Construire périodiquement

0 Build when a change is pushed to GitHub

0 Scrutation de !"outil de gestion de version

Figure 1O.15 - Paramétrage du job de déploiement en test

6. Pour l'onglet Build:


Pour Ajouter une étape au build, choisissez Exécuter un script shell.
Sous Commande, saisissez :

#suppression du conten eur ex i st ant


curl -v -X POST -H "Content- Type : appl i cation/ j son "
ht t p://docke r -api : 2375/conta i ners/test-helloworld/stop
curl -v -X DE LETE http : //doc ker -api :2375 / conta i ne rs / t est -helloworld

# création et démarrage d1un no uvea u conteneur


curl -v -X POST -H "Cont ent-Type : application/json " -d
' {"Image ":" helloworl d:master ", "ExposedPort s" : { "8090/tcp": (} },
"Port Bind i ngs ": { "8090/tcp ": [ { "Host Port ": "8490 " }] l }'
ht tp ://docker- api :2375/conta i ners/create?name=t est -helloworld
curl -v -X POST -H "Content- Type : appl i cation/ j son "
ht tp ://docke r -api : 2375/conta i ners/test-he ll oworld/start

Notons que nous commençons par arrêter et supprimer le conteneur existant.


"'Cl Lors du premier déploiement, ce conteneur n'existe pas, et l'API Docker
0
c:: retournera des erreurs http 404, ce qui n'est pas gênant pour notre job.
:::i
0 Nous constatons également que nous utilisons la branche master (ou plutôt
\.0
.-t
0
l'image de version master) lors de la création du conteneur, car nous voulons
N
toujours déployer en test la dernière version de l'application.
@
.......
..c:: 7. C liquez sur Sauver (en bas de page) .
O'l
ï:::::
>-
0.. Il faut noter que ce conteneur utilise le fichier de propriétés par défaut de
0
u l'application (c'est-à-dire src/main/resources/[Link]) qui utilise le port
8090. Cette façon de faire est acceptable pour un seul environnement; cependant,
pour tout autre environnement il faudra utiliser un autre port (autrement dit un autre
fichier de propriétés), ce qui sera le cas pour l'en vironnement de production expliqué
ci-après.
10.3 Configuration de notre Cl ------------------------12731
Le job de déploiement de l'environnement de production Deploy prod
Notre en vironnement de production est très proche de celui de test, à l'exception des
points suivants :
• il n'est pas déployé automatiquement, autre ment dit il n'y aura pas de configu,
ration au niveau de ce qui déclenche le build ;
• n ous ne devons pas utiliser la branche master, ma is une release spécifique. Pour
cela nous ajouterons un paramètre au build afin de spécifier manuellem ent le
tag à utiliser ou, plus précisément, la version de l'image Docker issue du tag ;
• le fichier de propriétés que nous avons accepté d'utiliser pour l'environnement
de test n e devra pas être utilisé pour l'environnement de production, car il y
aurait un conflit de ports si bien que nous devrons le surcharger.

Les fichiers de propriétés


Nous créons tout d'abord un nouveau projet dans GitLab pour gérer les fichiers de
propriétés relatifs aux environnements (dans n otre cas la production uniquement).
Pour rappel, on utilise le fichier de propriétés par défaut pour l'environnement de test.

Ce genre de projet doit être protégé afin de limiter son accès aux personnes autorisées
car il pourrait contenir des données sensibles, telles que des mots de passe. Dans
notre cas, nous le laissons « Public » pour simplifier le processus.

Créons donc ce nouveau projet :


1. Dans GitLab, cliquez sur New project.
2. Sous Project path, saisissez « environnements».
3. Pour Visibility Level, choisissez Public.
4. Cliquez sur Create Project.

Ajoutons un fichier [Link] directement à la racine de ce n ouveau projet :


1. Cliquez sur l'icône « + » et choisissez New files.
"'Cl
0
c::
:::i
~
,., 2. Sous File name, saisissez« [Link] ».
"O
0 [Link];
\.0 3 . Saisissez le contenu suivant:
.-t ~
0 V
N V
'&
@
.......
..c::
·c
B
:::;
CO
1 server . port = 8091
O'l c
ï::::: 0
c 4 . C ommitez le fichier dans la branche master en n'oubliant pas de spécifier un
>- c
o.. message.
u
0 ·3ù
:::;
"O
0
.... Le job Jenkins
c.
~
~
:::;
1. Dans Jenkins, cliquez dans le menu à gauche sur Nouveau Item (sic).
rS 2. Sous New item name .. . , saisissez« deploy,prod,hello,world ».
1
"O
0
c 3. Choisissez Construire un projet free,style.
8
(Ç) 4. Cliquez sur OK.
Chapitre 1O. Intégration continue avec Docker

Administrator /environnements v

E
environnements Q

'O' Star

HTIP v http : / /gitlab: 8180/root/environnements . git

0 Newlssue

~ New merge request


The repository for this projec1
lfyou already havefilesyou can push them using com-

Olherwiseyou can start with -


V Newbranch

. . Newtag
Command line instructions

Figure 10.16 - Création d'un repo Git pour contenir les propriétés d'environnement

5. Pour l'onglet General :


Coch ez Ce build a des paramètres, et créez un paramètre de type Paramètre
String :
- N om : app Version ; Pas de valeur par défaut

Ce paramètre correspond à la version de l'image Docker à utiliser.


6. Pour l'onglet Build :
Pour Ajouter une étape au build, ch oisissez Exécuter un script shell.
Sous Commande, saisissez :

#suppression du conteneur existant


curl -v -X POST -H "Content-Type : appl ica tion/json "
"'Cl ht tp :// doc ker -api : 2375/conta i ners/prod- helloworl d/stop
0
c:: curl -v -X DEL ETE http : //doc ker -api :2375/contai ners/prod -he l l oworld
:::i
0
\.0 # réc upérat i on des fichiers de propriétés de puis gi t
.-t
0 rm -rf env iron nements
N rm -f env i ronnemen t s . tar
@ gi t cl one htt p: //gi t lab :8180/root /environnements .gi t
.......
..c:: tar -cvzf env i ro nnement s . t ar env i ro nnements
O'l
·;::
>-
0.. # création d' un nouvea u conteneur
0
u JSON_CO NTENT="{\ "Image\ ": \ "hell owor l d: S{appVersion l\ ", \ "Ent ry point\ ":
[\ "ja va\ ", \ "-j ar\", \ "/opt / hel l oworld/hel l owor l d. jar\ ",
\ "-- spr i ng . conf i g.l ocat i on=/o pt/he l loworld/en vi ronnemen t s/prod . properties\ "J,
\ "ExposedPorts\ ": { \ "8091/ t cp\ ": Il l , \ "Port Bindings\ ": { \ "8091/tcp\ ": [(
\ "HostPort\ ": \ "8491\ " }] l }"
curl -v -X POST -H "Content -Type : application/json " -d "$JSON_CONTENT"
http : //docker-a pi : 2375/con t ainers/create?name=prod- hel lowor l d

# aj out du fi chier de propriétés dans l e conteneur


10.4 L'exploitation de notre Cl ------------------------l21sl
curl -v -X PUT
http : //docker-api : 2375/cont ai ners/prod-he l l owor l d/arc hi ve?path=/opt/ hel l oworld
--upl oad-fi l e env i ronnement s .tar

# démar rage du conteneur


cur l -v -X POST -H "Con t ent -Type : appl i cation/json "
http : //docker-api : 237 5/ cont ai ners/prod - hel l oworl d/st art

Ce script va, en plus de créer et démarrer le conteneur pour l'environnement


de production, injecter les propriétés : pour cela, nous copions le fichier
[Link] dans le conteneur avant de le démarrer. Notons que nous faisons
cela grâce à une archive tar car l'API Docker ne permet une copie que par ce
biais-là.
Lors du démarrage du conteneur, nous spécifions le fichier de propriétés à utiliser.
Nous constatons également que nous utilisons la version de l'image spécifiée
par le paramètre appVersion.
7. Cliquez sur Sauver (en bas de page).

Cette fois-ci notre CI est prête ! Nous allons dans la prochaine section illustrer
son exploitation par un exemple.

10.4 L'EXPLOITATION DE NOTRE Cl


Dans les précédentes sections, nous avons mis en place la totalité des composants
utiles à notre CI, et nous pouvons enfin l'exploiter. Cette dernière section est un cas
d'utilisation réaliste du système mis en place.

10.4.1 Développement d'une nouvelle fonctionnalité

Un besoin métier a été exprimé: la couleur du « HelloWorld »ne doit plus être noire,
mais rouge. Un développeur est assigné et doit donc modifier le code de l'application,
"'Cl
0 le tester localement et « pusher » ses modifications.
c::
:::i
~
,.,
"O
0 [Link]; La modification demandée concerne la vue de l'application, soit le fichier suivant
\.0
.-t
0
~
V
(c'est-à-dire un fichier du volume devenv-volume):
N V
'&
@ ·c
B
....... :::; /home/vag rant /volumes/deve nv/he l l o-
..c::
O'l
ï:::::
>-
CO
c
0
c
c
1 worl d/src/mai n/resou rces/ t emplates/he ll o. ht ml
o..
u
0 ·3ù Ouvrons le fichier avec un éditeur de texte et modifions-le ainsi :
:::;
"O
0
....
c.
~
~ <!DOCTYPE HTM L>
:::;
rS <html xml ns :th= "http : //www . thyme l eaf .org ">
1 <head>
"O
0
c <t i tle>Getti ng Started : Serv i ng Web Cont en t </ ti tle>
8 <meta http -equiv= "Content -Type " content="text/ html: charset =UTF-8" !>
(Ç) <l head>
Chapitre 1O. Intégration continue avec Docker

<body>
<p st yl e="color: red ;" th : text= "' Hel l o, ' + $(name } + '' '" !>
<!body>
1 </ht ml >

N ous pouvons simplement tester n otre modification en démarrant notre conten eur
de développement :

1 $doc ker r un -- rm -p 8090 :8090 -- vo l umes -f rom devenv -vol ume -- name devenv
devenv

Ouvrons un n avigate ur à l'adresse suivante :

1 ht tp :// l oca lhost :8090/hell o? name=J ohn


Nous constatons que le texte est désormais en rouge. Nous pouvon s arrêter notre
e nvironnement de développe ment:

1 $ doc ker st op devenv


Publions la modification dan s le dépôt git :

$ cd / home/vagrant/volumes/devenv/he l lo- wor l d/


$ gi t add src/ma i n/resources/templa t es/hello . html
$ gi t commit -m"Text e en rouge"
1 $ gi t push or i gi n mas t er :master

Utilisez l'utilisateur suivant lorsque le système le demande :


• Nom d'utilisateur : root
• Mot de passe : rootl 234

"'Cl
Si lors d'une commande git l'erreur suivante s'affich e :
0
c::
:::i
0 *** Pl ease tel l me who you are .
\.0
.-t Run
0
N gi t config -- gl obal user .emai l "yo u@exarnpl e. com "
@ gi t config -- gl obal user . name "Your Narne "
.......
..c::
O'l
·;::
>-
0..
il faut alors spécifier votre nom e t adresse email grâce aux commandes suivantes :
0
u
$ gi t config -- globa l user .ema i l "you@exarnple . com "
1 $ gi t config -- globa l us er . name "Your Name "

N ous vous rappelon s que n ous avon s installé un webhook dans G itLab afin de
builder et déployer en test automatiquement no tre application après tout push.
Vérifion s que tout s'est bien déroulé dan s Jenkins:
10.4 L'exploitation de notre Cl ---------------------------12111
.. J enkins (Ï) Adm1111st1 at e 111 1se deconn ecter

Jenk..ins

Noweau Item !]'Ajouter une description

Ali +
Utilisateurs

~ Historique des constructions


s M Nom du proj et 1 Dernier succès Dernier échec Derni ère durée

(t Administrer Jenkîns deploV·prod-he!to-wgrtd S. 0 S. O. ND fi)


Cl Mes vues deploy-test-hel!o-world 5 mn 59 s · !11 S, 0 1mn11 s
~
~ Credentials 7mn Us-ru S . O. 1 mn 6 s R)
Icône:
File d'attente des constructio ns Légende ~ RSS pour tout ~ RSS de tous les échecs ~ RSS luste pour les dernières
.[Link]
compilatîons
File d'attente des constructions vide

État du l anceur de compl! atlons

1 Au repos
2 Au repos

Figure 10.17 - Résultat d'un build et d'un déploiement en test dans Jenkins

Les jobs hello-world (pour la construction) et deploy-test-h ello-world (pour le


déploiement) contiennent une pastille bleue, ce qui signifie que leur dernière exécu-
tion s'est bien déroulée. U n testeur peut désormais constater le résultat simplement
en atteignant l'URL suivan te depuis un navigateur :

1 http : //doc ker-api :8490/h el l o?name=John


10.4.2 Mise en production

Les tests applicatifs (dans notre cas, la vérification de la couleur rouge) sont positifs.
Une mise en production de l'application est désormais souhaitée. Pour cela, nous
devons « releaser » le code, et nous utiliserons un tag git pour y parvenir.

"'Cl Lors d'une mise en production, dans un mode d'intégration continue, il convient
0
c:: ~
,., d'avertir tous les développeurs de ne plus« pusher »de code dans la branche courante
:::i
0 "O
[Link];
<master dans notre cas) afin d'éviter toute altération du code avant la release.
\.0
.-t ~
0 V
N V Ouvrons le projet hello-world dans GitLab et cliquons sur « 0 tags » d ans le
'&
@ ·c panneau principal :
....... B
:::;
..c:: CO
O'l c
0
Créons un nouveau tag :
ï::::: c
>- c
o.. 1. C liquez sur New tag.
u
0 ·3ù
:::;
"O
0
2. Pour Tag name, saisir « v 1.0.0 » .
....
c.
~ Par con vention, les noms de tags git suivent le format vX.Y.Z, où v signifie
~
:::; version, X le numéro de version majeure, Y le numéro de version mineure et Z
rS le numéro utilisé pour des corrections d 'anomalie.
1
"O
0
c 3. Sous Create from, saisissez « master ».
8
(Ç) 4. C liquez sur Create tag.
Chapitre 1O. Intégration continue avec Docker

Administrator / hello-world v Se~rch r G + c+

hello-world Q

Ô' Star o V fork o

HTIP v ht t p : / /[Link]: 8180/root/hello -world. git ~ .!. + • Global v

l i commits 1 branch ~ 0.29 MB Add Changelog Add License Add Contribution guide

6666c370 Texte en rouge· 6 days ago by '*' root

Figure 10.18 - Tagging dans Gitlab

Le tag est maintenant créé. Nous pouvons ainsi construire le conteneur qui lui
est associé (car par défaut notre job de build construit un conteneur pour la branch e
master). Pour cela nous ut ilisons Jen kins.
1. C liquez sur le projet hello,world.
2. C liquez sur Build with Parameters.
3. Pour appVersion, saisissez« vl.0.0 ».

4. Pour gitPath, saisissez« tags » .


Le caractère « * » décrit tout chemin possible représen tant des branches ; dans
notre cas, il s'agit d'un tag et nous devons le spécifier particulièrement.
5. C liquez sur Build.

Vous vous souvenez que le build hello-world déclenche, après un succès, le job
deploy-test-hello-world. Ce déclenchement est également valable lorsque le build est
"Cl exécuté à la main. Ainsi, dans notre cas, nous pourrons constater qu'un nouveau
0
c:: déploiement sur l'environnement de test sera effectué (basé sur la branche master).
:::i
0 Ce dernier n'aura toutefois aucune utilité, mais il n'est pas dérangeant.
\.0
.-t
0
N Dès la fin de la construction du conteneur, nous pouvons l'utiliser grâce au job de
@
.......
déplo iement de l'environnement de production. A insi, toujours dans Jenkins:
..c::
Ol
ï::::: 1. C liquez sur le projet deploy,prod,hello,world.
>-
0..
0 2. C liquez sur Build with Parameters.
u
3. Pour appVersion, saisissez« vl.0.0 ».

4. C liquez sur Build.

Testons maintenant notre environnement de production :

1 http ://docker-api :8491/hel l o?n ame=Joh n


10.4 L'exploitation de notre Cl -------------------------12791
10.4.3 Correction d'une anomalie

À ce stade, tous les environnements sont alignés, dans le sens où ils ont tous exacte-
ment la même version du code. A fin de constater qu'il s'agit bien d 'en vironnements
différents, notamment au niveau du test et de la production , nous allons utiliser le
pré texte d 'une anomalie qui doit être corrigée : dans no tre cas, il s'agira de la v irgule
en tre le mot « hello » et le nom fourni en paramètre.
La vue doit ainsi être corrigée. Pour cela, éditons le [Link] et supprimons la virgule :

<!DOCTYPE HTML>
<html xml ns :th=" http : //www . t hyme l eaf .org ">
<head>
<tit le>Getting Started: Serving Web Cont en t </ t i tle>
<meta ht tp-eq uiv="Content- Type " content="text/html: charset=UTF-8 " !>
<lhead>
<body>
<p style="color : red ; " th :text=" 1 Hello 1 + ${n ame ) + 1 1 1 • !>
<!body>
<l html>

Testons la modification dans n otre conteneur d'en v ironnement de développe-


ment:

$ docker run -- rm -p 8090 :8090 -- vo l umes -from devenv -vo lume -- name devenv
1 devenv
Si nous accédons avec un navigateur à nos trois en vironnements, nous obtiendrons
le résultat décrit dans le tableau ci-dessous (la couleur rouge n'est ici pas représentée) :
Environnement URL Résultat
Développement [Link] me=John Hello John!
Test [Link] Hello, John!
Production [Link] /hello?name=John Hello, John!
"'Cl
0 Logiquement, seul l'e nvironnement de développement est impacté.
c
:::i
~
,.,
"O
0 [Link]; Publio ns la modification :
\.0
.-t ~
0 V
N V
'ii $ cd /home /v ag ran t/ vo l umes/devenv/ hel l o-world/
@ ·c
....... [Link]; $ gi t add src/main/resources/temp l ates/hel l [Link]
..c CO
$ git commi t -m"Suppression virgul e"
O'l c
ï:::::
>-
o.
0
c
c
1 $ gi t push orig i n mas ter :ma ster
u
0 ·3ù
:::;
"O C omme précédemment, l'en vironnement de test est automatiquement construit
0
....
c.
~
et déployé .
~
:::;
En accédant (après le déploiement) aux trois env ironnements avec un navigateur,
rS
1 cette fois-ci, les en vironnements de développement et de test sont impactés, et
"O
0
c l'en vironnement de production reste inchan gé :
8
(Ç)
J2sol------------------ Chapitre 10. Intégration continue avec Docker

Environnement URL Résultat


Développement [Link] 8090/hello?name=John Hello John!
Test [Link] Hello John!
Production [Link] /hello?name=John Hello, John!

Essayons maintenant de redéployer l'environnement de production avec la version


précédemment créée (la v l.0.0) afin de constater que le résultat sera toujours le même.
Dans Jenkins :
1. Cliquez sur le projet deploy~prod~hello~world.
2. Cliquez sur Build with Parameters.
3. Pour appVersion, saisissez« vl.0.0 ».

4. Cliquez sur Build.

En ouvrant un navigateur à l'adresse de production, la virgule est bien toujours


présente. Il faudra it « releaser » le code (dan s une version Vl.0.1 pour suivre la
convention de nommage ) et déployer cette nouvelle version pour voir la correction
appliquée.

En résumé
Dans ce chapitre, n ous avons pu voir comment un système d'intégration continue
peut être facilement mis en place grâce à Docker. Nous avons pour cela utilisé deux
aspects:
- d'une part des images existantes (conçues par des tiers) contenant des outils
directement fonctionnels (dans notre exemple, il s'agissait de GitLab et Jenkins) ;
- d'autre part une architecture de déplo iement basée sur des conteneurs afin de
pouvoir tester très rapidement une application et la mettre en production le cas
échéant.
"'Cl
0
c
:::i
0
\.0
.-t
0
N
@
.......
..c
O'l
ï:::::
>-
0.
0
u
11
Docker Swarm

Clustering avec Docker


L'objectif de ce chapitre est de découvrir la solution de clustering implémentée
dans l'écosystème de Docker lnc.: Docker Swarm. Nous découvrirons d'abord les
différents composants nécessaires, puis créerons localement sur notre poste de travail
un petit cluster. Finalement, nous déploierons quelques conteneurs, tout d'abord
manuellement, puis avec Docker Compose.
À l'issue de ce chapitre, vous saurez déployer et utiliser un cluster Docker et
comprendrez comment les différents conteneurs communiquent entre eux via le
réseau overlay.
N ous n'avons pour l'instant utilisé Docker que sur un seul h ôte, principalement
"'Cl
0 notre poste de travail. Cependant, pour une utilisation productive de Docker, il est
c::
:::i
~
,., plus que probable que vous voudrez disposer de plusieurs nœ uds, typiquement pour
"O
0 [Link];
\.0 assurer une haute disponibilité de votre application. C es différents nœ uds devront
.-t ~
0 V
V
de plus pouvoir héberger des conteneurs devant communiquer entre eux, ce que le
N
'& réseau bridge ne peut réaliser; c'est là que nous aurons besoin d'un nouveau type de
@ ·c
B
.......
..c::
:::;
CO
réseau Docker : le réseau overlay.
O'l c
ï:::::
>-
0
c Commençons par comprendre les différents éléments constituant un cluster Docker
o.. c
0 ·3ù Swarm.
u :::;
"O
0
....
Swarm est un exemple de solution pour implémenter une architecture CaaS telle que
c.
~ nous l'avons décrite dans le chapitre 2. Le lecteur pourra s'y reporter pour découvrir
~
:::; d'autres solutions comme Kubernetes ou Mesos.
rS
1
"O
0
c
8
(Ç)
J2s2I------------------------ Chapitre 11. Docker Swarm

11.1 DOCKER SWARM


Docker Swarm permet de gérer centralement un ensemble d 'hôtes disposant d'une
instance de Docker Engine, le tout comme un hôte unique.
Il s'appuie pour cela sur :
• notre client Docker : il sera utilisé aussi bien pour gérer nos conteneurs que
notre cluster Swarm ;
• un service de découverte (discovery service) qui permet de centraliser les
informations de tous les hôtes (principalement la configuration réseau et l'état
de chaque hôte) ;
• d'un maître Swarm (Swarm Master) et optionnellement de plusieurs réplicas
dans le cas d'une architecture hautement disponible ;
• de plusieurs nœ uds Swarm (Swarm N ocle).

Service de
découverte Swarm Nede
(node 01)

Swarm Master Swarm Nede


(leader) (node 02)
Client docker

! 1 Swarm Nede
(node p)
Swarm Master Swarm Master
(replica 1) (replica n)

"O
0
c
::i Figure 11.1 - Architecture générique d'un cluster Swarm
0
\.0
.-t
0
N
@
Docker Swarm permet même de gérer de manière transparente des hôtes localisés
.......
.c
dans des centres de calculs différents, voire chez des fournisseurs cloud différents.
O'l
ï::::: Une réflexion poussée sur les aspects opérationnels de gestion et de performance
>-
0. est, dans ce cas, obligatoire, et nous ne pouvons que vous conseiller l'article sur le
0
u site de Docker qui couvre ce sujet plus en détail 1•

Détaillons un peu plus chacun de ces nouveaux composants.

1. h ttps://[Link]/swarm/plan-fo r-production/
11.1 D ocker Swarm ---------------------------12831
11 .1.1 Le service de découverte

Le service de découverte peut être considéré comme la C MDB 1 du duster. Il fournit


principale ment :
• un registre des serv ices disponibles ;
• un mécanisme pour pouvoir enregistrer de nouveaux services et surve iller leur
fonctionneme nt ;
• un mécanisme pour pouvoir découvrir les services disponibles et, bien sûr, s'y
connecter en fournissant tous les paramètres nécessaires.

Le registre des services est généralement implémenté à l'aide d'un système de


persistance de type d é/valeur qui stocke aussi bien les informations sur les différents
hôtes que les paramètres de configuration des applications.
Docker propose actuellement trois types de serv ice de découverte 2 :
• le premier est basé sur un fi chier listant uniquement les IP des différents hôtes.
Comme vous l'imaginez, ce mécanisme est vite limitant et n'est conseillé que
pour les configuratio ns simples ;
• le Docker Hub. L'utilisation de ce serv ice, qui nécessite que tous vos hôtes aient
accès à Internet, est déconseillée par Docker pour une utilisation en production.
Il repose sur un toke n (qui représente l'identifiant de votre duster) qui est
ensuite utilisé pour requêter le service de découverte du Docker Hub ;
• le dernier repose sur l'utilisation d 'un système dé/valeur dédié. Docker utilise
cela pour la bibliothèque libkv3 qui permet d 'abstraire l'utilisation d'un tel
serv ice et même d'en implémenter de nouveaux. Actuellement, libkv supporte
Consul4 (>= 0.5.1), etcd5 (>= 2.0 ), Zookeeper6 (>= 3.4.5 ) et BoltDB7 (un ique-
ment disponible localement).

Chacun dispose en général d'une interface de gestion REST qui permet aussi bien
l'enregistrement, le retrait des services et l'en voi de requêtes de découverte.
"'Cl
0
c
:::i
~
,., 11 .1.2 Maitre et nœuds Swarm
"O
0 [Link];
\.0
.-t ~
V
Q uand on parle de nœud du d uster, cela signifie simplement un hôte sur lequel tourne
0
N V
'ii le programme (binaire ) Swarm. C e programme dispose, comme nous l'avons vu dans
@ ·c
....... B
:::;
le chapitre 2, de deux modes de fonctionnement :
..c CO
O'l c
0
ï::::: c
>-
o. c
u
0 ·3ù
:::;
"O
0 1. Configuration and. Management Database
....
c. 2. [Link]
~
~ 3. h ttps://[Link]/docker/libkv
:::;
rS 4. [Link] io/
1
"O
0 5. [Link]
c
8 6. h ttps://[Link] [Link]/
(Ç) 7. [Link] [Link]/boltdb/bolt
Chapitre 11. Docker Swarm

• mode maître (Swarm master). Nous devons évidemment avoir au moins un


master par cluster, qui, en tant que contrôleur, gère les différents n œuds du
cluster et orchestre le déploiement des conteneurs sur les différents hôtes.
Étant un point individuel de défaillance, il est recommandé de définir plusieurs
réplicas, dont un deviendra le nouveau maître en cas de défaillance du premier 1 ;

Dans le cas d'une architecture multi-master, vous pouvez directement utiliser


les réplicas pour faire parvenir des commandes à votre cluster ; celles-ci seront
tout simplement transmises au maître pour leur exécution (les réplicas n'agissent
finalement qu'en tant que proxies).

• mode esclave. Les n œ uds Swarm sont simplement des hôtes sur lesquels nos
conteneurs vont tourner.

Mettons maintenant cela en œuvre.

11.2 MISE EN ŒUVRE D'UN CLUSTER SWARM


Mettre en œuvre un cluster Swarm pour un environnement haute disponibilité,
potentiellement réparti sur plusieurs réseaux privés différents, voire plusieurs centres
d'hébergement, est clairement en dehors du périmètre de ce livre. Par contre, grâce
à ce que nous avons appris sur l'utilisation de Docker Machine au chapitre 4, nous
pouvons créer localement, sur notre poste de travail, un cluster minimal.
Ce cluster reposera sur quatre hôtes (so it quatre machines virtuelles VirtualBox) :
• consul : cet hôte hébergera notre registre de service qui sera déployé comme
un conteneur Docker. La documentation de Consul recommande d'avoir entre
trois et cinq serveurs Consul2 par datacenter pour éviter toute perte de données
et fournir un système de haute disponibilité. Dans notre cas, nous n'utiliserons
qu'un seul serveur pour simplifier la mise en œuvre ;
"'Cl
0
c • swarm,master : notre Swarm Master sera installé sur cette machine virtuelle.
:::i
0 Il sera notre point d'entrée pour commander notre cluster (dans notre cas, il
\.0
.-t permettra également de faire tourner des conteneurs de la même manière que
0
N les n œ uds esclaves) ;
@ • swarm,node-01 et swarm-node-02 : nous aurons deux nœuds dans notre cluster
.......
..c qui feront tourner nos conteneurs .
O'l
ï:::::
>-
0.
0 Nous allons créer ces quatre hôtes localement à l'aide de Docker Machine et de
u son driver Virtualbox.
Au final, nous aurons la configuration suivante :

1. [Link]
2. [Link] html
11.2 Mise en œ uvre d'un cluster Swarm

localhost

Client docker swarm-master

swarm-node-01 swarm-node-02

Figure 11 .2 - Architecture de notre cluster Swarm

C o mmençons direc tement par notre machine virtuelle « consul ».

11.2.1 Service de registre : Consul

Consul est un système de découverte et de configuration des services. Il fournit en plus


un système de health check, inclut une base de données clé/valeur et peut ê tre utilisé
d;:ins 11n e confî g11rntion ;:ivec p l11sie11rs centres d e c ;:ilc11ls.

Il est basé sur un système distribué d'agents, chacun pouvant fonctionner :


• soit en mode serveur : dans ce cas, il stockera localement les informations
dans sa base de données qui seront ensuite répliquées entre les différents agents
serveurs. Ces différents serveurs formeront un cluster C onsul (idéalement en tre
t rois et cinq serveurs pour avoir une haute disponibilité ). Dans le cas de plusieurs
"'Cl centres de données, il est conseillé que chacun dispose de son cluster C onsul
0
c:: ~
,., pour éviter une perte de données ;
:::i
"O
0 [Link]; • soit en mode agent simple : chaque hôte peut conten ir un agent Consul, mais ce
\.0
.-t ~ dernier ne servira qu'à surveiller les services de son hôte. Il n 'est pas obligatoire
0 V
N V
'&
·c
d'en avoir un.
@
....... B
:::;
..c:: CO
Dans notre configuration , nous n'aurons qu'un serveur C onsul qui tournera sur un
O'l c
0
ï::::: c
>-
o.. c h ôte dédié pour simplifie r la mise en œ uvre. Nous avons déjà vu au ch apitre précé-
u
0 ·3ù dent la commande docker-mach ine create . Utilisons-la po ur créer n otre mach ine
:::;
"O
0
....
« consul » :
c.
~
~
:::;
rS $ docker -machi ne create -- dri ver=v i rt ualbox consul
"O
1 Running pre-create chec ks . ..
0
c Creati ng ma chi ne . ..
8 (consu l ) Copying /Users/thomas/ .docker/mac hi ne/cache/boot2doc ker . iso to
(Ç) /Users/t homas/ .docker/ mach i ne/mach i nes/consu l /boot 2docke r. iso .. .
Chapitre 11. Docker Swarm

(consul ) Crea ti ng Virt ualBox VM ...


(consul ) Cr ea ting SSH key .. .
(consul) Starti ng t he VM .. .
(consul ) Check network t o re-c reat e i f needed ...
(consul ) Wait ing for an IP ...
Wai ti ng for machine to be r unning , this may ta ke a f ew minut es . ..
Detect ing operat i ng system of created i nstance ...
Waiting for SS H to be avai l abl e ...
Detec t ing t he provisione r ...
Provision i ng with boot 2docker ...
Copyi ng ce r ts to t he l ocal machine di rectory ...
Copy i ng certs to the remot e mach i ne . ..
Setting Do cker con f iguration on the remote daemon. . .
Ch ecki ng connection t o Docker ...
Docker is up and running!
To see how to con nect your Docker Client to the Docker Engine ru nn i ng on t his
vi rt ua1 mac hi ne, run : docker -machine env cons ul

Po inton s notre environnement vers notre nouvelle machine et démarrons un


conteneur Consul: nous utiliserons pour cela l'image progrium/consul1 disponible sur
le Docker Hub.

$ eva l $ (docker -machine envconsu l )


$ docker r un -d -p 8500 :8500 -p 8600 : 53/ udp -h cons ul -- name=consul
1 prog ri um/cons ul -server -bootstra p -u i -dir / ui

Quelques explications sur les différents paramètres de la commande précédente :


• nous exposons les deux ports qui permettent d'interagir avec notre registre,
HTTP (port 8500) et ONS (8600). Nous verrons bientôt plus en détail
comment ils sont utilisés ;
• le paramètre server perme t d'indiquer à l'agent Consul de démarrer en mode
serveur ;
• le paramètre boots trap est requis par Consul pour indiquer à notre agent qu'il
peut s'auto,élire comme leader Raft. Raft est le protocole de consensus utilisé en
"'Cl
0 interne par Consul. Dans le cas d'une configuration à plusieurs agents Consul,
c
:::i il permet d'élire un leader et ensuite de s'assurer que tous les agents répondent
0
\.0 de manière consistante aux requêtes qu'ils reçoivent2 ;
.-t
0
N
• le paramètre ui - di r / ui : C onsul embarque une interface web qui permet
@ d'explorer le contenu du magasin clé/valeur. Ce paramètre est optionnel et
.......
..c nous permettra de comprendre plus simplement le fonctionnement de notre
O'l
'i: cluster. Il nous suffit pour cela de récupérer l'IP de notre machine et, avec un
>-
0.
0 navigateur, d'aller à l'adresse [Link] ip_machine>:8500/ui.
u

Pour récupérer l'adresse IP de la machine Docker hébergeant le conteneur


«consul », il suffit d'exécuter la commande suivante: docker -mach ine i p consu l.

1. [Link]
2. [Link] html
11.2 Mise en œuvre d 'un cluster Swarm

Nous pouvons d'ailleurs directement nous en servir pour voir que nous avons
maintenant un hôte Consul qui fournit le service Consul sur le port 8300 (qui est le
port RPC 1 utilisé pour la communication entre serveurs Consul) .

..
<::•
_,,_ ·-....... - ...,,.....

consul 0.2
.... ..,,. e

1 1
1 conlUI
·-1 .......
OICCKS
-
....
Serf Heallh Status
-

Figure 11 .3 - Interface graphique de Consul

Consul dispose d'une documentation d'excellente qualité. N ous ne pouvons que


vous encourager à la parcourir pour comprendre toutes les capacités et les rouages
intemes2 .
Prochaine étape : créons notre Swarm Master ainsi que les deux nœ uds esclaves.

11.2.2 Maitre et nœuds Swarm


N ous allons de n ouveau utiliser Docker Machine pour c réer nos différents hôtes.
"'Cl
0
Commençons par notre Swarm Master :
c
:::i
~
,.,
"O
0 [Link];
\.0 $ docker -ma ch in e create ·- dr i ver=v i rt ual box ··swa rm ··swa rm-ma ster
.-t ~
0 V
V
- -swarm-di scovery= "consu l : // $(doc ker -ma chi ne i p con sul ) : 8500 "
N
'ii - -engi ne-opt =" cl uste r -store=con sul : / /$ (doc ker -mach i ne i p con sul ) : 8500 "
@
.......
..c
·c
[Link];
CO
1 -- engi ne-opt="cl uste r-ad vertise=ethl :2376 " swarm-ma ste r
O'l c
0
ï::::: c
>- c
Regardons un peu les différents paramètres :
o.
u
0 ·3ù
:::; • - -dri ve r=vi rtua l box : sans surprise, nous utilisons le driver VirtualBox;
"O
0
.... • - - swa rm : installe automatiquement Docker Swarm sur notre machine ;
c.
~
~
:::;
• - · swarm-maste r : configure Swarm comme étant un Swarm Master;
rS
1
"O
0
c
8 l. Remote Procedure Cali
(Ç) 2. h ttps://[Link]/docs/[Link]
Chapitre 11. Docker Swarm

• --swarm- discove ry= "consul : // $(d ocker -mac hi ne ip cons ul ) :8500 " : spec1-
fie la localisation de notre service de découverte. Nous obtenons l'IP de notre
machine Consul avec la commande doc ke r- machine i p consu l et précisons le
port exposé HTIP ( 8500) ;
• --en gine-opt="cluster -s tore=cons ul : //$( docker-ma chi ne ip
consul ) : 8500" : ce paramètre permet de configurer le démon Docker qui sera
installé sur notre machine. Cela permettra à notre hôte de s'enregistrer comme
faisant partie de notre cluster ;
• -- eng i ne-opt="cl uster-a dve rt i se=et hl : 2376 ": adresse à laquelle notre
démon sera exposé et jo ignable sur notre cluster.

Si nous n ous connectons sur notre machine, nous pouvons vérifier que la configu-
ration s'est effectivement bien passée :

$ doc ke r -machi ne ssh swarm-maste r

docker@swarm - mas t er : ~$ docker ps -a


CONTAINER ID IMAGE COMMA ND CREATE D
STATUS PORTS NAM ES
e46d3a l 9e743 swarm : l atest "/swarm jo i n -- advert " 6 minutes aga
Up 6 mi nutes swarm-agent
5d l3ed 6ca0b4 swarm : la t es t "/swarm man age -- t l sv" 6 mi nut es aga
Up 6 mi nutes swarm -agent -mas t er

Docker Machine a automatiquement instancié deux conteneurs Swarm (basés sur


la même image qui contient principalement le binaire de Swarm1 ) :
• swarm-master-agent : comme vous l'avez deviné, c'est notre Swarm Maste r ;
• swarm-agent : c'est l'agent Swarm qui gérera les conteneurs de notre hôte et qui
recevra les commandes du Swarm Master.

Nos deux conteneurs ne contiennent finalement que le binaire Swarm (et quelques
"'Cl
0
certificats CA nécessaire au mode TLS). C'est une technique efficace pour packager
c un exécutable et profiter ainsi du Docker Hub comme moyen de distribution. 11
:::i
0
\.0
est aussi possible d'installer manuellement le binaire de Docker Swarm, même si
.-t
0 l'intérêt est limité, comme le reconnaît d'ailleurs Docker lnc 2•
N
@
.......
..c Regardons plus en détail les processus docker/swarm qui tournent dans notre
O'l
ï::::: machine:
>-
0.
0
u
doc ker@swarm- mas te r : ~$ ps -ax
2636 ? Sl 0:12 /usr/ l ocal/bin /docker daemon -D -g /var/ l ib /docker
-H uni x: // -H tc p: //0 . 0. 0. 0: 2376 - -l abe l prov i der=vi rtualbox
1 -- cl uster -store=cons ul : // 192.168. 99 . 102:8500 -- cl us t er -advert i se=et hl: 2376

1. [Link]
2. [Link]
11.2 Mise en œuvre d'un cluster Swarm

-- t l sveri fy -- tl scacert=/va r /l ib / boot2docker/ca . pem


--tlscert=/var/ l ib / boot2doc ker / server . pem
-- t l skey=/var/ l i b/boot2docker/server -key . pem -s aufs

2777 ? Ss l 0:00 /s warm manage --t l sverify


- -tlscacert=/var/ l i b/ boot2docker/ca . pem
--tlsce rt=/var /lib/ boot2docker/server . pem
-- t l skey=/var/ l i b/boot2docker /server -key . pem -H t cp : //0 . 0. 0. 0:3376 -- strategy
spread - -advert i se 192 .168 . 99 . 103 :3376 cons ul : // 192 . 168 . 99 . 102 :8500

2790 ? Ss l 0:00 /swarm j oi n --a dverti se 192 .168 . 99 .1 03 :2376


cons ul : / /19 2. 168 . 99 . 102 :8500

Nous retrouvons bien :


• notre démon Docker disponible sur le port 2376 (port TLS par défaut) et avec
les options que nous avions passées à Docker Machine ( --cl us t er-s to re et
--c l uster-advertise );
• notre Swarm Master (/swarm manage) qui sera disponible sur le port 3376. C'est
par ce port que nous piloterons notre cluster depuis notre client Docker. A u
passage, nous remarquons que notre Swarm Master utilise bien la stratégie par
défaut « spread » ;
• notre agent Swarm (/swarm join) qui enregistre le démon Docker de notre
hôte dans Consul et le rend disponible pour notre cluster. Nous pouvons
d'ailleurs nous en rendre compte via l'interface de Consul sous KEY/VALUE,
puis DOCKER/NODES qui liste les démons Docker disponibles.

'"'0 ..
~-oc-·--~I e

OOCKER/NOOES/ •

dOCkOf/nodes/192.1611.99.103:2370 [Link]ŒD

"'Cl
0
c::
:::i
~
,.,
"O
0 [Link];
\.0
.-t ~
0 V
N V
'&
@ ·c "49odl)l-11~------

....... B
:::;
..c:: CO
O'l c
0
ï::::: c
>- c
o..
u
0 ·3ù
:::;
"O
0
....
c.
~
~
:::;
Figure 11.4 - Nœuds Dockers enregistrés par Consul
rS
1
"O
0
c
8 Il est conseillé sur un environnement de production de ne pas avoir d'agent
(Ç) Swarm non~master sur l'hôte qui h éberge le Swarm Master, car cela évite d'avoir
Chapitre 11. Docker Swarm

des conteneurs qui se déploient sur ce serveur. Par défaut, Docker Machine en installe
un, ce qui peut être considéré comme un bug.
Sur le même principe, il ne nous reste plus qu'à créer nos deux nœuds esclaves.
L'unique différence est l'absence du paramètre -- swarm -mas t er, si bien que nous
n'aurons qu'un agent Swarm sur ces hôtes (ce sont donc des nœ uds esclaves) .

$ docker -machine create -- driver=virtualbox -- swarm


- -swarm-d i scovery="consul : //$ (d ocker-mach i ne i p consul ) :8500 "
--engine-opt="c l uster-st ore=consul : // ${docker-machine i p consul) :8500 "
-- engine -opt= "cl us t er -advertise=eth l :2376 " swarm -node -01

$ docker-machi ne crea t e --driver=virt ualbox --swarm


- -swarm -di scovery= "cons ul : // ${docker -mach i ne i p consul ) :8500 "
- -engi ne -opt="c l uster -store=consu l : / / $(docker-machine i p consu l ) : 8500 "
--engine-opt="c lu ster-advertise=et hl :2376 " swarm-n ode-02

Connectons maintenant notre client Docker sur notre Swarm Master. Pour cela,
nous utilisons une légère variante de la commande que nous avons vue précédemment :
nous rajoutons le paramètre - - swa rm qui nous permet d'interagir avec le Swarm Master
(sur le port 3376). Si nous oublions ce paramètre, par défaut, notre client serait
configuré pour utiliser le port 2376 qui est notre démon Docker. Dans ce cas, nous
court~circuiterions Swarm et nous ne ferions que piloter un unique hôte.

On peut le voir facilement:

$ docker -machine env swarm-master


export DOCKER_TLS_VERI FY=" l "
export DOCKER_HDST="tcp : //192 . 168 .99 .107 :2376 "
export DOCKER_CERT_PATH="/Users/thomas/ .docker/machine/machi ne s/swarm -master"
export DOCKER_MACH INE_NAME=" swarm -maste r"
# Run th i s comma nd to configure your shel l :
# eval $(docker -machine env swarm -master)
"'Cl
0
$ docker -machi ne env --swarm swarm-mas t er
c::
:::i
export DOCKER_T LS_VER IFY= "l "
0 export DOCKER_HOST="t cp : //192 .1 68 .99 .107:3376"
\.0
.-t
export DOCKE R_C ERT_PATH="/Users/thomas/ .docker/machine/machi nes /swarm -mas t er "
0
N
export DOCKER_MACH INE_NAME="swarm -master "
@
# Run th i s comma nd to configure your shel l :
....... # eva l $(docker -machine env -- swarm swarm -mas t er)
..c::
O'l
·;::
>- Listons maintenant tous les n œ uds e t conteneurs de notre cluster. Nous pouvons
0..
u
0 pour cela utiliser la commande docker i nf o sur notre Swarm Master après avoir
configuré les variables d'en vironnement pour notre client Docker.

$ eva l $(docker -machine env -- swarm swarm -master)


$ docker i nfo
Containers : 4
Running : 4
Paused : 0
11.2 Mise en œuvre d'un cluster Swarm

Stopped : 0
Images : 3
Server Version : swarm/ 1. 1.3
Ro l e: primary
St rategy : spread
Fi lters : hea lt h, port . dependency , affinity , const rain t
Nades : 3
swarm -master : 192 .1 68 .99 . 107 : 2376
L Status : Healthy
L Cont ainers : 2
L Reserved CPUs : 0 / 1
L Reserved Memory : 0 B / 1. 021 GiB
L Labe l s : executiondr i ver=nat i ve -0.2. kerne l vers i on=4 . l . 19 -boot 2docker .
operat i ngsys t em=Boot2Doc ker 1. 10.3 (TC L 6.4. 1) ; master : 62511 7e - Thu Mar 10
22 :09 :02 UTC 2016, prov i der=v i rtualbox . storagedriver=aufs
L Error : (none)
L Upda t edAt: 2016 -03 -13T07 :38 :12Z
swarm-node-01 : 192 .168 .99 .108 :2376
L Stat us : Healthy
L Containers : 1
L Reserved CPUs : 0 / 1
L Reserved Memory : 0 B / 1.021 GiB
L Labe l s : executiondr i ver=nat i ve -0.2. kerne l vers i on=4 . l . 19-boot 2docker .
operat i ngsys t em=Boot2Doc ker 1. 10.3 (TC L 6.4 . 1) ; master : 62511 7e - Thu Mar 10
22 :09 :02 UTC 2016, prov i der=v i rtualbox . storagedr i ver=aufs
L Error : (none)
L UpdatedAt : 2016-03- 13T07:39 :04Z
swarm -node -02 : 192.168 .99. 109 :2376
L Stat us : Healthy
L Cont ainers : 1
L Reserved CPUs : 0 / 1
L Reserved Memory : 0 B / 1. 021 GiB
L Labe l s : execut i ondr i ver=nati ve-0 .2, ke r ne l vers i on=4 . l . 19-boot 2doc ker.
operatin gsystem=Boot2Doc ker 1. 10 .3 (TCL 6.4. 1) ; master : 625117e - Th u Mar 10
22 :09 :02 UTC 2016. prov i der=v i rtua l box . storagedr i ver=aufs
L Error : (none)
L UpdatedAt : 2016-03- 13T07:38 :38Z
Pl ugi ns :
"'Cl
Vo l ume :
0 Network :
c:: ~
,.,
:::i
"O
Kernel Version : 4.l. 19 -boot 2docker
0 [Link];
\.0
Operat i ng System : l i nux
.-t
0
~
V
Architect ure : amd64
N V
'&
CPUs : 3
@ ·c Tota l Memory : 3.064 GiB
....... B
..c::
:::;
CO Name : swarm -master
O'l c
0
ï::::: c
>-
o.. c
0 ·3ù Nous retrouvons bien n os trois nœuds avec le nombre de conteneurs actifs sur
u :::;
"O
0
chaque nœud: deux pour swarm,master (le Swarm Master et l'agent Swarm), un pour
....
~
c. chacun de n os nœ uds esclaves (uniquement l'agent Swarm).
~
:::;
Notre registre de service est totalement fonctionnel, et nos machines sont
rS
"O
1
maintenant prêtes. Nous pouvons donc déployer nos premiers conteneurs.
0
c
8
(Ç)
Chapitre 11. Docker Swarm

-
11.3 DEPLOYER UNE APPLICATION SUR UN CLUSTER
SWARM
11.3.1 Prise en main rapide

Abordons cela étape par étape pour bien comprendre comment Swarm orchestre
le déploiement de nos conteneurs. C ommençons, par exemple, par déployer quatre
conteneurs Nginx.

$ eval $(docker-mac hin e env --swarm swarm-ma ster)


#Nous ut i lisons not re Swarm Mas t er
$ docker r un -d -p 80 --name=nginx-1 ng i nx

$ docke r r un -d -p 80 --name=nginx -2 ng i nx

$ docker r un -d -p 80 --name=nginx -3 ng i nx

$ docker run -d -p 80 --name=n ginx-4 ng i nx

Vous remarquerez que les commandes run prennent plus de temps qu'à la normale.
C'est que Docker doit, pour chaque nœud sur lequel le conteneur Nginx doit être
instancié, télécharger l'image depuis le Docker H ub. En effet, les images ne sont pas
partagées par les différents nœuds du cluster et doivent être disponibles dans le cache
local de chaque hôte. Ainsi la première fois qu'un conteneur est démarré sur un nœud,
l'image devra être téléchargée ; dans notre cas cela se produit pour les trois premiers
conteneurs car nous avons en tout trois nœuds disponibles (deux nœuds esclaves et le
nœud Swarm Master). Listons nos conteneurs :

$docker ps --forma t "table {{ . ID}} {{ .Sta t us} } {( . Ports}} ( ( . Names }}"


CONTAINER ID STATUS PO RTS NAMES
"'Cl 555b54781876Up Abo ut an ho ur 443/tcp, 192 . 168 . 99 .1 09 :32769 ->80 /tcp
0
c:: swarm -node -02/nginx -4
:::i
0 bl44c4e25694Up Abo ut an ho ur 443/tcp . 192 . 168 .99 . 108 :32769- >80/ tcp
\.0 swarm -master/ng i nx -3
.-t
0 llbbade4a679Up About an hour 443 /tc p, 192 .168 . 99 .1 09 :32768->80/tcp
N
swarm -node -02/nginx -2
@
.......
7d7fl7a74c33Up About an hour 443 / tcp, 192 .1 68.99. 101 :32768 ->80/ tc p
..c:: swarm-node-01/ng i nx-l
O'l
ï:::::
>-
0..
0
u Nous avons bien nos quatre conteneurs, deux sur swarm-node-01, un sur swarm-
node-02, et un sur swarm-master. Lorsqu'un Swarm Master reçoit une commande pour
instancier un nouveau conteneur, il utilise deux mécanismes complémentaires pour
sélectionner le nœud sur lequel le conteneur va être démarré : les filtres et la stratégie
de déploiement .
11.3 Déployer une application sur un cluster Swarm

Les filtres
Les filtres vous permettent de définir finement les règles de déploiement et de dire à
Swarm où instancier le conteneur.
Il existe cinq filtres répartis en deux types :
• les premiers se basent sur les attributs du nœud, plus particulièrement sur les
attributs du démon Docker directement. Ce sera soit des attributs standards
(la version du n oyau Linux, le système d'explo itation ... ), soit des étiquettes
personnalisées dé[Link] au niveau du démon. Regardons quelques exemples
utiles :

Commande à utiliser Commentaire


sur le Swarm Master
$docker run -d -e constraint:node=swarm-node- Déploie un conteneur nginx-5 sur le nœud avec
01 - name=nginx-5 nginx le nom« swarm-node-01 ».
$ docker run -d -e constraint: operatingsys- Déploie le conteneur nginx-6 sur un nœud qui
tem=Boot2Docker* -name=nginx-6 nginx est basé sur une image Boot2Docker.
$ docker run -d -e constraint: storagedri- Déploie le conteneur nginx-7 sur un nœud dont
ver=devicemapper -name=nginx-7 nginx le démon Docker utilise le pilote de stockage
devicemapper (référez-vous au chapitre 4 pour
plus de détails sur ce sujet).
$ docker run -d -e constraint: type=front - Déploie le conteneur nginx-8 sur un nœud dont
name=nginx-8 nginx le démon Docker a été démarré avec l'étiquette
" -label type="front" ,, comme paramètre.
$docker run -d -p 80 :80 - na me= nginx-9 nginx Déploie le conteneur nginx-9 sur un nœud
dont le port 80 est disponible. La création de
ce conteneur échouera si aucun nœud n'a de
port 80 disponible.

La liste des attributs utilisables dans les filtres s'obtient facilement avec la com-
mande docker i nf o et en regardant le champ Labels.

"'Cl
0 • les seconds types de filtres s'appliquent aux conteneurs eux-mêmes. Il est alors
c::
:::i
~
,.,
0 "O possible de regrouper des conteneurs ayant certaines affinités sur le même hôte
[Link];
\.0
.-t ~
ou partageant certaines dépendances. De nouveau, voici quelques exemples
0 V
N V intéressants à garder en tête :
'&
@ ·c
....... B
:::;
..c:: CO Commande à utiliser Commentaire
O'l c
ï::::: 0
c sur le Swarm Master
>- c
o.. $ docker run -d -e affinity:container=nginx-4 Déploie le conteneur nginx-10 sur le même
u
0 ·3ù
:::; -name=nginx-1 0 nginx nœud qu'un conteneur portant le nom « nginx-
"O
0
.... 4 ».
c.
~ $ docker run -d -e -e affinity:image= nginx - Déploie le conteneur nginx-11 sur un nœud
~
:::; name= nginx-1 1 nginx qui dispose déjà de l'image Nginx localement.
rS $ docker run -d -volumes-from=volume_ 1 - Déploie le conteneur nginx-12 sur le même
1
"O
0 name= nginx-12 nginx nœud que le conteneur volume_ 1 pour per-
c
mettre l'accès aux volumes de ce dernier.
8
(Ç)
Chapitre 11. Docker Swarm

Attention, si Docker Swarm ne peut pas honorer l'affinité demandée, le conteneur


ne sera pas instancié !

Les stratégies de déploiement


S i aucun filtre n'est défini, Docker Swarm se base sur une stratégie de distribution des
con teneurs. Il existe trois stratégies possibles :
• spread : les conteneurs seront répartis de manière h omogène sur les différents
h ôtes. Swarm sélectionne pour cela le nœ ud qui dispose du plus petit nombre de
conteneurs, indépendamment du fait que les conteneurs présen ts soient arrêtés
ou non;
• binpack : au contraire de la stratégie spread, Docker Swarm essayera de regrou,
per un maximum de conteneurs sur un minimum de nœ uds. Pour cela, Docker
Swarm calcule un poids1 pour ch aque nœ ud en fonction d'un certain nombre
de paramètres (CPU, RAM, du nombre de conteneurs déjà présents, santé du
démon Docker. .. ) et déploie le conteneur sur celui qui est le mo ins utilisé ;
• random: comme son n om l'indique, la répartition sera effectuée de manière
aléatoire sur tous les nœ uds du cluster.

Par défaut, Docker Swarm utilise la stratégie spread. S i nous reprenons nos
commandes dans l'ordre et regardons après chaque commande combien de conteneurs
nous avons sur chaque n œ ud, voici le résultat illustré dans un tableau :
Étape/commande Nombre de conteneurs par nœud
Initialement swarm-master : 2
swarm-node -01 : 1
swarm-node-02 : 1
$ docker run -d -p 80 -name=nginx-1 swarm-master : 2
nginx swarm-node -01 : 2 ( 1 + nginx-1>
swarm-node-02 : 1
$ docker run -d -p 80 -name=nginx-2 swarm-master : 2
l:l nginx
0 swarm-node -01 : 2
c
:::i swarm-node-02 : 2 (1 + nginx-2)
0
\.0 $ docker run -d -p 80 -name=nginx-3 swarm-master: 3 <2 + nginx-3> - N'oublions pas que
.-t
0 nginx nous avons un nœud esclave sur cet hôte !
N
swarm-node -01 : 2
@
....... swarm-node-02 : 2
..c
O'l
ï:::::
$ docker run -d -p 80 -name=nginx-4 swarm-master : 3
>- nginx swarm-node -01 : 3 (3 + nginx-4)
0.
0
u swarm-node-02 : 2
lntéressons,nous maintenant à un cas où nos conteneurs doivent communiquer les
uns avec les autres, tout en étant localisés sur des nœ uds différents.

1. [Link]
11.3 Déployer une application sur un cluster Swarm

11 .3.2 Le réseau overlay


Nous avons déjà couvert en détail le fonctionnement du réseau Docker dans le cas
d'un hôte (réseau de type bridge ) au chapitre 9. Pour notre cluster, nous allons devoir
utiliser un nouveau type de réseau : le réseau overlay. Ce réseau permet de faire
communiquer de manière transparente des conteneurs qui sont localisés sur des nœ uds
différents.
Regardons avant tout les réseaux disponibles sur notre cluster :

$ eva l $(docker-mach i ne env --swarm swarm -master)


$docker net work l s
NETWORK ID NAM E DRIVER
55d03caed3e0 swarm -node-02/host hos t
96b2d6913f bd swarm-node-02/bridge br idge
2c220eb04dc7 swarm- node-02/none null
4422eb632120 swarm -master/none nul l
66a56314ef b0 swarm -master/bridge bridge
53e82elb3384 swarm -node -01/none null
6cf9cb621ff6 swarm-master/host host
78286be3able swarm-node-01/bridge bri dge
64a36a3c4672 swarm -n ode -01/host host

N ous retrouvons pour chacun de nos nœuds, les trois réseaux standards de Docker :
bridge, null et host. Pour que nos conteneurs sur des hôtes différents puissent
communiquer entre eux, nous allons créer un nouveau réseau :

$ docker network create --d r i ver over l ay swarm -net


1 5e9bb5166beldc85fb903234c8de74bb9a50c9162aef99d7a4479d6blb2d2fbl
N ous pouvons effectivement vérifier que ce réseau est maintenant disponible sur
tous les nœuds de notre cluster :

$ eva l $(docker-mach i ne env swarm -ma st er)


"'Cl
$ docker network ls
0 NETWORK ID NAM E DRIVER
c::
:::i
~
,., 5e9bb5166bel swarm -net overlay
"O
0
\.0
[Link]; 4422eb632120 none null
.-t ~
V
6cf9cb621ff6 host hos t
0
N V
'&
66a56314ef b0 bridge br id ge
@ ·c $ eva l $(docker -machine env swarm -node -01)
B
.......
..c::
:::;
CO
$ docker network ls
O'l c
0 NETWORK ID NAM E DRIVER
ï::::: c
>-
o.. c 5e9bb5166bel swarm -net overlay
u
0 ·3ù 78286be3able bridge bridge
:::;
"O 53e82elb3384 none nul l
0
.... 64a36a3c4672 host hos t
c.
~
~
:::;
Un réseau de type overlay nécessite pour fonctionner quelques prérequis qui ont
rS
1 été satisfaits automatiquement en construisant notre cluster :
"O
0
c
8 • un registre de service : en effet, Docker l'utilise pour stocker des informations
(Ç) sur le réseau. Nous pouvons d'ailleurs nous en rendre compte via l'interface web
Chapitre 11. Docker Swarm

de Consul en allant dans Key/value, puis docker/network/v 1.0. Nous retrouvons,


par exemple, la liste de n os endpo ints et de notre réseau overlay ;
• les différents hôtes doivent bien sûr avoir accès au service de registre ;
• les démons Docker doivent être configurés avec les options suivantes :
cl uste r -store et -- clus t er- advertise. R appelez,vous que nous les avons
passées en paramètre à Docker Machine pour configurer notre démon.

Notre réseau étant prêt, n ous allons pouvoir maintenant déployer quelques
conteneurs devant fonctionner de concert. Nous allons pour cela déployer un serveur
Gitlab.

Au contraire de notre serveur Gitlab du chapitre consacré à l'intégration continue,


celui que nous allons créer se basera sur l'image sameersbn/gitlab qui nécessite deux
conte neurs additionnels: un pour la base de données (postgreSQL) et un pour le
registre clé/valeur (redis). Nous utilisons ici cette image à des fins didactiques pour
disposer facilement d'une application multi,conteneurs simple à déployer.

Commençons tout d'abord par notre conteneur de base de données:

$ eval $(doc ker -mac hin e env -- swarm swa rm -mas t er) #Nous uti l is ons not re Swarm
Mas ter
$ docker run --name git la b-postgresq l -d - -net=swarm -net - -env
'DB_NAME=g i t l abhq_producti on ' - -env 'DB_US ER=gi t l ab' --env 'DB_PASS=pass111ord'
- -env 'DB_EXTENS ION=pg_trgm' sameers bn/pos tgresq l : 9. 4- 17

Quelques points importants à noter :


• nous attach ons notre conteneur à notre réseau overlay swarm,net. Il sera ainsi
atteignable par tous les autres conteneurs du réseau simplement par son nom
d'hôte « gitlab,postgresql » ;
• n ous passons un certain nombre de variables d'environnement nécessaires à
-0 cette image (sameersbn/postgresql:9.4, 17 1) pour son script [Link], telles
0
c
::i
que le nom de l'utilisateur et le mot de passe pour la base de données.
0
\.0
.-t Démarrons ensuite notre conteneur redis de la même manière, en n'oubliant pas
0
N de l'attacher aussi au réseau swarm,net :
@
.......
..c
O'l
ï:::::
1 $ doc ker r un --n ame gi t l ab - red i s -d --n et=swarm- net sameersbn/red i s :la t est
>-
0.
0 Il ne nous reste plus qu'à instancier le conteneur contenant Gitlab lui,même :
u

$ doc ker r un -- name git la b -d -- net=swarm -net -p 10022 :22 -p 10080 :80 -- env
'GITLAB_PORT=l 0080' -- env 'GITLAB_SSH_PO RT=l 00 22' -- env
1 'GITLAB_SECRETS_DB_K EY_BASE=cdsp5439850' --env 'DB_HOST=gi t l ab-postgres ql ' - -env

1. h ttps://h [Link]/r/sameersbn/postgresq1/
11.3 Déployer une application sur un cluster Swarm

1
DB_PASS=password 1 -- env 1 DB_US ER=gi tl ab 1 -- env 1 REDIS_HOST=gitla b-red i s 1
1 sameersbn/g i tlab :8.6.l

De nouveau:
• nous avons attaché ce conteneur au réseau swarm~net ;
• nous avons défini les variables d'environnement n écessaires : DB_HOST et
REDIS_HOST sont particulièrement intéressantes car ce sont les noms d'hôtes
des deux conteneurs que nous avons créés précédemment. Ces variables sont
remplacées dans les différents fichiers de configuration de Gitlab pour les noms
d'hôtes de la base de données et du registre clé/valeur.

En listant nos conteneurs, nous voyons qu'ils ont été répartis par Docker Swarm
sur les différents nœuds de notre cluster :

$docker ps --format "table ( ( . ID} } ( ( .Por ts} } {( . Names}} " -f name=gitla b*


CONTAINER ID PORTS NAM ES
8520b0fefc96 6379/t cp swarm -node-01/gi t l ab -redis
Olb465148718 5432/t cp swarm-node-02/gi t l ab-postgresql
333596179afl 443/tcp . 192 . 168 . 99 .1 12:10022->22/tcp .
192 .1 68 . 99 .1 12:10080 ->80/ tc p swarm -mas t er/gi t lab

Notre serveur Gitlab est disponible à l'adresse [Link] ud_du_conteneur_


gitlab>:l0080, soit dans notre cas http:l/[Link]:10080.
Gitlab ..
Pleue cœ.ate e p.1ssword for your new account

Gitlab Community Edition Change you r password


Open source software to colla borate on code Newpusword

Manage git repositories with fine grained access controls that keep Conf1rm new p115$word

your code secure. Petform code reviews and enhance collaboration


with merge requests. Each project can also have an issue tracker and a
wiki.
MNH1.1"1
"O
0
~
Didn't reœive confirmation instructions?
c ,.,
:::i AJready have login and password? Si111 ln
"O
0 [Link];
\.0 Expl<n Help About Gitlab
.-t
0
.,.,
~

N
'1;:
@ ·c
....... [Link]; Figure 11 .5 - Application Gitlab
.c CO
O'l c
0
ï::::: c
>-
o. c Nous pouvons aussi, bien sûr, ut iliser Docker Compose pour définir une application
u
0 ·3ù multi~conteneurs répartie sur plusieurs hôtes. Cette approche est même, avec quelques
:::;
"O
0
....
c.
limitations 1, totalement supportée par Docker Swarm.
~
~
:::;
rS
1
"O
0
c
8
(Ç) 1. h ttps://[Link]/compose/swarm/
Chapitre 11. Docker Swarm

Reprenons directement notre exemple ci-dessus et c réons un fichier docker-


[Link] pour représenter notre application 1. Reportez-vous au chapitre consacré
aux applications multi-co nteneurs pour plus de détails sur Docker Compose.

Vous trouverez le fichier complet dans le dépôt Git :


[Link]

Plaçons-n ous dans le réperto ire où se trouve ce fichier et utilisons simplement la


commande suivante :

$ doc ker- compose - -project -n ame=gitl ab up -d


Creating network "gitlab_defaul t" with the def ault driver
Crea ti ng gi t la b_r ed is_l

Creating git l ab_g i t l ab_l

Creati ng git la b_postgresql _l

Que fait Docker Compose ?


• il crée tout d'abord un réseau dédié pour notre application de type overlay avec
le nom « gitlab_default ».Nous n'avons plus besoin de le créer manuellement
car Docker Compose s'en charge directement ;
• il crée ensuite nos trois conteneurs, les répartit ensuite sur les différents nœuds
de notre cluster e t les attache au réseau créé précédemment.

Nous venons donc de déployer notre applicatif sur plusieurs hôtes et de manière
transparente.

En résumé
Dans ce chapitre, nous avons pu mettre en œuvre Swarm, le logiciel de clustering
l:l
0
c Docker à la base de l'offre CaaS de Docker. Nous avons vu comment instancier
:::i
0 une architecture à plusieurs nœuds s'appuyant sur un service de découverte comme
\.0
.-t
C onsul. N ous nous sommes enfin attachés à montrer le potentiel des filtres et des
0
N stratégies de déploiement pour influencer la distribution des conteneurs sur les
@ différents hôtes.
.......
..c
O'l
ï:::::
>-
0.
0
u

1. Ce fichier est basé sur celui proposé à [Link] quick-start.


Nous l'avons juste légèrement adapté pour fon ctionner avec la nouvelle version 2 du format de
Docker Compose.
Conclusion :
un potentiel en devenir

À travers les différents chapitres de ce livre, nous nous sommes attachés à donner une
vue aussi complète que possible de ce qu'est aujourd'hui Docker et la technologie des
conteneurs. En plus d'une présentation purement fonctionnelle, nous avons étudié
des exemples plus complexes et plus opérationnels.
Le lecteur aura sans doute compris la portée de cette petite révolution. Nous n'en
sommes qu'aux prémices de changements qui mettront probablement plus de dix ans
à se faire sentir dans le quotidien des départements informatiques des entreprises.
Commençons par un bilan des domaines d'application que nous avons abordés
précédemment.

"'Cl
0
c::
:::i
0
\.0
.-t
0
N
@
.......
..c::
O'l
·;::
>-
0..
0
u
LES DOMAINES D'APPLICATIONS EXISTANTS

Le tableau ci~dessous liste les domaines d'application de la technologie des conteneurs


présentés dans ce livre :
Domaine d'application Description I chapitre du livre
Distribution d'application Nous l'avons abordé à diverses reprises dans ce livre (dès le
chapitre n
Le DockerHub est aujourd'hui le lieu de publication de nombreuses
images de base par des organisations open source (citons Apache,
Nginx, MySQL, etc.) mais aussi, plus marginalement, par des sociétés
commerciales.
De nombreux éditeurs commencent à considérer Docker et son
registry public comme le centre de téléchargement officiel de services
logiciels.
Il reste encore à travailler le modèle de sécurisation de cette
distribution, mais Docker Content Trust (présenté dans le chapitre 8)
apporte les bases d'un mécanisme de signature fiable.
Conditionnement de C'est probablement l'usage le plus commun de Docker aujourd'hui.
modules applicatifs pour Docker, au même titre que Vagrant (que nous avons présenté dans
le support du cycle de le chapitre 2), permet de conditionner des environnements de
développement développement ou d'intégration pouvant être détruits et reconstruits
à loisir.
Le chapitre 10 présente d'ailleurs un exemple complet de chaîne
d'intégration continue.
Docker offre enfin un mode de conditionnement des logiciels
facilitant le transfert en exploitation (comme nous l'avons expliqué
dans le chapitre 1).
Construction d'architectures C'est le propos de solutions CaaS <pour Container As A Setvice) qui
à micro-services sont décrites dans le chapitre 2 puis, à travers un exemple complet,
dans le chapitre 9 et le chapitre 11 .
Il s'agit sans aucun doute d'une nouvelle manière de considérer le
développement d'applications. Néanmoins, celle-ci mettra du temps
à s'installer dans les entreprises. La rupture que cette approche
impose est difficilement compatible avec les existants plus classiques.
"'Cl À l'inverse, pour toute entreprise d'édition de logiciel SaaS ou encore
0
c pour une startup Internet, l'architecture à micro-service devrait être
:::i
0
une option privilégiée.
\.0 Notons enfin que la solution PaaS OpenShift <[Link]
.-t
0 corn/) de RedHat s'appuie solidement sur Docker et Kubernetes.
N
@
.......
..c Domaines d'application actuels de Docker
Ol
ï:::::
>-
0.
0
u
Les applications décrites ci~dessus sont déjà une réalité. Les offres CaaS d'Ama~
zon, G oogle ou Microsoft, ou encore l'architecture distribuée de Spotify (l'un des
utilisateurs emblématiques de Docker) ne sont plus des prototypes.
Mais nous pensons que d'autres applications de Docker peuvent encore être
développées.
De nouvelles applications pour les conteneurs - - - - - - - - - - - - - - - - - - - 1 301 I
DE NOUVELLES APPLICATIONS POUR LES CONTENEURS

Bien que ces usages ne soient encore que balbutiants (ou encore en maturation), nous
pouvons déjà entrevoir d'autres usages possibles pour Docker.
Domaine d'application Description
Bus d'intégration La plupart des ESB sont aujourd'hui construits sur la base d'une
logique de middleware relativement centralisée. Dans la pratique, il
s'agit de moteurs de workflow plus ou moins complexes associés à
des message queues <pour l'asynchronisme) et à des connecteurs.
Ce type d'architecture se prend parfois un peu les pieds dans le
tapis en imposant des modèles complexes de distribution de charge.
Par ailleurs certaines intégrations nécessitent des configurations OS
spécifiques qui sont souvent difficile à répliquer <et nécessitent parfois
de dédier une machine pour un connecteur).
Des initiatives comme Dray ([Link] proposent d'implémenter
des workflows sur la base de processus encapsulés dans des
conteneurs indépendants. L'avantage de ce type d'approche est
d'offrir une isolation forte de chaque étape du workflow <y compris
pour ce qui concerne les ressources système) tout en permettant
d'implémenter des configurations OS très spécifiques pour des
connecteurs exotiques.
Déploiement d'application Docker est déjà un moyen de distribution d'application sur le serveur.
sur le poste client Kitematic <que nous avons abordé dans le chapitre 3) offre une
interface graphique pour lancer des applications Docker sur son
poste client Windows ou Mac OSX.
Docker pourrait-il devenir un moyen alternatif aux package managers
et autres Windows installers pour déployer des applications sur le
poste client ?
Les deux prérequis sont de disposer d'une version native de Docker
pour ces deux OS desktop, ce qui est pratiquement le cas.
Le second prérequis sera de disposer d'images natives pour ces OS
capables d'exposer une interface graphique sur l'hôte.
Documentation Comme nous l'avons vu dans le chapitre 8, il est possible d'ajouter
automatique d'architecture de la méta-information aux images Docker par l'intermédiaire
"'Cl
de l'instruction LABEL. Par ailleurs, la commande docker i nspect
0 permet aussi de visualiser sous une forme JSON de nombreuses
c ~
,.,
:::i
"O
informations sur une image ou un conteneur.
0 [Link];
\.0 L'exploitation de cette méta-information est à la base des interfaces
.-t ~
0 V graphiques (pour le moment sommaires) des solutions CaaS.
N V
'ii Pour peu qu'un standard de méta-information pour les images
@ ·c
....... [Link];
Docker émerge et que le pattern « micro-services » soit implé-
..c CO
menté, on pourrait envisager des architectures auto-descriptives. La
O'l c
0
ï::::: c documentation (les dépendances, les services exposés) serait alors
>-
o. c contenue, non plus dans des documents, mais dans l'environnement
u
0 ·3ù d'exécution lui-même.
:::;
"O
0
....
c.
~
~
:::;
Autres applications potentielles pour Docker
rS
1
"O
0
c
8
(Ç)
-
LES DEFAUTS DE JEUNESSE DE DOCKER
Aussi intéressant que puisse être Docker, il faut reconnaître qu'il s'agit encore d'une
solution présentant des défauts de maturité. C eux,ci se corrigent peu à peu, mais
certains sont encore difficilement acceptables pour un exploitant prudent.
Sous C entOS, par exemple, un yum update de Docker provoque l'arrêt du Docker
engine et de tous ses conteneurs 1 • Dans certaines conditions, il arrive que les montages
de répertoires du host donnent, à l'intérieur du conteneur, une image incorrecte de
l'état des fichiers.
En dépit de ces défauts (bien référencés), l'usage de Docker en production s'accroît
chaque jour. Les éditeurs qui adoptent les conteneurs (et Docker en particulier) sont
nombreux et motivés. On ne peut donc douter que les avantages surpassent déjà les
incon vénients qui, par ailleurs, sont souvent surmontables pour peu que l'on s'appuie
sur une architecture adaptée.
Nous sommes con vaincus que Docker Inc. a semé en quelques années les germes
d'un changement profond. Cette petite startup française devenue l'une des valeurs
montantes de la Silicon Valley saura,elle en retirer les fruits ?
Difficile d 'en être certain. Le monde IT est très cruel avec les nouveaux entrants
dans le domaine des logiciels d'infrastructure, mais il ne fait aucun doute que des
géants comme Google, Microsoft ou Amazon ont déjà su tirer parti des avantages
technologiques des conteneurs.
Que Docker soit connu dans quelques années comme le nom d 'un projet open
source ou comme une société profitable du NASDAQ est difficile à prédire, mais il est
certain que nous utiliserons (peut,être sans le savoir) de plus en plus de conteneurs !

-0
0
c
:::i
0
\.0
.-t
0
N
@
.......
..c
O'l
'i:
>-
0.
0
u

1. h ttps://[Link]/docker/docker/issues/2658
Index

Les commandes apparaissent dans l'index en police à espacement fixe. Les commandes Docker
sont en minuscul es et les commandes Dockerfile sont en MAJUSCULES.

A CU 33, 123
cloud 45
AOD 167
cluste ring 23, 281
agent TI
déploiement d'application 292
AmazonAWSTI
CMD 158
Amazon ECS 45
CNM 234
Ansible 29, 48
commit 142
Apache Marathon 43
composition TI
Apach e Mesas 43
API Docker 258 Consul 285
API Docker Remote 68 Container as a Service Voir CaaS
application multi-conteneurs 217, 230 Container ID 100
ARG 192
conta iner layer î7
Atomic 8,22,85 [Link]
création de la VM89 accès 103
attach 138 arrêter 99
autorité de certification 203 clustering TI
Azure Container Service 46 commandes de gestion 136
communication 239
composition TI
"'Cl
0
B connexion. 103
c ~
,.,
:::i
"O Boot2Docker TI couche î7
0 [Link];
\.0 bridge 236 création. 98
.-t ~
0
N
V
V build 119, 141 création. d'une image 114
'ii
@ ·c cycle de vie 97, 132
B
....... :::;
dans une machine virtuelle 8
..c
O'l
ï:::::
CO
c
0
c
c définition 1î
>- c
o.
0 ·3ù CaaS 27, 12, 34 démarrage 98
u :::;
architecture 32 écosystème 20
"O
0
....
c. déploiement d'applications 29 fondations 9
~
~ solutions 35, 46 image TI,97
:::;
rS cache 155 infrastructure 25
1
"O
0
CentOST5,58 intermodal S
c
8 CGroups ÎÜ, 133 montage d'un répertoire 108
(Ç) Ch ef46 moteur d'exécution 20
multiple IT, 231 Docker Con tent Trust 206
orchestration TI Docker daemon 55, 68
OS spécialisé TI Docker Datacenter35
suppression 102 Docker Engine 9, 20, 143
conteneurisation 3 Docker H ub14
COPY 171
Docker in Docker 252, 258
copy on write 18
Docker Machine 56, 74, 287
CoreOS 8, TI, 45
commandes de gestion du démarrage 85
COW Voir copy on write
installation 74
cp 139
prise en main 75
create 102, 134
doc ker -mac hine create 76
docker -mac hine env 84
D docker-mach i ne inspect 8:3
daemo n 128 docker -mac hi ne l s 82
Data Center Operating System 24, 34, 43 Docker Remo te API 68, 203, 254
data container 233, 259 Docker Swarm 36, 282
data volume ï9 Docker ToolBox 55
DCOS Voir Data Center Operating System Docker Trusted Registry 36
démon 68, 128
Docker UCP 36, 38
déploiement 271
Dockerfile 115, 147, 183
stratégies 294
commentaires 150
devicemapper 19, 92
instruction format exécution 149
di ff 139
Docker instruction format terminal 148
alternatives TI instructions 150
avantages TI modèles d'instruction 147
clien t 66, 123 programmation 116
commandes système 128
configuration SSL 205
construction image originale 110 E
démon 128
"'Cl ENTRY PO IN T 160
0
c groupe 68
:::i
installation 55 ENV 183
0
\.0
.-t
installation automatisée 63 etcd 39, 45
0
N installation avec Docker Machine 77,Sî events 130
@ installation sur un hôte 73 exec 104, 137, 229
.......
..c intégration continue 249 export 140
O'l
'i: manipulation des images 141 EXPOSE 163
>-
0.
0 options des commandes 125
u réseau 234
réseau bridge 237 F
sécurisation 202
variables d'environnement 124 Fedora Atomic 8, 85
Docker A PI 252 Fleet 45
Docker Compose 35, 245 forward 239
commandes 248 FROM 150
Index

G libnetwork 234
ligne de commande Voir C U
GitLab 251, 256, 262
l oad 143
Google Con tainer Engine 45
load balancer 42
Gradle 253, 265
l ogi n 144
guest additions 60
l ogout 144
l ogs 136
H LXCD
hi story 119, 142
HyperV6
M
MAINTAINER 152
1
mappage des ports 165
IaaS 26, 27, 32 MariaDB 223
déploiement d'applications 28 micro-service 34, 42
limites29
image IT
de base 98 N
i mages Tiî, 117, 142
Namespaces TI, 235
i mport 143
i nfo 129 networ k 146
Infrastructure as a Service Voir IaaS Nginx 98, 220, 231, 244
i ns pect 106, 132 node 4î, 283
intégration continue 249 Notary 206
Iptables 240

0
J ON BUI LD198
OpenSSH 164
OpenVZD
"'Cl K orchestration 23, 245
0
c ~
,., overlay 295
:::i kemel7
"O
0 [Link];
\.0 ki 11 99, 132
.-t ~
0
N
V
V Kitematic 64 p
'ii
@ ·c kube-proxy 40
....... [Link]; pause 133
..c CO kubelet 40
O'l
ï:::::
c
0
Kubemetes 39 persistance19
>- c
o. c PHP-FPM 221, 232, 244
0 ·3ù architecture 39
u :::; modèle réseau 4T pod4T
"O
0
....
c. Kubemetes Contrai Plane 4T port 141
~
~
port IP 109
:::;
rS ps 100, 130
"O
1 L pu ll 144
0
c
LABE L 186 Puppet 29, 46, 52
8
(Ç) libcontainer 9 push 144
13061 Docker

R T
registry 14, 143 ta 9IB
privé 209 top 140
registry cloud16
rename 138
réseau'i34 u
restart 132
Rkt45 Ubemetes43
rm 102, 133 UCP Voir Universal Control Plane
rmi 112, 142 union file system Ï Ï
Rtk2T Universal Control Plane 36, 38
RUN 153 unpause 133
run 98, 104, 134 update 134
RunC2T USER 189

s V
save 143
scheduler4f, 44 Vagrant~
search 144 variables d'environnement 124
service de découverte 283 version 129
start 101, 132 VirtualBox 6, 9, 57, 81
stats 129 virtualisation matérielle 6, 27
stop 99, 132 VMWare6
STOPSIGNAL 201 volume 19, fil
storage driver19,93 création105"
Supervisor 224 VOLUMEl l i
Swarm282 volume 146
architecture 37
cluster 284
filtres 293
master 283
w
mode esclave184 wait 133
mode maître 284 Windows Nano Server22
node 283 Windows Serveur 201610
Symfony 220, 228, 243 WORKDIR 187

Vous aimerez peut-être aussi