TP Docker
TP Docker
TP Docker
Les objectifs :
Avant installation de Docker Engine pour la première fois, il faut tout d’abord installer le
dépôt Docker :
1
2. Installation des packages Docker.
:
Dans ce cas, le daemon Docker va chercher si l'image hello-world est disponible en local.
Dans le cas contraire, il va la récupérer sur la registry Docker officielle.
Le conteneur démarre, puis affiche du contenu, et il fini par s'arrêter. Si on souhaite que le
conteneur reste allumé jusqu’à l'arrêt du service qu'il contient, on doit ajouter l’argument --
detach (-d) . Celui-ci permet de ne pas rester attaché au conteneur, et donc de pouvoir lancer
plusieurs conteneurs.
2
Démarrez une application avec un conteneur Docker
Nous commençons par récupérer le code source d’une application simple depuis github :
git clone https://github.com/docker/getting-started-app.git
Pour créer l'image, on utilise un Dockerfile. Un Dockerfile est simplement un fichier texte
sans extension qui contient un script d'instructions. Docker utilise ce script pour créer une
image de conteneur.
La commande docker build utilise le Dockerfile pour créer une nouvelle image. Docker
télécharge beaucoup de « couches ». En effet, nous avons indiqué au constructeur qu’on
souhaite démarrer à partir de l'image node:18-alpine, que Docker va télécharger.
3
Une fois que Docker a téléchargé l'image, les instructions du Dockerfile ont été copiées dans
l’application et ont utilisé par yarn pour installer les dépendances de l’application. La
directive CMD spécifie la commande par défaut à exécuter lors du démarrage d'un conteneur
à partir de cette image.
L'argument -t permet de donner un nom à notre image Docker. Cela permet de retrouver
plus facilement l’mage par la suite.
Le . est le répertoire où se trouve le Dockerfile ; dans notre cas, à la racine de notre projet.
Maintenant que vous disposez d'une image, vous pouvez exécuter l'application dans un
conteneur à l'aide de la commande docker run.
3. Ajoutez un élément ou deux et voyez qu'il fonctionne comme prévu. Vous pouvez
marquer des éléments comme terminés et les supprimer. Votre frontend stocke avec
succès les éléments dans le backend.
4
À ce stade, vous disposez d’un gestionnaire de liste de tâches en cours d’exécution avec
quelques éléments.
La commande docker ps (ou docker ps -a) permet de visualiser tous les conteneurs
en cours d’exécution :
docker ps
Mise à jour de
l’application :
Nous avons conteneurisé une application de tâches. Dans cette partie, on va mettre à jour
l'application et l'image. On verra comment arrêter et supprimer un conteneur.
Dans les étapes suivantes, vous allez remplacer le « texte vide » lorsque vous n'avez aucun
élément de liste de tâches par « Vous n'avez pas encore d'éléments de tâche ! Ajoutez-en un
ci-dessus ! »
2. Créez votre version mise à jour de l'image à l'aide de la commande docker build.
docker build -t getting-started .
5
Un message d’erreur s’affiche. L'erreur s'est produite car vous ne parvenez pas à démarrer le
nouveau conteneur alors que votre ancien conteneur est toujours en cours d'exécution. La
raison en est que l'ancien conteneur utilise déjà le port 3000 de l'hôte et qu'un seul processus
sur la machine (conteneurs inclus) peut écouter un port spécifique. Pour résoudre ce
problème, vous devez supprimer l'ancien conteneur.
Supprimer l’ancien container:
Pour supprimer un conteneur, vous devez d’abord l’arrêter. Une fois arrêté, vous pouvez le
supprimer.
Remarque:
Actualisez votre navigateur sur http://localhost:3000 et vous devriez voir votre texte d'aide
mis à jour.
Partager l’application
Maintenant que vous avez créé une image, vous pouvez la partager. Pour partager des images
Docker, vous devez utiliser un registre Docker. Le registre par défaut est Docker Hub et c'est
là que proviennent toutes les images que vous avez utilisées.
6
Pour pousher une image, vous devez d'abord créer un référentiel (repository) sur Docker Hub.
Dans la ligne de commande, exécutez la commande docker push que vous voyez sur Docker
Hub. Notez que votre commande aura votre identifiant Docker, et non « docker ».
docker push docker/getting-started
The push refers to repository [docker.io/docker/getting-started]
An image does not exist locally with the tag: docker/getting-
started
Pourquoi a-t-il échoué ? La commande push recherchait une image nommée docker/getting
started, mais n'en a pas trouvé. Si vous exécutez docker image ls, vous n'en verrez pas non
plus.
Pour résoudre ce problème, vous devez « tager » votre image existante que vous avez créée
pour lui donner un autre nom.
Utilisez la commande docker tag pour donner un nouveau nom à l'image de démarrage.
Remplacez YOUR-USER-NAME par votre Docker ID.
docker tag getting-started YOUR-USER-NAME/getting-started
Maintenant, exécutez à nouveau la commande docker push. Si vous copiez la valeur depuis
Docker Hub, vous pouvez supprimer la partie tag name, car vous n'avez pas ajouté de balise
7
au nom de l'image. Si vous ne spécifiez pas de balise, Docker utilise une balise appelée
latest.
On peut récupérer des images sur le Docker Hub sans pour autant lancer de conteneur. Pour cela,
on a besoin de lancer la commande docker pull:
Applications multi-conteneurs
Container networking
Les conteneurs, par défaut, s'exécutent de manière isolée et ne connaissent rien des autres
processus ou conteneurs sur la même machine. Alors, pour pouvoir communiquer, il faut
placer les deux conteneurs sur le même réseau.
Démarrer MySQL :
8
Dans les étapes suivantes, vous allez d'abord créer le réseau, puis attacher le conteneur
MySQL au démarrage.
Créer le réseau
docker network create todo-app
Lorsque l’invite du mot de passe apparaît, saisissez secret. Dans le shell MySQL, répertoriez
les bases de données et vérifiez que vous voyez la base de données todos.
mysql> SHOW DATABASES;
Se connecter à MySQL :
À l'intérieur du conteneur, vous allez utiliser la commande dig, qui est un outil DNS utile.
Vous allez rechercher l'adresse IP du nom d'hôte mysql.
dig mysql
Dans la "SECTION RÉPONSE", vous verrez un enregistrement A pour MySQL qui se résout
en 172.23.0.2 (votre adresse IP aura très probablement une valeur différente). Bien que mysql
ne soit normalement pas un nom d'hôte valide, Docker a pu le résoudre en l'adresse IP du
conteneur qui possédait cet alias réseau. N'oubliez pas que vous avez utilisé --network-alias
plus tôt.
Cela signifie que votre application doit simplement se connecter à un hôte nommé mysql et
communiquer avec la base de données.
10
3. Ouvrez l'application dans votre navigateur et ajoutez quelques éléments à votre liste de
tâches.
4. Connectez-vous à la base de données MySQL et prouvez que les éléments sont en
cours d'écriture dans la base de données.
docker exec -it <mysql-container-id> mysql -p todos
Le gros avantage de Compose est que vous pouvez définir votre pile d'applications dans
un fichier, la conserver à la racine du référentiel de votre projet (sa version est désormais
contrôlée) et permettre facilement à quelqu'un d'autre de contribuer à votre projet. Il
suffirait à quelqu'un de cloner votre référentiel et de démarrer l'application à l'aide de
Compose.
12
-e MYSQL_HOST=mysql \
-e MYSQL_USER=root \
-e MYSQL_PASSWORD=secret \
-e MYSQL_DB=todos \
node:18-alpine \
sh -c "yarn install && yarn run dev"
4. Ensuite, migrez à la fois le répertoire de travail (-w /app) et le mappage de volume (-v
"$(pwd):/app") en utilisant les définitions working_dir et volumes.
13
L'un des avantages des définitions de volume Docker Compose est que vous pouvez utiliser
des chemins relatifs à partir du répertoire actuel.
services:
app:
image: node:18-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 127.0.0.1:3000:3000
working_dir: /app
volumes:
- ./:/app
Enfin, vous devez migrer les définitions des variables d'environnement à l'aide de la clé
environnement.
services:
app:
image: node:18-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 127.0.0.1:3000:3000
working_dir: /app
volumes:
- ./:/app
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASSWORD: secret
MYSQL_DB: todos
docker run -d \
--network todo-app --network-alias mysql \
-v todo-mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
14
-e MYSQL_DATABASE=todos \
mysql:8.0
Ensuite, définissez le mappage de volume. Lorsque vous avez exécuté le conteneur avec
Docker Run, Docker a créé automatiquement le volume nommé. Cependant, cela ne se
produit pas lors de l'exécution avec Compose.
services:
app:
# The app service definition
mysql:
image: mysql:8.0
volumes:
- todo-mysql-data:/var/lib/mysql
volumes:
todo-mysql-data:
services:
app:
# The app service definition
mysql:
image: mysql:8.0
volumes:
- todo-mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: todos
15
volumes:
todo-mysql-data:
mysql:
image: mysql:8.0
volumes:
- todo-mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: todos
volumes:
todo-mysql-data:
Maintenant que vous disposez de votre fichier compose.yaml, vous pouvez démarrer votre
application.
Assurez-vous qu'aucune autre copie des conteneurs n'est exécutée en premier. Utilisez docker
ps pour lister les conteneurs et docker rm -f <ids> pour les supprimer.
16
Démarrez la pile d'applications à l'aide de la commande docker compose up. Ajoutez
l'indicateur -d pour tout exécuter en arrière-plan.
Docker-compose up -d
Lorsque vous exécutez la commande précédente, vous devriez voir un résultat semblable à
celui-ci :
Vous remarquerez que Docker Compose a créé le volume ainsi qu'un réseau. Par défaut,
Docker Compose crée automatiquement un réseau spécifiquement pour la pile d'applications
(c'est pourquoi vous n'en avez pas défini dans le fichier Compose).
Consultez les journaux à l’aide de la commande docker-compose logs -f. Vous verrez les
journaux de chacun des services entrelacés dans un seul flux. Ceci est utile lorsque vous
souhaitez surveiller les problèmes liés au timing. L'indicateur -f suit le journal et vous
donnera donc une sortie en direct au fur et à mesure de sa génération.
Si vous avez déjà exécuté la commande, vous verrez un résultat semblable à ceci :
mysql_1 | 2019-10-03T03:07:16.083639Z 0 [Note] mysqld: ready for
connections.
mysql_1 | Version: '8.0.31' socket: '/var/run/mysqld/mysqld.sock' port:
3306 MySQL Community Server (GPL)
app_1 | Connected to mysql db at host mysql
app_1 | Listening on port 3000
Le nom du service est affiché au début de la ligne (souvent coloré) pour aider à distinguer les
messages. Si vous souhaitez afficher les journaux d'un service spécifique, vous pouvez ajouter
le nom du service à la fin de la commande logs (par exemple, docker compose logs -f app).
À ce stade, vous devriez pouvoir ouvrir votre application dans votre navigateur sur
http://localhost:3000 et la voir fonctionner.
17
Lorsque vous êtes prêt à tout démolir, exécutez simplement Docker-Compose Down. Les
conteneurs s'arrêteront et le réseau sera supprimé.
À l’aide de la commande docker-image history, vous pouvez voir la commande qui a été
utilisée pour créer chaque layer dans une image.
Utilisez la commande docker-image history pour voir les layers dans l'image
de démarrage que vous avez créée.
Docker image history getting-started
En apportant n’importe quelle modification, toutes les dépendances sont à nouveau crée.
Pour résoudre ce problème, vous devez restructurer votre Dockerfile pour prendre en charge
la mise en cache des dépendances. Pour les applications basées sur des nodes, ces
dépendances sont définies dans le fichier package.json. Vous pouvez d'abord copier
uniquement ce fichier, installer les dépendances, puis copier tout le reste. Ensuite, vous ne
recréez les dépendances que s'il y a eu une modification dans le fichier package.json.
1. Mettez à jour le Dockerfile pour copier d'abord dans le package.json, installez les
dépendances, puis copiez tout le reste.
# syntax=docker/dockerfile:1
FROM node:18-alpine
WORKDIR /app
18
COPY package.json yarn.lock ./
RUN yarn install --production
COPY . .
CMD ["node", "src/index.js"]
2. Créez un fichier nommé .dockerignore dans le même dossier que le Dockerfile avec
le contenu suivant.
node_modules
Les fichiers .dockerignore sont un moyen simple de copier uniquement les fichiers
pertinents pour l'image. Dans ce cas, le dossier node_modules doit être omis lors de la
deuxième étape COPY car sinon, il risquerait d'écraser les fichiers créés par la commande
lors de l'étape RUN.
Vous devriez remarquer que la construction a été beaucoup plus rapide. Et vous verrez que
plusieurs étapes utilisent des couches précédemment mises en cache. Pousser et extraire cette
image et ses mises à jour seront également beaucoup plus rapides.
19