Niveau 1 : Introduction à Docker et docker-compose
Auteurs
Assemblé et rédigé par Martin Souchal, d'après les travaux de Fabrice Jammes et David Chamont

This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
Introduction
Qu'est-ce qu'un conteneur ?
L'industrie utilise aujourd'hui massivement les machines virtuelles. Ces machines exécutent des applications au sein d'un système d'exploitation "invité", qui exploite un matériel "virtuel" émulé par le système d'exploitation "hôte" de la vraie machine.
L'isolation entre invité et hôte est excellente, mais se paie cher par l'émulation du matériel virtuel et l'exécution d'un système d'exploitation invité complet.
Les conteneurs peuvent être vus comme une variante plus légère : en exploitant plus directement les couches basses du système hôte (noyau), les conteneurs fournissent une isolation presque aussi forte que les machines virtuelles, à un cout en performance beaucoup moins élevé.

Microservice
Dans l'écosystème des conteneurs, on parle de microservice : dans un conteneur il n'y a qu'un seul service (ou application). Ce n'est pas obligatoire mais cela fait partie des bonnes pratiques, et dans lorsque l'on parle d'orchestration de conteneurs cela devient obligatoire.
Qu'est-ce que Docker ?
Il s'agit d'un ensemble d'outils qui facilitent l'écriture, le partage et le déploiement d'applications au sein de conteneurs. Les conteneurs Docker sont originellement dédiés au monde linux. On dispose maintenant de distributions permettant de faire tourner ces conteneurs également sur des machines hôtes MacOSX ou Windows, par le biais de machines virtuelles légères.
Un peu de vocabulaire
Image
Dans le contexte de Docker (comme dans celui des machines virtuelles), on appelle "image" une description statique de conteneur, une sorte de photographie de machine, que vous pouvez échanger avec vos collaborateurs, et à partir de laquelle on peut instancier et exécuter des conteneurs. Pour optimiser le stockage, les images Docker sont découpées en couches, et se réutilisent les unes les autres pour éviter un stockage en double des couches communes.
Conteneur
Une machine virtuelle légère, chargée en mémoire, que l'on peut démarrer, arrêter, redémarrer, détruire... Un conteneur s'instancie à partir d'une image. Si il est correctement configuré, un conteneur peut-être redémarré sans perdre les modifications apportées à son système de fichiers interne. Pour repartir à zéro de l'image de départ, il faut détruire le conteneur et en recréer un nouveau.
Registre
Entrepôt ou l'on stocke des images. Une fois Docker installé, vous avez un registre local sur votre machine, ou seront stockées toutes les images que vous utilisez. Il existe aussi des registres destinés à partager des images entre utilisateurs, tel que le registre central officiel de Docker, qui est consultable à l'adresse http://hub.docker.com/. Chacun peut y créer un compte et y stocker ses images gratuitement (tant qu'elles sont publiques).
Premiers pas
Si vous avez installé Docker et vérifié qu'il fonctionnait,
vous avez sans doute déjà exécuté un conteneur hello-world :
Pour lancer ce conteneur, Docker a besoin de l'image correspondante. Si elle n'est pas déjà dans votre registre local, elle sera préalablement téléchargée depuis un registre (il faut du réseau). Vous auriez pu le faire explicitement avec cette commande :
Si vous voulez connaître la liste des images actuellement disponibles sur votre machine locale :
Si vous voulez connaître la liste des conteneurs actuels de votre machine locale :
En réalité, la commande ci-dessus, par défaut, ne montre que les
conteneurs en cours d'exécution. Si vous voulez les voir tous,
ajouter l'option -a :
Surprise, notre conteneur hello-world, bien qu'ayant terminé sa tâche, est toujours là !
Vous pouvez le relancer, avec l'option -i pour que les affichages soient bien redirigés
dans le terminal courant. Et il ne faut pas utiliser le nom de l'image d'origine,
mais l'identifiant unique du conteneur, ou le nom unique attribué aléatoirement par Docker :
Une image est configurée pour exécuter une certaine commande au
lancement du conteneur. A la fin de la commande, le conteneur s'arrête.
Le conteneur disparait alors de l'affichage de docker ps, mais il est
toujours là, et visible par docker ps -a.
Un peu de ménage
Pour éliminer un conteneur qui n'a plus d'utilité, une commande "rm" fera l'affaire :
Nous n'avons pas encore rencontré ce cas de figure, mais un conteneur de type "démon" peut
être en cours d'exécution, même si il n'est pas actuellement connecté à un terminal. Pour
supprimer un tel conteneur, il faut d'abord l'arrêter à l'aide d'une commande docker stop,
ou bien ajouter l'option -f à votre commande docker rm.
Par défaut, lorsque la commande principale d'un conteneur est terminée, ce dernier est arrêté, mais il n'est pas détruit pour autant. En effet, l'utilisateur pourrait vouloir le redémarrer et s'y attacher, notamment pour inspecter le contenu de ses fichiers internes (lors de la destruction d'un conteneur, toutes les modifications apportées aux fichiers internes sont perdues).
Si vous préférez détruire directement un conteneur à la fin de sa commande principale,
afin de ne pas polluer votre ordinateur avec des centaines de conteneurs dormants, vous
pouvez utiliser l'option --rm lors du lancement :
Par ailleurs, à force d'essayer des images différentes, vous finirez par manquer
de place dans votre registre local, et il faudra sans doute faire du ménage dans
les images. Vous connaissez déjà la commande docker images qui vous en
dresse la liste. Pour en supprimer une, vous avez docker rmi. Essayez :
Démarrer un conteneur avec une commande alternative
A chaque conteneur est associé une commande principale. Lorsque vous créez le conteneur, la commande principale est exécutée, et lorsque cette commande se termine, le conteneur s'arrête (mais ne disparait pas).
Lorsque vous démarrez un nouveau conteneur, vous pouvez aussi choisir explicitement une commande à exécuter, au lieu d'utiliser celle par défaut. Par exemple, si je veux faire un curl sur l'url ifconfig.me, je vais le faire ainsi :
Nous allons tester avec une distribution linux legère (alpine linux), je vais demarrer un conteneur et lancer une commande à l'intérieur de ce dernier :
Manipuler le conteneur comme on manipulerait un processus
Comme nous l'avons vu précédemment, un conteneur peut-être démarré, arrêté... mais aussi redémarré, tué... un peu comme un processus.
Les commandes stop ou kill se traduisent par des signaux SIGTERM ou SIGKILL
transmis à la commande principale en cours d'exécution dans le conteneur.
Pour retracer l'historique d'un conteneur, et éventuellement rechercher la source
d'un problème, vous disposez de la commande logs:
S'inviter dans un conteneur en cours d'exécution
Un conteneur, même si il lance initialement une commande principale, est tout à fait capable d'exécuter d'autres processus concurrents.
Ainsi, à supposer qu'une image dispose de l'interpréteur bash, on
peut très bien "s'inviter" dans un conteneur pour aller inspecter le
contenu de son système de fichier, à l'aide de la commande
docker exec. Par exemple, avec l'image nginx qui lance un serveur web
en tâche de fond :
Vous pouvez également modifier les fichiers internes du conteneur, tels que les fichiers html ci-dessus, ou procéder à des installations :
Mais n'oubliez pas qu'à moins de vous placez dans un volume spécial, tout ce que vous allez faire sera perdu quand le conteneur sera détruit.
Communication entre conteneur et hôte
Par défaut, les conteneurs sont isolés de leur système hôte, ce qui peut devenir un problème dès que l'on veut coordonner un système de plusieurs conteneurs. Vous avez trois possibilités pour faire circuler de l'information entre hôte et conteneurs :
-
La définition par l'hôte de variables d'environnement qui seront transmises au conteneur au moment de son lancement.
-
Le renvoi de ports (port forwarding) permet de reproduire sur l'hôte des ports réseau des conteneurs.
-
L'utilisation de volumes de données partagés, qui permet à un conteneur d'interagir directement sur le système de fichiers de son hôte.
Renvoi de ports
Lorsqu'on lance un conteneur nginx, on aimerait évidemment pouvoir consulter les pages web servies,
depuis un navigateur de la machine hôte. Pour reproduire sur la machine hôte le port 80 du conteneur,
on peut lancer le conteneur avec cette option -p :
Vous pourrez ensuite vérifier la présence du serveur web en consultant l'adresse http://localhost/.
(ATTENTION : selon votre machine et votre système d'exploitation, il peut être nécessaire de
remplacer localhostpar le numéro IP de votre machine, ou de la machine virtuelle qui permet
d'exécuter le noyau linux.)
On peut aussi, à la faveur du renvoi, changer de numéro de port :
A présent l'adresse http://localhost/ ne répond plus, mais http://localhost:8080/ oui. On
retiendra l'ordre des numéros de ports : d'abord celui sur l'hôte, puis celui au sein du conteneur.
Partage de fichiers
Si le conteneur est détruit, ses fichiers le sont avec lui. Dans le cas d'un serveur web, on aimerait que le contenu du site web soit stocké sur la machine hôte, et que le conteneur nginx ne serve qu'à lancer un serveur temporaire, pour vérifier le rendu des pages. Créez une page de test :
Voyons maintenant comment installer un lien, de sorte que notre conteneur voit ces fichiers, à
l'aide de l'option -v(volumes). Au sein du conteneur, le serveur s'attend à trouver ses
fichiers html au sein du répertoire /usr/share/nginx/html. Nous obtiendrons l'effet voulu
ainsi :
A nouveau, vous pouvez vérifier la présence du serveur web en consultant l'adresse http://localhost/.
Et vous pouvez également modifier html/index.htmlet recharger la page pour constater l'effet
produit.
Comme pour les ports, on donne d'abord le chemin sur la machine hôte, puis le chemin au sein du conteneur.
Le chemin local doit être un chemin absolu, d'où la présence de $PWD (mais vous auriez pu mettre
directement le chemin complet). On notera également que le répertoire ainsi lié masque l'éventuel
répertoire de même nom dans le conteneur (/usr/share/nginx/html).
Téléchargement d'une image MariaDB
Lorsque vous voulez utiliser une image, elle d'abord recherchée dans votre registre local, puis dans le registre central par défaut, appelé Docker Hub. Dans ce dernier, on trouve notamment toutes les images officielles des produits informatiques libres, dont celle de la base de données MariaDB.
Lancement du premier conteneur MariaDB
Ci-dessous, l'option --name permet de préciser explicitement le nom donné à un conteneur,
plutôt que laisser Docker le choisir au hasard. L'option -epermet de définir une variable
d'environnement au sein du conteneur. L'option -d permet de lancer le conteneur en tâche
de fond ("detached").
Allons inspecter quel est l'environnement shell de ce conteneur, en lancant dans notre conteneur mariadbtest
une commande secondaire bash avec pour seule instruction printenv :
Récupérer des images du Hub Docker ou de Gitlab
Le registre central de docker met à votre disposition une très grande quantité d'images
prêtes à l'emploi, chacun avec éventuellement de multiples étiquettes. Vous pouvez utiliser votre navigateur pour
parcourir le site web, ou bien utiliser la commande en ligne docker search pour trouver des images, que vous
pourrez ensuite récupérer LOCALEMENT par docker pull.
Warning
soyez vigilant de ne pas télécharger n'importe quoi, au risque d'introduire un virus sur votre machine.
Les images qualifiées d'official sont validées par Docker.
Warning
Les pulls d'image en provenance de Docker Hub sont maintenant limitées pour les utilisations anonymes. Pour lever cette limite vous devez avoir un compte sur Docker Hub. (cf docker-hub )
Pour les utilisateurs d'instances Gitlab, chaque projet peut également faire office de registre Docker. Pour voir ce qui est disponible, consultez l'onglet "registry" d'un projet.
Construire sa propre image
Les images sont des descriptions statiques de conteneurs. Précedemment
nous avons téléchargé l'image MariaDB et nous avons demandé à Docker de
créer un conteneur basé sur cette image. Pour voir la liste des images
disponibles sur votre ordinateur, tapez docker images.
A présent, nous allons fabriquer notre propre image.
Voici un exemple de fichier Dockerfile :
Les conventions de nommage de docker imposent d'utiliser le nom "Dockerfile" (sans extensions).
Toutes les ressources nécessaires à notre fabrication ont été placées
dans le sous-répertoire niveau1. La "recette" à appliquer est donnée
dans le fichier Dockerfile, qui est abondamment commenté.
En résumé :
* FROM : une autre image servant de base.
* RUN : permet d'exécuter une commande (par exemple un apt-get install).
* WORKDIR: définit le répertoire dans lequel débutera l'exécution.
* ADD: permet de copier dans l'image un fichier de la machine hôte.
* CMD: commande à exécuter au lancement du conteneur.
Construisez ainsi votre image, qui sera nommée webserver
(option --tagpour le nommage) :
Utiliser l'image précédente
Démarrer un conteneur webserver
On notera l'option --detach=true (équivalente à -d), qui permet de laisser
tourner le conteneur en tâche de fond.
On notera également l'option --publish 8000:8000 (équivalente à -p 8000:8000)
qui permet de renvoyer le port 8000 du conteneur sur le port 8000 de la machine
hôte. Ainsi, en consultant "http://localhost:8000" depuis votre navigateur
web habituel, vous devriez voir ce que diffuse le conteneur webserver.
Lister les conteneurs en cours d'exécution
Supprimer un conteneur en cours d'exécution
Démarrer un conteneur en le nommant explicitement
Vérifier le nom du conteneur par docker ps.
Utiliser des fichiers html localisés sur la machine hôte
Ici les fichiers html utilisés sont ceux de la machine hôte, grâce à l'option -v qui monte le répertoire $PWD/www en tant que /home/www au sein du conteneur.
C'est un moyen pratique d'associer des données variables à un conteneur.
Consultez à nouveau "http://localhost:8000" depuis votre navigateur
web. Que remarquez vous ? Ici le répertoire monté à l'aide de
l'option -v s'est interposé devant celui qui était dans
l'image.
Les etiquettes (tags)
Un registre peut contenir plusieurs versions de la même image, différenciées
par une étiquette (tag). Cette étiquette peut être un numéro de version ou
une chaine de caractère quelconque. Il n'y a pas vraiment de règle, à part le
fait que l'étiquette par défaut est latest. Ainsi, la commande de construction
donnée en exemple précédemment est parfaitement équivalente à :
Si je préfère créer une version v1, je taperai :
Re-étiquettage
Dans le dernier exemple ci-dessus, vous aurez peut-etre remarqué que grâce à sa
mécanique de cache, Docker n'a pas réellement recréé une nouvelle image, mais
réutilisé celle qui s'appellait webserver:latest pour lui donner un deuxième
nom, à savoir webserver:v1. On aurait pu le faire directement ainsi :
Gestion des étiquettes
Rien n'est contrôlé ni permanent dans l'usage des étiquettes. On peut modifier, redéfinir, écraser à loisirs les images et leurs étiquettes. Donc il faut être très rigoureux dans ses manipulations d'étiquettes, et s'astreindre à un certain processus, sous peine de se perdre dans ses versions d'images.
Partager une image
Jusqu'à présent, nous n'avons fait que télécharger des images sur notre
machine depuis le registre central Docker, par la commande docker pull.
Puis nous avons créé nos propres images. A présent, comment les
partager avec d'autres ?
Distribuer une image sous forme de fichier archive
Il s'agit de la méthode la plus rustre, qui vous permettra de distribuer votre image même en absence de réseau. Pour créer le fichier archive à partir d'une image déjà construite et disponible dans votre registre local :
On peut le faire également directement sur une image d'un registre distant. Le fichier archive peut ensuite être compressé et copié dans une clef USB.
A l'inverse, pour recharger une image dans un registre local, à partir d'un fichier archive, compressé ou non :
Publier une image sur le Hub Docker
Le registre central de docker vous permet de stocker gratuitement une image privée (avec les étiquettes de vore choix), ou autant d'images publiques que vous le souhaiterez.
Après avoir créé un compte <MON-ID> sur le site hub.docker.com, puis un
"dépôt" (repository) <MON-IMAGE>. Il vous suffira de créer localement une image
s'appelant <MON-ID>/<MON-IMAGE>, de vous authentifier à l'aide d'une
commande docker login, puis de faire une commande docker push
pour téléverser votre image :
Publier une image sur Gitlab
Chaque projet d'une instance Gitlab est maintenant
capable de stocker des images Docker. Sur le site web du serveur, l'onglet "Registry" de chaque projet
liste les images stockées, ainsi que les instructions pour les télécharger ou les déposer.
Par exemple, pour un projet public <MON-IMAGE> :
Si le projet est privé, il faut d'abord se logger sur le repository avec votre compte gitlab :
Ensuite il est possible de faire des push ou des pull selon ses droits dans le projet Gitlab.
Optimiser ses images Docker
Découpage de l'image en couches

En apparence, nous manipulons des "images" monolithiques, mais en réalité Docker les découpe en couches réutilisables.
Réutilisation des couches
Si vous construisez tout un système d'images, et que vous souhaitez optimiser l'espace disque que vous utilisez, vous avez tout intérêt à hiérarchiser vos images et à partager tout ce qui peut l'être. La factorisation des couches communes réduira l'empreinte disque.
Limiter le nombre de commandes dans un Dockerfile reduira de fait la taille de l'image, car chaque commande crée une nouvelle couche.
Par exemple au lieu d'écrire :
Ecrire :Multi stage build
Un manifeste peut contenir un environnement de Build et un environnement d'execution (stages) :
Comme on le voit dans cet exemple, on peut copier des fichiers d'un stage à un autre avec la commande COPY.
- On peut contruire chaque stage séparement, notamment a des fins de test ou debug :
- On peut également copier un artefact d'une image externe :
- L'interet est de produire des images les plus petites possibles et ainsi réduire la surface d'attaque et les temps de build.
Exercice
Convertissez le Dockerfile suivant pour utiliser le multi-stage :
Solution
Une solution possible (l'accent est mis sur le passage de l'application à la première étape) :
Optimiser les directives d'un Dockerfile
Dans le Dockerfile donné en exemple au début, regardez l'ordre des directives : à chaque
construction, Docker essaie de ne refaire que ce qui est nouveau et nécessaire. Quand c'est possible,
vous avez tout intérêt à placer en fin de fichier ce qui change le plus souvent. Vos constructions
seront ainsi beaucoup plus facile (et vos images plus petites ?).
Docker compose
La commande docker compose permet de gérer collectivement
un ensemble de conteneurs appelés à fonctionner ensemble. On se placera dans un répertoire
dédié (de votre choix), dont le ficher docker-compose.yml contiendra la configuration
complète de l'ensemble, et toutes les actions vont se faire avec la seule commande
docker compose.
Pour commencer doucement, nous allons faire tourner l'image hello-world non pas à l'aide
de docker run, mais à travers docker compose. Pour ce faire, créez un répertoire tout
neuf dans lequel vous vous placez et vous créez un ficher docker-compose.yml :
Toujours dans ce même répertoire, tapez docker compose up:
Les affichages nous informent de ce que fait Docker:
- Le client Docker contacte le démon Docker.
- Le démon télécharge l'image "hello-world" du hub Docker.
- Le démon instancie un nouveau conteneur à partir de l'image, qui exécute le processus qui affiche "Hello from Docker...".
- Le démon transmet les affichages au client, qui les affichent sur le terminal.
Si le processus ne s'arrête pas de lui-même, tapez CTRL-C.
Bien sur, cet exemple ne démontre pas encore l'intérêt majeur de docker-compose,
qui est de gérer simultanément un ensemble de conteneurs. Nous allons y venir,
mais jetons d'abord un premier regard aux sous-commandes de docker compose.
Un apercu des sous-commandes de docker compose
La commande docker compose travaille sur la base de répertoires. Si vous voulez faire tourner
plusieurs groupes de conteneurs, faites un répertoire par groupe, chacun avec son propre
fichier docker-compose.yml.
En production, on voudra faire tourner les conteneurs en tâches de fond, plutôt qu'en
interactif. Faites le avec l'option -d : docker compose up -d (comme vous auriez
fait docker run -d pour un conteneur isolé).
Pour voir l'état des conteneurs du groupe/répertoire courant, utilisez la commande
docker compose ps:
Les conteneurs en cours d'exécution ont le statut Up.
Pour un arrêt de tous les conteneurs : docker compose stop, voire
docker compose kill.
Pour éliminer tous les conteneurs, ainsi que leurs éventuels volumes internes :
docker compose rm. Cela permet de repartir sur des bases neuves.
Vous l'aurez compris, la commande docker compose reprend la plupart des commandes
d'origine de docker, mais elles les applique à l'ensemble des conteneurs décrits
dans docker-compose.yml.
Configuration à plusieurs conteneurs
Essayons maintenant un scénario plus complexe, ou nous démarrons à la
fois une instance de l'image wordpress et une instance de l'image mariadb
(que nous appellerons wordpress_db), avec un "lien" entre les deux.
Le fichier docker-compose.yml est le suivant :
Au sein du conteneur wordpress, le conteneur wordpress_db apparait en tant que mysql.
Si on lance docker compose up, on verra qu'il manque encore un peu de configuration :
Il manque visiblement la définition de plusieurs variables d'environnement,
ce que l'on peut faire facilement dans docker-compose.yml. Essayez :
L'image mariadb est configurée pour vérifier l'existence de la variable
MYSQL_ROOT_PASSWORD au lancement, et se charge alors de créer une base
de donnée initiale et un compte root avec le mot de passe défini par
MYSQL_ROOT_PASSWORD. Par ailleurs, le conteneur wordpress est capable
de récupérer cette variable de wordpress_db et de s'en servir pour
faire sa propre initialisation.
Pour voir ce qui s'affiche sur le serveur web du conteneur wordpress,
on doit transmettre son port 80 sur un port de la machine hôte, par exemple
8080, afin de pouvoir consulter le serveur à l'aide d'un navigateur de l'hôte,
en demandant l'adresse http://localhost:8080/ :
Utilisation d'un volume partagé
Parce qu'il s'agit d'images officielles, respectant les bonnes pratiques définies par Docker, ces images sont dotées de volumes internes persistents, ce qui permet de retrouver ses données quand les conteneurs sont redémarrés (docker stop, start, restart)... mais pas si vous les effacez (docker rm).
On peut également vouloir placer les documents web dans un répertoire de la machine hôte, afin de préserver ces documents même en cas de destruction du conteneur wordpress :
Pour rendre en compte la modification, il faudra détruire le conteneur concerné avant de le démarrer de nouveau :
Maintenant, vous devriez trouver dans le répertoire ~/wordpress de votre hôte un
sous-répertoire wp_html avec le contenu de votre site. Toute modification faite
depuis l'hôte sera répercutée dans le /var/www/html du conteneur.
Personnaliser les images
En vérité, la commande docker compose up est l'équivalent d'une
commande docker compose build suivie d'une commande docker compose run.
Dans le fichier docker-compose.yml, on peut remplacer l'usage direct d'une
image existante par la construction d'une image personnalisée.
La commande docker compose build détecte et construit ces images
personnalisées.
Essayons à présent de créer une variante personnalisée de mariadb,
dans laquelle on définirait directement la variable MYSQL_ROOT_PASSWORD.
Ceci pourrait se faire au sein d'un sous-répertoire MariaDb contenant
le fichier Dockerfile approprié :
Ensuite, mon fichier de configuration global docker-compose.yml
doit être modifié comme suit :
Ajouter des volumes persistants
Afin de conserver les données utilisées dans un service (par exemple une base de donnée), on peut rendre persistant un volume en lui donnant un nom. Ce volume sera crée sur l'hote et survivra aux modifications du docker compose.
Dans l'exemple suivant on va rajouter un volume mysql pour la base de données et un volume wordpress avec les fichiers web.
Pout lister les volumes présents sur un hote, et les supprimer on utilise la commande
... et un réseau privé
Pour finir de rendre ce docker compose persistant et sécurisé, on peut créer des réseaux virtuels afin de mieux controler la confidentialité des flux. Pour ce faire, il faut utiliser le mot clé "networks" et donner un nom a chaque réseau. Il faut ensuite déclarer dans le docker compose quels services ont accès au réseau :
En résumé :
- Les conteneurs connectés à ce réseau peuvent communiquer entre eux.
- Ils sont isolés du réseau de l’hôte et des autres réseaux Docker, sauf si vous configurez des accès spécifiques.
- "bridge" est le mode réseau par défaut pour les conteneurs Docker sur une machine locale.
Pour aller plus loin
Certaines possibilités de docker compose n'ont pas été traitées :
- échelonner un service :
docker compose scale ... - importations entre fichiers
docker-compose.yml.
Tout ce qui précède fait sens si vous faite tourner vos conteneurs sur un seul hôte, typiquement votre ordinateur personnel. A partir du moment où vous exploitez une grappe de serveurs, il faut vous tourner vers l'orchestration de conteneurs, ce sera l'objet du Niveau 3 de ces Ateliers.
Wrap-up : conteneurisation d'une application complète
Création d'une application Django
Commencez par créer un répertoire vide.
On va ensuite créer un environnement virtuel python dans ce répertoire :
Maintenant activez cet environnement virtuel :
Votre prompt doit maintenant commencer par (django-venv).
Pour vérifier que votre environnement est bien actif, la commande which python doit renvoyer un chemin dans le dossier actuel.
Si tout est bon, on peut maintenant installer Django :
On va maintenant initialiser un projet Django, ici on va l'appeller tp :
Si tout s'est bien passé, vous devez maintenant avoir un répertoire tp qui contient un fichier manage.py. Tapez la commande python tp/manage.py runserver pour lancer Django. Vous pouvez maintenant ouvrir un navigateur sur l'adresse http://127.0.0.1:8000/ et admirer la fusée Django.
On va ensuite personnaliser un peu le code pour afficher le message "Hello, World!". Commencez par créer une application, que l'on va appeller hello dans le projet Django :
Django à automatiquement crée un répertoire nommé hello qui va contenir le code de notre application. On va ajouter les fichiers suivants :
django-tp/tp/hello/urls.py
django-tp/tp/hello/views.py
et enfin
django-tp/tp/tp/urls.py
Maintenant, si tout va bien, vous pouvez lancer le serveur Django qui doit afficher un magnifique "Hello, World!" sur la page http://127.0.0.1:8000/ :
Nous avons maintenant un code en python, utilisant le framework django en local.
Création d'un conteneur
Exercice
écrivez un Dokerfile pour conteneuriser l'application que nous venons de créer.
Solution
Le Dockerfile suivant contient le minimum necessaire pour faire tourner une application Django : nous avons juste besoin d'un fichier requirements.txt pour pouvoir installer les dépendances python. Pour générer ce fichier, lancez la commande suivante depuis votre environnement virtuel python, toujours dans le repertoire tp (qui contient le fichier manage.py :
Ensuite on peut passer à la création de l'image Docker :
Si le build s'est bien passé, il devrait y avoir le message suivant :
1 2 | |
Pour tester le conteneur, il faut lancer l'image que l'on vient de créer :
Véifiez que le message "Hello World" s'affiche bien dans un navigateur à l'adresse http://127.0.0.1:8000/
Votre application est conteneurisée !
Mise en place d'un environnement complet avec docker compose
Exercice
rajoutez une base de donnée dans un service docker compose pour gérer les données de l'application Django. Vous pouvez ensuite ajouter le service django. Dans l'idéal rajoutez des volumes persistants pour la base de donnée et un réseau privé pour la communication entre les django et mariadb.
Solution
Voici un fichier docker compose qui reprends tout ce qui est demandé :
Lancez ensuite cet environnement et connectez vous sur l'interface web.
Sources
- Build, Ship, Run using Docker.
- Docker Hub.
- DigitalOcean.
- DigitalOcean.
- Sebastien Goasguen
- Documentation officielle.
- Exercices DevOps