TP1 : Découverte et prise en main de Docker
Table des matières
Introduction
L’objectif de ce premier TP / labo est de vous permettre de découvrir la notion de “container” et son utilité au travers d’exercices pratiques avec l’outil de conteneurisation Docker.
A la fin de ce TP, vous devez être capable de :
- comprendre les termes “image”, “container”, “publication de ports”, “registre d’images”, “dockerfile”
- démarrer un container avec les paramètres appropriés,
- interagir avec le container via un shell,
- récupérer des informations sur un container en cours d’exécution (adresse IP, ports à l’écoute, …),
- envoyer des requêtes au container en exploitant à bon escient la publication de ports,
- pouvoir utiliser une image soit depuis le système de fichier local, soit depuis un registe d’images,
- créer une image sur mesure depuis un Dockerfile
Lectures préalables
Avant de réaliser ce TP, il est important de vous informer sur la notion de “container”. Pour cela, vous êtes invités à prendre connaissance des chapitres théoriques suivants :
- Chapitre 1 : Virtualisation et conteneurisation. L’objectif est de comprendre les concepts et techniques de virtualisation, la différence entre la virtualisation et la conteneurisation, et les enjeux spécifiques à chacun d’eux. Les sections accompagnées du tag [facultatif] sont des sections qu’il est conseillé de lire mais sur lesquelles vous ne serez pas interrogés.
- Chapitre 2 : Les containers et Docker. Ce chapitre détaille les aspects techniques des containers et de leur fonctionnement. Ici aussi, certaines sections sont marquées du tag [facultatif], cfr ci-dessus.
- Chapitre 3 : Docker en pratique. Ce chapitre présente de manière plus pratique et concrète l’utilisation de Docker. Il vous sera utile pour comprendre les manipulations que vous effectuerez dans ce TP, n’hésitez pas à y revenir régulièrement. Les sections 3.1. à 3.3 vous serons utiles cette semaine, les suivantes serviront pour le second TP.
Vous pouvez également, si vous le souhaitez ou si vous avez besoin de plus d’explications, consulter la documentation officielle Docker.
Installation
Pour utiliser Docker, vous avez deux possibilités :
- Utiliser une machine virtuelle sur laquelle Docker est installé. C’est la configuration recommandée si vous travaillez sur les PCs des labos. Vous pouvez par exemple utiliser la VM GNS3-Admin-I-2022, qui est une distribution Ubuntu sur laquelle Docker est installé. Si vous n’arrivez pas à installer Docker sur votre machine, cette option peut également vous convenir.
- Installer Docker sur votre ordinateur personnel. Pour cela, référez-vous aux instructions d’installation sur la documentation officielle Docker
1. Premier container
1.1. Hello World
Pour vous assurer que Docker est fonctionnel sur votre poste de travail, exécutez la commande suivante : docker run hello-world
Pouvez-vous expliquer avec vos mots ce qui s’est passé suite à l’exécution de cette commande?
1.2. Observer un container
Exécutez à présent la commande : docker container ls -a
Retrouvez les informations suivantes sur le container lancé précédemment :
- Quel est son identifiant ?
- Quel est son nom ?
- Quel est son état ?
- Quel est le nom de son image? Avez-vous vu au point 1.1. d’‘où cette image provenait?
- Quelle commande le container a-t-il exécuté?
- Si vous avez installer Docker Desktop, pouvez-vous retrouver ces mêmes informations dans l’interface graphique?
1.3. Les images
Tapez à présent la commande suivante : docker image ls
- Quelles informations voyez-vous? Quel est le lien avec ce que vous avez observé auparavant?
- Comparez l’output de cette commande avec la vue correspondante de l’interface graphique.
- Essayez de trouver la commande qui vous permettra de supprimer cette image. C’est une bonne idée de ne pas conserver les images non utilisées sur votre système de fichiers : même avec la mutualisation de couches, elles prennent de l’espace sur le disque!
2. Utiliser un container
Nous allons à présent voir comment il est possible d’interagir avec un container. Pour cela, nous allons prendre un simple container basé sur une distribution Linux Ubuntu, et interagir avec lui comme nous le ferions dans le cas d’une machine “normale” ou d’une machine virtuelle, via un shell interactif.
2.1. Interagir avec un container
Lancez un container Ubuntu avec la commande suivante : docker run -it ubuntu bash
Normalement, après téléchargement de l’image ubuntu, le container se lance et vous obtenez un “prompt” dans votre console indiquant que vous pouvez interagir avec ce container.
- A quoi servent les options
i
ett
dans la commande ci-dessus?- Chaque container Docker est destiné à exécuter une commande unique. Quelle est-elle dans ce cas-ci?
- Dans le container, quels sont les processus présents? Et leurs PIDs?
- Avec quel utilisateur êtes-vous loggé?
- Votre container a-t’il accès à Internet? Qui est son résolveur?
2.2. Inspecter un container
Dans un autre terminal et la commande docker inspect
ou via l’interface graphique, essayez d’obtenir des informations sur ce container. Conseil : la commande grep
peut vous être d’une grande aide!
- Chaque container dispose d’une interface réseau. Quelle est l’adresse IP de l’interface de votre container?
- Votre container a-t’il des ports ouverts?
Une fois que vous avez pu retrouver l’information demandée, vous pouvez à présent éteindre votre container ubuntu. Deux options sont possibles :
- Utiliser la commande
docker stop
depuis la GUI ou un autre terminal. - Taper
exit
dans le shell du container. Cela aura pour effet de quitter le processusbash
, qui est le processus principal du container. Une fois ce processus quitté, le container n’a plus de raison d’être et s’arrête automatiquement (il est néanmoins possible de le redémarrer).
2.3. Faire tourner un service dans un container
Les containers sont utiles pour faire tourner des services de manière isolée, tout en permettant beaucoup de souplesse pour la migration ou la mise à jour : les containers peuvent être détruits et redémarrés très facilement, simplement sur base d’une image. Nous allons ici lancer un petit serveur web et voir comment le rendre accessible.
Nous allons commencer par exécuter un container sur base de l’image officielle “nginx” (serveur web concurrent d’Apache). Cette image est disponible sur le Docker Hub, et sera automatiquement téléchargée lorsque vous tenterez de l’utiliser. Il s’agit d’une image sur laquelle nginx et ses dépendances ont été installée, et qui peut donc être utilisée telle quelle.
- Exécutez la commande
docker run --name=mon-serveur-web nginx
dans un terminal.- Examinez à présent le container ainsi lancé, soit depuis l’interface graphique, soit depuis la console. Observez ce que vous voyez au niveau des “ports”.
- Le serveur nginx tourne donc sur le port 80, sur l’interface du container. Cependant, ce serveur n’est pas accessible en dehors de l’environnement Docker. Pour solutionner ce problème, nous allons effectuer une redirection de port (aussi appelée publication de port en terminologie Docker). Eteignez le container, puis relancez-en un nouveau, cette fois avec la commande
docker run -p80:80 --name mon-serveur-web nginx
.- Analysez le container et comparez les informations relatives aux ports ouverts avec celles obtenues deux étapes plus tôt. Quelle est la différence ? Si votre hôte est un système Linux, n’hésitez pas à confronter ces informations à l’output de
netstat
.- Essayez à présent d’accéder au serveur web via votre navigateur.
Qu’avez-vous observé au niveau des “ports” ? Expliquez et illustrez votre réponse avec des screenshots.
3. Construire des images
Pour la suite de ce TP, référez-vous à cette section du support théorique.
3.1. Figer un container
Imaginons que nous souhaitions configurer un service conformément à nos besoins. Par exemple, dans le cas de notre petit serveur web, nous souhaitons modifier la page d’accueil pour la personnaliser.
Nous pouvons lancer un container sur base d’une image de base, ouvrir un shell interactif et aller éditer nos configurations.
- Vérifiez que votre serveur web tourne toujours. Son processus principal (“commande”) est normalement le processus nginx.
- Démarrez terminal bash. Pour cela, nous allons lancer un second processus sur le container, en y attachant notre terminal afin de pouvoir interagir :
docker exec -it \<nom-du-container> /bin/bash
- Nous allons à présent commencer à personnaliser notre container. Nous pouvons installer des outils supplémentaires, via un
apt update
puisapt install
. Installez ce que vous voulez, par exemplenano
, ou encore votre outil favorinetstat
.- Pour personnaliser la page d’accueil, vous pouvez ensuite aller éditer le fichier
/usr/share/nginx/html
et le transformer à votre goût. Tester ensuite avec votre navigateur que les modifications ont bien eu lieu.
Votre container est à présent personnalisé : vous avez effectué des modifications sur la couche supérieure du système de fichiers en éditant le fichier html et en ajoutant des packages à l’OS. Néanmoins, il s’agit d’un container spécifique : l’image de départ n’a pas été modifiée, et si vous perdiez votre container, vous perdriez également toutes vos modifications!
Une première façon de rendre ces modifications persistantes consiste à créer un snapshot de ce container, et d’en faire une image.
- Utilisez la commande
docker container commit \<nom-container> \<nom-image>
pour créer une image sur base de votre serveur web.- Vérifiez dans la liste de vos images que vous retrouvez bien celle de votre serveur web.
- Arrêtez votre précédent container si ce n’est pas déjà fait, afin de libérer le port 80.
- Démarrez un nouveau container sur base de votre image personnelle, et vérifiez qu’elle fonctionne comme prévu.
3.2. Créer une image sur base d’un Dockerfile
La technique du snapshot est pratique, mais l’image ainsi générée doit alors être soigneusement documentée pour comprendre sa configuration. De plus, toute modification ultérieure (par exemple pour des mises à jour, ou simplement pour modifier la page d’accueil) nécessite également des interventions manuelles sur l’image, complexifiant ainsi son historique.
Une seconde technique, plus propre, consiste à écrire dans un fichier les instructions qui permettront de construire le container souhaité. Docker peut alors créer lui-même l’image sur base de ces instructions. Ce fichier s’appelle un “Dockerfile”.
- Créez un Dockerfile réalisant les mêmes opérations que celles que vous avez effectuées plus tôt, sur base de cet exemple. Enregistrez-le dans un répertoire de travail, en l’appelant
Dockerfile
.FROM nginx:latest RUN apt update RUN apt install -y nano net-tools COPY index.html /usr/share/nginx/html
- Mettez également dans ce répertoire un fichier
index.html
qui sera votre page d’accueil personnalisée.- Exécutez ensuite la commande
docker build -t <nom de l'image> .
dans ce même répertoire. Cela aura pour effet de déclencher la construction d’une nouvelle image, sur base de l’imagenginx
.- Vérifiez ensuite que cette image fonctionne comme prévu.
Exercices récapitulatifs
4.1. Démarrer un serveur Web Apache
Effectuez les mêmes opérations que plus haut, mais cette fois en utilisant Apache au lieu de nginx.
- Trouvez une image Apache sur le Docker Hub
- Démarrez un container sur base de cette image et vérifiez qu’il fonctionne sur localhost via votre navigateur.
- Créez un second virtualhost sur le port 8080.
- Personnalisez la page d’accueil des deux virtual hosts.
- Créez un Dockerfile permettant d’obtenir une image avec votre configuration Apache personnalisée.
4.2. Lancer un résolveur Bind dans un container Docker
- Allez sur le Docker Hub, et voyez s’il existe une image Docker avec bind pré-installé. Téléchargez-la.
- Démarrez un container sur base de cette image, et faites en sorte de pouvoir l’interroger via le port 53 de l’interface localhost de votre hôte. Attention : rappelez-vous le protocole transport utilisé par le DNS!
- Testez votre container avec l’outil ad-hoc.
- Modifiez la configuration de Bind pour transformer votre résolveur en forwarder DNS vers 8.8.8.8. Validez son comportement en utilisant Wireshark.
- Construisez le Dockerfile permettant d’obtenir une image intégrant cette configuration de Bind.
- Quelle configuration avez-vous effectuée au niveau des ports ?
- Qu’avez-vous observé dans la trace Wireshark qui prouve que la configuration est correcte? Illustrez avec un screenshot de la capture.
4.3. Container avec script Python
Créez un Dockerfile définissant une image permettant d’exécuter un container dont le rôle est d’afficher l’heure sur stdout au démarrage. C’est la seule opération que ce container effectuera avant de s’arrêter. Voici un exemple de code Python permettant d’obtenir ce résultat.
from datetime import datetime now = datetime.now() print(f"Nous sommes le {now.date()} à {now.time()}")