Lab 1 : Travailler avec des conteneurs
Dans ce lab1, vous apprendrez à travailler avec des conteneurs. Vous explorerez différentes façons d'exécuter des conteneurs et comment connecter des conteneurs ensemble. Dans ce lab, nous utiliserons Docker comme environnement d'exécution de conteneurs.
Prérequis
Avant de commencer le Lab, vous devez installer docker.
Warning
Il est recommandé d'installer docker en mode rootless
Partie 1 : Exécuter des conteneurs Docker
Il existe différentes façons d'utiliser des conteneurs. Celles-ci incluent :
- Pour exécuter une tâche unique : Il peut s'agir d'un script shell ou d'une application personnalisée.
- De manière interactive : Cela vous connecte au conteneur de manière similaire à la façon dont vous vous connectez en SSH à un serveur distant.
- En arrière-plan : Pour des services de longue durée comme des sites web et des bases de données.
Dans cette section, vous essaierez chacune de ces options et verrez comment Docker gère la charge de travail.
Exécuter une tâche unique dans un conteneur Alpine Linux
Dans cette étape, nous allons démarrer un nouveau conteneur et lui demander d'exécuter la commande hostname. Le conteneur démarrera, exécutera la commande hostname, puis se terminera.
-
Exécutez la commande suivante dans votre console Linux.
La sortie ci-dessous montre que l'image
alpine:latestn'a pas pu être trouvée localement. Lorsque cela se produit, Docker la télécharge automatiquement depuis Docker Hub.Une fois l'image téléchargée, le nom d'hôte du conteneur s'affiche (
888e89a3b36bdans l'exemple ci-dessous). -
Docker maintient un conteneur en cours d'exécution tant que le processus qu'il a démarré à l'intérieur du conteneur est toujours en cours d'exécution. Dans ce cas, le processus
hostnamese termine dès que la sortie est écrite. Cela signifie que le conteneur s'arrête. Cependant, Docker ne supprime pas les ressources par défaut, donc le conteneur existe toujours dans l'étatExited.Listez tous les conteneurs.
Notez que votre conteneur Alpine Linux est dans l'état
Exited.CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 888e89a3b36b alpine "hostname" 50 seconds ago Exited (0) 49 seconds ago awesome_elionNote : L'ID du conteneur est le nom d'hôte que le conteneur a affiché. Dans l'exemple ci-dessus, c'est
888e89a3b36b.
Les conteneurs qui effectuent une tâche puis se terminent peuvent être très utiles. Vous pourriez construire une image Docker qui exécute un script pour configurer quelque chose. N'importe qui peut exécuter cette tâche simplement en exécutant le conteneur - ils n'ont pas besoin des scripts réels ou des informations de configuration.
Exécuter un conteneur Ubuntu interactif
Vous pouvez exécuter un conteneur basé sur une version différente de Linux que celle qui s'exécute sur votre hôte Docker.
Dans l'exemple suivant, nous allons exécuter un conteneur Ubuntu Linux
-
Exécutez un conteneur Docker et accédez à son shell.
Dans cet exemple, nous donnons à Docker trois paramètres :
--interactiveindique que vous voulez une session interactive.--ttyalloue un pseudo-tty.--rmindique à Docker de supprimer le conteneur lorsqu'il a terminé son exécution.
Les deux premiers paramètres vous permettent d'interagir avec le conteneur Docker.
Nous disons également au conteneur d'exécuter
bashcomme processus principal (PID 1).Lorsque le conteneur démarre, vous vous retrouverez dans le shell bash avec l'invite par défaut
root@<container id>:/#. Docker s'est attaché au shell dans le conteneur, relayant les entrées et sorties entre votre session locale et la session shell dans le conteneur. -
Exécutez les commandes suivantes dans le conteneur.
ls /listera le contenu du répertoire racine dans le conteneur,ps auxmontrera les processus en cours d'exécution dans le conteneur,cat /etc/issuemontrera quelle distribution Linux le conteneur exécute. -
Tapez
exitpour quitter la session shell. Cela terminera le processusbash, provoquant la sortie du conteneur.Note : Comme nous avons utilisé le flag
--rmlors du démarrage du conteneur, Docker a supprimé le conteneur lorsqu'il s'est arrêté. Cela signifie que si vous exécutez un autredocker container ls --all, vous ne verrez pas le conteneur Ubuntu. -
Vérifiez la version du système d'exploitation hôte.
ou
La distribution de Linux à l'intérieur du conteneur n'a pas besoin de correspondre à la distribution de Linux s'exécutant sur l'hôte Docker.
Cependant, les conteneurs Linux nécessitent que l'hôte Docker exécute un noyau Linux. Par exemple, les conteneurs Linux ne peuvent pas s'exécuter directement sur des hôtes Docker Windows. Il en va de même pour les conteneurs Windows - ils doivent s'exécuter sur un hôte Docker avec un noyau Windows.
Les conteneurs interactifs sont utiles lorsque vous assemblez votre propre image. Vous pouvez exécuter un conteneur et vérifier toutes les étapes nécessaires pour déployer votre application, et les capturer dans un Dockerfile.
Vous pouvez commit un conteneur pour créer une image à partir de celui-ci - mais vous devriez éviter cela autant que possible. Il est bien préférable d'utiliser un Dockerfile répétable pour construire votre image. Vous verrez cela sous peu.
Exécuter un conteneur MySQL en arrière-plan
Les conteneurs en arrière-plan sont la façon dont vous exécuterez la plupart des applications. Voici un exemple simple utilisant MySQL.
-
Exécutez un nouveau conteneur MySQL avec la commande suivante.
--detachexécutera le conteneur en arrière-plan.--namele nommera mydb.-eutilisera une variable d'environnement pour spécifier le mot de passe root (NOTE : Cela ne devrait jamais être fait en production).
Comme l'image MySQL n'était pas disponible localement, Docker l'a automatiquement téléchargée depuis Docker Hub.
Unable to find image 'mysql:latest' locallylatest: Pulling from library/mysql aa18ad1a0d33: Pull complete fdb8d83dece3: Pull complete 75b6ce7b50d3: Pull complete ed1d0a3a64e4: Pull complete 8eb36a82c85b: Pull complete 41be6f1a1c40: Pull complete 0e1b414eac71: Pull complete 914c28654a91: Pull complete 587693eb988c: Pull complete b183c3585729: Pull complete 315e21657aa4: Pull complete Digest: sha256:0dc3dacb751ef46a6647234abdec2d47400f0dfbe77ab490b02bffdae57846ed Status: Downloaded newer image for mysql:latest 41d6157c9f7d1529a6c922acb8167ca66f167119df0fe3d86964db6c0d7ba4e0Tant que le processus MySQL est en cours d'exécution, Docker maintiendra le conteneur en cours d'exécution en arrière-plan.
-
Listez les conteneurs en cours d'exécution.
Notez que votre conteneur est en cours d'exécution.
-
Vous pouvez vérifier ce qui se passe dans vos conteneurs en utilisant quelques commandes Docker intégrées :
docker container logsetdocker container top.Cela montre les logs du conteneur Docker MySQL.
<output truncated> 2017-09-29T16:02:58.605004Z 0 [Note] Executing 'SELECT * FROM INFORMATION_SCHEMA.TABLES;' to get a list of tables using the deprecated partition engine. You may use the startup option '--disable-partition-engine-check' to skip this check. 2017-09-29T16:02:58.605026Z 0 [Note] Beginning of list of non-natively partitioned tables 2017-09-29T16:02:58.616575Z 0 [Note] End of list of non-natively partitioned tablesRegardons les processus s'exécutant à l'intérieur du conteneur.
Vous devriez voir que le démon MySQL (
mysqld) s'exécute dans le conteneur.Bien que MySQL soit en cours d'exécution, il est isolé dans le conteneur car aucun port réseau n'a été publié vers l'hôte. Le trafic réseau ne peut pas atteindre les conteneurs depuis l'hôte à moins que les ports ne soient explicitement publiés.
-
Listez la version de MySQL en utilisant
docker container exec.docker container execvous permet d'exécuter une commande à l'intérieur d'un conteneur. Dans cet exemple, nous utiliseronsdocker container execpour exécuter l'équivalent en ligne de commande demysql --user=root --password=$MYSQL_ROOT_PASSWORD --versionà l'intérieur de notre conteneur MySQL.Vous verrez le numéro de version de MySQL, ainsi qu'un avertissement utile.
-
Vous pouvez également utiliser
docker container execpour vous connecter à un nouveau processus shell à l'intérieur d'un conteneur déjà en cours d'exécution. L'exécution de la commande ci-dessous vous donnera un shell interactif (sh) à l'intérieur de votre conteneur MySQL.Notez que votre invite de shell a changé. C'est parce que votre shell est maintenant connecté au processus
shs'exécutant à l'intérieur de votre conteneur. -
Vérifions le numéro de version en exécutant à nouveau la même commande, mais cette fois depuis la nouvelle session shell dans le conteneur.
Notez que la sortie est la même qu'avant.
-
Tapez
exitpour quitter la session shell interactive.
Partie 2 : Créer des conteneurs
Créer des images de conteneurs
Dans cette section, vous apprendrez comment créer vos propres images de conteneurs. Une image Docker est un package logiciel léger, autonome et exécutable qui inclut tout ce qui est nécessaire pour exécuter un logiciel, y compris le code, l'environnement d'exécution, les bibliothèques, les variables d'environnement et les fichiers de configuration. Les images sont construites à l'aide de fichiers déclaratifs spéciaux, les Dockerfiles.
Étape 1 : Créer un Dockerfile
Un Dockerfile est un document texte qui contient toutes les commandes pour assembler une image. Nous allons maintenant voir comment créer un serveur web python.
Pour commencer, créons un serveur hello world (enregistrez-le sous le nom app.py) :
# app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, World!'
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)
et écrivez un requirements.txt pour installer les dépendances requises :
Dockerfile avec le contenu suivant) :
# Use an official Python image
FROM python:3.12
# Set the working directory in the container
WORKDIR /app
# Copy the current directory contents into the container at /app
COPY . /app
# Install requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
# Run app.py when the container launches
CMD ["python", "app.py"]
Info
Il existe des bonnes pratiques établies par la communauté sur la façon de créer des Dockerfiles. Parmi elles, les builds multi-étapes réduisent la taille d'un conteneur.
Étape 2 : Construire l'image Docker
Pour construire l'image Docker à partir du Dockerfile, utilisez la commande docker build. Exécutez la commande suivante dans le répertoire contenant votre Dockerfile :
Cette commande construit l'image et la tague comme python-app.
Note
Vous pouvez utiliser des tags pour publier différentes versions du même conteneur (par exemple, une pour x86 et une pour arm)
Étape 3 : Exécuter le conteneur Docker
Une fois l'image construite, vous pouvez exécuter un conteneur en utilisant la commande docker run :
Maintenant vous pouvez accéder à l'application à :
et vous verrez le serveur web répondre avecHello, World!
Note
Le mécanisme de mappage de port est différent du mécanisme d'espace de noms réseau. Dans ce cas, un port sur votre hôte est mappé au port du conteneur via des règles iptables.
Vous pouvez exporter le contenu d'un conteneur sous forme de fichier archive en utilisant la commande export.
Question 1
En utilisant la commande docker export, enregistrez le conteneur python-app en tant qu'archive tar. Ensuite, extrayez-la et analysez-la.
Quelle est la structure de l'archive ?
Quelles informations sur le conteneur pouvez-vous trouver ?
Warning
Le conteneur doit être en cours d'exécution pour pouvoir être exporté.
Nettoyage
Partie 3 : Réseaux de conteneurs
Les conteneurs ont besoin d'un espace de noms réseau pour communiquer avec d'autres conteneurs et avec Internet. Dans cette partie du Lab, nous explorerons comment les conteneurs sont liés ensemble ou isolés.
Réseaux Docker par défaut et leurs différences
Par défaut, Docker est équipé de trois réseaux différents. Regardons-les :
La sortie devrait être similaire à :NETWORK ID NAME DRIVER SCOPE
a19bac0e4c32 bridge bridge local
9e1ac4485c0a host host local
bcd75e804e3c none null local
-
Réseau Bridge : Le réseau
bridgeest le réseau par défaut pour les conteneurs. Il permet aux conteneurs qui y sont connectés de communiquer entre eux, tout en fournissant une isolation des conteneurs non connectés au bridge. Les conteneurs sur le réseau bridge peuvent accéder aux réseaux externes, y compris Internet, via l'interface réseau de l'hôte. Bridge est également le nom du pilote utilisé pour ce type de réseau. -
Réseau Host : Comme son nom l'indique, le réseau
hostest le même réseau que le système d'exploitation hôte. Les conteneurs utilisant le réseau host partagent la pile réseau de l'hôte et peuvent utiliser directement l'adresse IP de l'hôte. Cela signifie que les conteneurs peuvent accéder à tous les ports ouverts sur l'hôte. -
Réseau None : Le réseau
nonedésactive le réseau pour le conteneur.
Info
Lectures complémentaires sur le réseau Docker : IPvlan, Macvlan, Overlay.
Question Bonus
Quelle est l'adresse IP d'un conteneur attaché à un réseau Macvlan ? Et qui l'attribue ?
Déployer des conteneurs dans différents réseaux
Dans cette partie, vous déploierez deux conteneurs utilisant différents réseaux Docker. Ce tutoriel vous donnera une compréhension pratique du fonctionnement de ces réseaux et de la façon dont les conteneurs communiquent dans Docker.
Note
Chaque fois qu'un nouveau conteneur est créé, docker créera un nouveau namespace (réseau) pour le conteneur.
Réseau Bridge
-
Créez un nouveau conteneur connecté au réseau bridge.
Cette commande exécute un conteneur Nginx en arrière-plan en utilisant le réseau bridge par défaut.
-
Créez un autre conteneur connecté au réseau bridge.
Les deux conteneurs sont maintenant connectés au réseau bridge et devraient pouvoir communiquer entre eux.
-
Vérifiez que les conteneurs sont en cours d'exécution et connectés au réseau bridge.
docker container ls # Affiche les conteneurs en cours d'exécution docker network inspect bridge # Affiche le contenu du réseauLe résultat de ces commandes devrait ressembler à :
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0b5a9d812179 nginx "/docker-entrypoint.…" 16 seconds ago Up 15 seconds 80/tcp app2 28755a17cd52 nginx "/docker-entrypoint.…" 25 seconds ago Up 20 seconds 80/tcp app1[ { "Name": "bridge", "Id": "ba3606add1244c0fd7ba5189f6fceb7b7c52acee5a8e9e177537cc417b11e545", "Created": "2025-02-13T11:47:39.796570164Z", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.17.0.0/16", "Gateway": "172.17.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "0b5a9d812179115094030c3bc6307c942f92de483bf345fe3f9ff035ee0e9127": { "Name": "app2", "EndpointID": "1e2211dcc219da9cf7f68514d578fbd30acc35f438b71a7d83c2b250e7d0045f", "MacAddress": "02:42:ac:11:00:03", "IPv4Address": "172.17.0.3/16", "IPv6Address": "" }, "28755a17cd52af14d84035c24fb238ee57334c7f801da0d972f1402fb95fbe98": { "Name": "app1", "EndpointID": "1a598cb3746789fe8717845e57d6cf774c33508b4fbc284c10fef43a9857598f", "MacAddress": "02:42:ac:11:00:02", "IPv4Address": "172.17.0.2/16", "IPv6Address": "" } }, "Options": { "com.docker.network.bridge.default_bridge": "true", "com.docker.network.bridge.enable_icc": "true", "com.docker.network.bridge.enable_ip_masquerade": "true", "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0", "com.docker.network.bridge.name": "docker0", "com.docker.network.driver.mtu": "65535" }, "Labels": {} } ]
Ces commandes montrent que les deux conteneurs sont dans le même réseau et qu'ils ont les IP : 172.17.0.2/16 et 172.17.0.3/16.
Question 2
Quelle est l'adresse de la passerelle de ce réseau bridge ?
Pouvez-vous voir le réseau avec la commande ifconfig ou ip a ?
Warning
Si vous utilisez MacOS ou Windows, vous devez d'abord vous connecter en SSH à la VM Docker.
Réseau Host
-
Créez un nouveau conteneur connecté au réseau host.
Cette commande exécute un conteneur Nginx en arrière-plan en utilisant le réseau host.
-
Créez un autre conteneur connecté au réseau host.
Les deux conteneurs sont maintenant connectés au réseau host
Question 3
Quelle est l'adresse IP des deux conteneurs ? Pouvez-vous voir quels ports sont ouverts sur le conteneur ? Que se passe-t-il si vous exécutez la commande :
docker container run -d --name host-container3 --network host nginx?
Réseau None
-
Créez un nouveau conteneur sans réseau.
Cette commande exécute un conteneur Nginx en arrière-plan sans réseau.
Question 4
Pouvez-vous vous connecter à Internet en utilisant ce réseau ?
-
Créez un autre conteneur sans réseau.
Les deux conteneurs sont maintenant isolés sans connectivité réseau.
-
Vérifiez que les conteneurs sont en cours d'exécution et n'ont pas de réseau.
Déployer des conteneurs dans le même namespace
Il y a des cas où vous souhaitez déployer des conteneurs dans les mêmes namespaces et laisser les conteneurs communiquer entre eux en utilisant uniquement localhost. Ce cas est très courant, par exemple dans Kubernetes. Cette section du lab vous apprendra comment y parvenir dans docker.
Étape 1 : Créer le premier conteneur
Démarrez un conteneur normalement. Par exemple :
Étape 2 : Exécuter le deuxième conteneur
Utilisez le flag --network container:<container_name pour attacher le deuxième conteneur au namespace réseau du conteneur principal :
Étape 3 : Vérifier la connectivité
D'abord, nous vérifions que les conteneurs sont en cours d'exécution :
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
88fef5507abf alpine "sleep 300000" 6 seconds ago Up 2 seconds second
20d60f685794 alpine "sleep 300000" 48 seconds ago Up 41 seconds first
Dans cette configuration, le deuxième conteneur partage la pile réseau du premier conteneur. Les deux conteneurs partagent maintenant la même adresse IP et peuvent communiquer entre eux via localhost.
Vérifiez l'adresse IP des conteneurs en exécutant :
Il est maintenant temps de vérifier la connectivité entre les conteneurs. Sur deux terminaux séparés, exécutez :
etChaque caractère écrit dans le deuxième conteneur devrait maintenant apparaître dans le premier et ils devraient pouvoir communiquer en utilisant localhost.
Questions 5-8
- Quel est le nom d'hôte des conteneurs
firstetsecond? - Que se passe-t-il pour le conteneur
secondsi vous supprimez le conteneurfirst? - Dans quel cas déploieriez-vous deux conteneurs dans le même namespace réseau ?
- Que se passe-t-il si
firstetsecondécoutent sur le même port ?
Étape 4 : Nettoyage
-
Ce lab a été inspiré par : https://github.com/play-with-docker/play-with-docker ↩