Work on tuto 2

This commit is contained in:
nemunaire 2022-09-20 06:02:53 +02:00
parent 1ca35a1d57
commit bc179806db
19 changed files with 543 additions and 143 deletions

View File

@ -0,0 +1,12 @@
include ../../tutorial/pandoc-opts.mk
SOURCES = subject.md docker-api.md ex-api-updater-intro.md ex-api-updater.md rendu.md end.md
all: subject.pdf
subject.pdf: ${SOURCES}
pandoc ${PANDOCOPTS} -o $@ $+
clean::
rm subject.pdf

View File

View File

@ -0,0 +1 @@
Bon courage !

View File

@ -0,0 +1,2 @@
Mini-projet
===========

View File

@ -0,0 +1,131 @@
::::: {.exercice}
Écrivez un programme tirant parti de l'API du Docker Engine (le *daemon*
Docker) qui pour un conteneur donné :
1. détecte si le conteneur exécute une image disposant d'une mise à jour ;
1. cherche à récupérer la dernière image disponible ;
1. mette à jour le contneur ;
1. dans un conteneur, automatiquement pour toutes les images.
## Étape 1 : Lister les conteneurs
Lancé sans argument, votre programme doit retourner la liste des conteneurs
actifs. Un nom par ligne.
### Exemple d'exécution {-}
<div lang="en-US">
```bash
42sh$ docker run -d nginx
42sh$ docker run -d mysql
42sh$ docker run -d redis
42sh$ ctr-updater
Choose a container to analyze:
dazzling_driscoll
amazing_proskuriakova
optimistic_meninsky
```
</div>
## Étape 1 bis : Prêt pour la prod
Écrivez un `Dockerfile` pour conteneuriser ce programme : gérer tant la
construction (s'il y a des étapes de construction) que l'exécution. En
utilisant les bonnes pratiques vues en cours.
### Exemple d'exécution {-}
<div lang="en-US">
```bash
42sh$ docker run -d --name myp0m nemunaire/youp0m
42sh$ docker build -t login/ctr-updater .
42sh$ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock login/ctr-updater
Choose a container to analyze:
myp0m
# Après l'étape 2 :
42sh$ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock login/ctr-updater myp0m
42sh$ echo $?
0 # Le conteneur est à jour
```
</div>
Notez que l'on n'emploie pas `ctr-updater` pour appeler le binaire dans
l'image. Le premier argument passé au conteneur est donc le nom du conteneur à
vérifier.
## Étape 2 : Détecter si le conteneur exécute la dernière image disponible
Lancé avec un argument, votre programme doit, à partir des informations
accessibles localement (conteneurs et images), retourner le code de 0 ou 1,
suivant si (0) aucune mise à jour de l'image n'est disponible, respectivement
(1) une mise à jour est disponible.
### Exemple d'exécution {-}
<div lang="en-US">
```bash
42sh$ docker build -t my_webserver .
42sh$ docker run -d --name mws my_webserver
42sh$ ctr-updater mws
42sh$ echo $?
0 # Le conteneur est à jour
42sh$ echo "nouvelle page" > index.html
42sh$ docker build -t my_webserver .
42sh$ ctr-updater mws
42sh$ echo $?
1 # Une mise à jour est dispo.
```
</div>
N'hésitez pas à utiliser la sortie d'erreur et la sortie standard pour afficher
des informations pour vous. Celles-ci ne seront pas vérifiées.
## Étape 3 : Chercher une mise à jour l'image
En ajoutant l'option `--pull`, votre programme va lancer un pull de l'image
avant de faire la vérification.
<div lang="en-US">
```bash
42sh$ docker run -d --name myp0m nemunaire/youp0m
42sh$ ctr-updater myp0m
42sh$ echo $?
0 # Le conteneur est à jour
42sh$ ctr-updater --pull myp0m
42sh$ echo $?
1 # Une mise à jour est dispo.
42sh$ ctr-updater myp0m
42sh$ echo $?
1 # La nouvelle image a été pull précédemment
# et est disponible dans le cache local
```
</div>
L'image `youp0m` est mise à jour régulièrement. Il y a de forte chance pour
qu'elle ne soit plus à jour si celle dont vous disposez date de plus d'une
semaine. Si vous possédez déjà la dernière version de vos conteneurs,
recherchez une image sur le Docker Hub régulièrement mise à jour pour faire vos
tests.
Attention une fois l'image *pull* par `ctr-updater`, un appel à nouveau à
`ctr-updater` sans `--pull` retourne la mise à jour, car le `pull` précédent
aura téléchargé localement l'image.
## Étape 4 : Mettre à jour le conteneur
En ajoutant l'option `--autoupdate`, si une mise à jour de l'image utilisée par
le conteneur est disponible (après un éventuel `pull` si l'option est passée),
le conteneur est arrêté, supprimé, puis relancé avec les mêmes options, mais en
utilisant la nouvelle image.
Il est attendu dans ce cas de toujours retourner le statut 0 si la mise à jour
se passe bien.
:::::

View File

@ -0,0 +1 @@
../../tutorial/2/rendu.md

View File

@ -0,0 +1,10 @@
---
title: Virtualisation légère -- Mini-projet n^o^ 2
author: Pierre-Olivier *nemunaire* [Mercier]{.smallcaps}
institute: EPITA
date: EPITA -- Promo 2023
abstract: |
Le rendu de ce mini-projet individuel est attendu par un tag signé
sur un dépôt privé de la forge de l'école au plus tard le **mardi
18 octobre 2022 à 23 h 42**.
...

View File

@ -1,8 +1,12 @@
include ../pandoc-opts.mk include ../pandoc-opts.mk
SOURCES = tutorial.md \ SOURCES = tutorial.md \
../docker-advanced/security.md \
../dockerfiles/what.md ../dockerfiles/interactive.md ../dockerfiles/dockerfile.md ../dockerfiles/goodpractices.md ../dockerfiles/others.md ../dockerfiles/entrypoint.md \ ../dockerfiles/what.md ../dockerfiles/interactive.md ../dockerfiles/dockerfile.md ../dockerfiles/goodpractices.md ../dockerfiles/others.md ../dockerfiles/entrypoint.md \
../docker-internals/vulnerability-scan.md ../docker-internals/clair-tiny.md ../docker-internals/vulnerability-scan-ex.md \ ../docker-internals/vulnerability-scan.md ../docker-internals/clair-tiny.md ../docker-internals/vulnerability-scan-ex.md
SOURCES_PROJECT = tutorial.md \
../docker-advanced/what.md ../docker-advanced/setup.md ../docker-advanced/manual.md ../new-page.md ../docker-advanced/compose.md \
rendu.md rendu.md
SOURCES_CLAIR = tutorial-clair.md \ SOURCES_CLAIR = tutorial-clair.md \

View File

@ -3,61 +3,36 @@
Rendu Rendu
===== =====
Est attendu d'ici le TP suivant : Est attendu d'ici le cours suivant :
- le rendu des exercice de ce TP ; - votre `Dockerfile` et son *entrypoint* pour dépôt `youp0m` ;
- vos réponses à [l'évaluation du cours](https://virli.nemunai.re/quiz/12). - ce mini-projet ;
- vos réponses à [l'évaluation du cours](https://virli.nemunai.re/quiz/34).
Pour les SRS (et en bonus pour les GISTRE), [un
projet](https://virli.nemunai.re/project-1.pdf) est à rendre pour le 13
octobre. Consultez les modalités de rendu sur le sujet directement.
Modalités de rendu Arborescence attendue
------------------
En tant que personnes sensibilisées à la sécurité des échanges électroniques,
vous devrez m'envoyer vos rendus signés avec votre clef PGP.
Un service automatique s'occupe de réceptionner vos rendus, de faire des
vérifications élémentaires et de vous envoyer un accusé de réception (ou de
rejet).
Ce service écoute sur l'adresse <virli@nemunai.re>, c'est donc à cette adresse
et exclusivement à celle-ci que vous devez envoyer vos rendus. Tout rendu
envoyé à une autre adresse et/ou non signé et/ou reçu après la correction ne
sera pas pris en compte.
Afin d'orienter correctement votre rendu, ajoutez une balise `[TP2]` au sujet
de votre courriel. N'hésitez pas à indiquer dans le corps du message votre
ressenti et vos difficultés ou bien alors écrivez votre meilleure histoire
drôle si vous n'avez rien à dire.
Tarball
------- -------
Tous les fichiers identifiés comme étant à rendre pour ce TP sont à Tous les fichiers identifiés comme étant à rendre sont à placer dans un dépôt
placer dans une tarball (pas d'archive ZIP, RAR, ...). Git privé, que vous partagerez avec [votre
professeur](https://gitlab.cri.epita.fr/nemunaire/).
Voici une arborescence type (vous pourriez avoir des fichiers Voici une arborescence type (vous pourriez avoir des fichiers supplémentaires) :
supplémentaires) :
<div lang="en-US"> <div lang="en-US">
``` ```
login_x-TP2/ ./
login_x-TP2/my_webservice/ # 1.2.2 + 1.3 ./youp0m/ # 1.2.7 + 1.3
login_x-TP2/my_webservice/Dockerfile ./youp0m/Dockerfile
login_x-TP2/my_webservice/index.html ./youp0m/entrypoint.sh # 2.2.2
login_x-TP2/youp0m/ # 1.2.7 + 1.3 ./youp0m/.dockerignore
login_x-TP2/youp0m/Dockerfile ./youp0m/...
login_x-TP2/youp0m/entrypoint.sh # 2.2.2 ./ctr-updater/
login_x-TP2/youp0m/.dockerignore ./ctr-updater/Dockerfile
login_x-TP2/youp0m/... ./ctr-updater/...
login_x-TP2/mysql:latest.html # rapport d'analyse PAclair/Trivy/...
login_x-TP2/....html
``` ```
</div> </div>
Inutile d'inclure le contenu du dépôt `youp0m` dans votre tarball. Placez-y Votre rendu sera pris en compte en faisant un [tag **signé par votre clef
uniquement les fichiers que vous avez ajouté. PGP**](https://lessons.nemunai.re/keys). Consultez les détails du rendu (nom du
tag, ...) sur la page dédiée au projet sur la plateforme de rendu.

View File

@ -3,7 +3,7 @@ title: Virtualisation légère -- TP n^o^ 2
subtitle: Construire des images Docker et leur sécurité -- Annexe subtitle: Construire des images Docker et leur sécurité -- Annexe
author: Pierre-Olivier *nemunaire* [Mercier]{.smallcaps} author: Pierre-Olivier *nemunaire* [Mercier]{.smallcaps}
institute: EPITA institute: EPITA
date: Jeudi 23 septembre 2021 date: Mercredi 21 septembre 2022
abstract: | abstract: |
Clair est un outil très intéressant à déployer dans un contexte d'analyse Clair est un outil très intéressant à déployer dans un contexte d'analyse
continue, au sein d'une plateforme de déploiement continue par exemple. Vous continue, au sein d'une plateforme de déploiement continue par exemple. Vous

View File

@ -3,23 +3,9 @@ title: Virtualisation légère -- TP n^o^ 2
subtitle: Construire des images Docker et leur sécurité subtitle: Construire des images Docker et leur sécurité
author: Pierre-Olivier *nemunaire* [Mercier]{.smallcaps} author: Pierre-Olivier *nemunaire* [Mercier]{.smallcaps}
institute: EPITA institute: EPITA
date: Jeudi 23 septembre 2021 date: Mercredi 21 septembre 2022
abstract: | abstract: |
Durant ce deuxième TP, nous allons voir comment créer nos propres Durant ce deuxième TP, nous allons voir comment créer nos propres
images, et comment s'assurer qu'elles n'ont pas de vulnérabilités images, et comment s'assurer qu'elles n'ont pas de vulnérabilités
connues ! connues !
\vspace{1em}
Tous les éléments de ce TP (exercices et projet) sont à rendre à
<virli@nemunai.re> au plus tard le **mercredi 29 septembre 2021 à 23 h
42**. Consultez la dernière section de chaque partie pour plus d'informations
sur les éléments à rendre. Et n'oubliez pas de répondre aux [questions de
cours](https://virli.nemunai.re/quiz/12).
En tant que personnes sensibilisées à la sécurité des échanges électroniques,
vous devrez m'envoyer vos rendus signés avec votre clef PGP. Pensez à
[me](https://keys.openpgp.org/search?q=nemunaire%40nemunai.re) faire signer
votre clef et n'hésitez pas à [faire signer la
vôtre](https://www.meetup.com/fr/Paris-certification-de-cles-PGP-et-CAcert/).
... ...

View File

@ -20,8 +20,8 @@ Il est donc primordial de ne pas laisser ses conteneurs à l'abandon une fois
leur image créée et envoyée en production. Nos conteneurs doivent être leur image créée et envoyée en production. Nos conteneurs doivent être
regénérés sitôt que leur image de base est mise à jour (une mise à jour d'une regénérés sitôt que leur image de base est mise à jour (une mise à jour d'une
image telle que Debian, Ubuntu ou Redhat n'apparaît que pour cela) ou bien image telle que Debian, Ubuntu ou Redhat n'apparaît que pour cela) ou bien
lorsqu'un des programmes ou l'une des bibliothèques que l'on a installées lorsqu'un des programmes ou l'une des bibliothèques que l'on a installées est
ensuite est mise à jour. mise à jour.
Convaincu ? Cela sonne encore comme des bonnes pratiques difficiles à mettre en Convaincu ? Cela sonne encore comme des bonnes pratiques difficiles à mettre en
œuvre, pouvant mettre en péril tout un système d'information. Pour s'en œuvre, pouvant mettre en péril tout un système d'information. Pour s'en
@ -38,13 +38,13 @@ propager à cause de l'usage d'une image parente pas à jour.
[^dockerhubvulnerability]: <https://www.enck.org/pubs/shu-codaspy17.pdf> [^dockerhubvulnerability]: <https://www.enck.org/pubs/shu-codaspy17.pdf>
Une mesure efficace consiste à reconstruire régulièrement (et surtout Une mesure efficace consiste à reconstruire régulièrement (et surtout
automatiquement) les images que l'on publie sur un registre public, sans automatiquement) les images que l'on publie sur un registre, sans oublier de
oublier de mettre à jour l'image de base. mettre à jour l'image de base.
D'ailleurs, avez-vous vérifié qu'une mise à jour de l'image `nemunaire/youp0m` D'ailleurs, avez-vous vérifié qu'une mise à jour de l'image
n'était pas disponible depuis que vous avez commencé à l'utiliser ? Docker ne `registry.nemunai.re/youp0m` n'était pas disponible depuis que vous avez
vérifie jamais si une mise à jour des images que vous avez précédemment commencé à l'utiliser ? Docker ne vérifie jamais si une mise à jour des images
téléchargées. Pensez donc régulièrement à appeler : que vous avez précédemment téléchargées. Pensez donc régulièrement à appeler :
<div lang="en-US"> <div lang="en-US">
``` ```
@ -67,7 +67,7 @@ intermédiaire.
::::: {.warning} ::::: {.warning}
Par cette méthode, vous êtes limité à 10 scans par mois. Par cette méthode, vous êtes limité à 10 scans par mois avec un compte gratuit.
::::: :::::
@ -102,17 +102,17 @@ commencer notre analyse :
<div lang="en-US"> <div lang="en-US">
``` ```
42sh$ docker scan nemunaire/fic-admin 42sh$ docker scan nemunaire/youp0m
Testing nemunaire/fic-admin... Testing nemunaire/youp0m...
Package manager: apk Package manager: apk
Project name: docker-image|nemunaire/fic-admin Project name: docker-image|nemunaire/youp0m
Docker image: nemunaire/fic-admin Docker image: nemunaire/youp0m
Platform: linux/amd64 Platform: linux/amd64
Base image: alpine:3.14.2 Base image: alpine:3.16.2
✓ Tested 16 dependencies for known vulnerabilities, no vulnerable paths found. ✓ Tested 15 dependencies for known vulnerabilities, no vulnerable paths found.
According to our scan, you are currently using the most secure version of According to our scan, you are currently using the most secure version of
the selected base image the selected base image
@ -142,9 +142,9 @@ Package manager: deb
Project name: docker-image|mysql Project name: docker-image|mysql
Docker image: mysql Docker image: mysql
Platform: linux/amd64 Platform: linux/amd64
Base image: mysql:8.0.26 Base image: mysql:8.0.30
Tested 135 dependencies for known vulnerabilities, found 79 vulnerabilities Tested 119 dependencies for known vulnerabilities, found 24 vulnerabilities
According to our scan, you are currently using the most secure version of According to our scan, you are currently using the most secure version of
the selected base image the selected base image
@ -152,8 +152,8 @@ the selected base image
</div> </div>
Ce dernier exemple est sans appel : `mysql` est une image officielle, et sa Ce dernier exemple est sans appel : `mysql` est une image officielle, et sa
dernière version à l'écriture de ses lignes contient pas moins de 79 dernière version à l'écriture de ses lignes contient pas moins de 24
vulnérabilités dont 11 *high*. vulnérabilités dont 9 *high* (pourtant corrigées dans des versions suivantes).
## Trivy ## Trivy
@ -176,16 +176,16 @@ Tentons à nouveau d'analyser l'image `mysql` :
<div lang="en-US"> <div lang="en-US">
``` ```
42sh$ docker run --rm aquasec/trivy mysql 42sh$ docker run --rm aquasec/trivy image mysql
2021-09-22T10:27:46.509Z INFO Need to update DB INFO Need to update DB
2021-09-22T10:27:46.509Z INFO Downloading DB... 100.00% 14.41 MiB p/s 2s INFO Downloading DB... 100.00% 14.41 MiB p/s 2s
2021-09-22T10:27:56.556Z INFO Detected OS: debian INFO Detected OS: oracle
2021-09-22T10:27:56.556Z INFO Detecting Debian vulnerabilities... INFO Detecting Oracle vulnerabilities...
2021-09-22T10:27:56.579Z INFO Number of language-specific files: 0 INFO Number of language-specific files: 0
mysql (debian 10.10) mysql (oracle 8.6)
==================== ==================
Total: 158 (UNKNOWN: 5, LOW: 19, MEDIUM: 64, HIGH: 61, CRITICAL: 9) Total: 5 (UNKNOWN: 0, LOW: 0, MEDIUM: 4, HIGH: 1, CRITICAL: 0)
``` ```
</div> </div>
@ -193,24 +193,24 @@ Les résultats sont un peu différents qu'avec `docker scan`, mais on constate
que l'image `mysql` contient vraiment de nombreuses vulnérabilités. Même si que l'image `mysql` contient vraiment de nombreuses vulnérabilités. Même si
elles ne sont heureusement pas forcément exploitables directement. elles ne sont heureusement pas forcément exploitables directement.
Voyons maintenant s'il y a des différentes avec l'image `nemunaire/fic-admin` : Voyons maintenant s'il y a des différentes avec l'image `nemunaire/youp0m` :
<div lang="en-US"> <div lang="en-US">
``` ```
42sh$ docker run --rm aquasec/trivy nemunaire/fic-admin 42sh$ docker run --rm aquasec/trivy image nemunaire/youp0m
2021-09-22T10:29:48.091Z INFO Need to update DB INFO Need to update DB
2021-09-22T10:29:48.091Z INFO Downloading DB... 100.00% 15.98 MiB p/s 1s INFO Downloading DB... 100.00% 15.98 MiB p/s 1s
2021-09-22T10:29:51.902Z INFO Detected OS: alpine INFO Detected OS: alpine
2021-09-22T10:29:51.902Z INFO Detecting Alpine vulnerabilities... INFO Detecting Alpine vulnerabilities...
2021-09-22T10:29:51.903Z INFO Number of language-specific files: 1 INFO Number of language-specific files: 1
2021-09-22T10:29:51.903Z INFO Detecting gobinary vulnerabilities... INFO Detecting gobinary vulnerabilities...
nemunaire/fic-admin (alpine 3.14.2) nemunaire/youp0m (alpine 3.16.2)
=================================== ===================================
Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0) Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
srv/admin (gobinary) srv/youp0m (gobinary)
==================== ====================
Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0) Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
``` ```
@ -218,7 +218,7 @@ Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
Nous pouvons remarque que Trivy, en plus de faire l'analyse statique des Nous pouvons remarque que Trivy, en plus de faire l'analyse statique des
vulnérabilités de l'image, a aussi fait une analyse des dépendances du binaire vulnérabilités de l'image, a aussi fait une analyse des dépendances du binaire
`/srv/admin`. `/srv/youp0m`.
Trivy est en effet capable de rechercher des vulnérabilités par rapport aux Trivy est en effet capable de rechercher des vulnérabilités par rapport aux
dépendances connues de certains langages : Python, PHP, Node.js, .NET, Java, dépendances connues de certains langages : Python, PHP, Node.js, .NET, Java,

View File

@ -8,7 +8,7 @@ que l'on a réussi à faire précédemment en utilisant le `Dockerfile` suivant
<div lang="en-US"> <div lang="en-US">
```dockerfile ```dockerfile
FROM ubuntu:latest FROM ubuntu:jammy
RUN apt-get update RUN apt-get update
RUN apt-get install -y nano RUN apt-get install -y nano
@ -21,7 +21,16 @@ est suivie de ses arguments.
Dans notre exemple, nous utilisons `FROM`{.dockerfile} qui indique une image de Dans notre exemple, nous utilisons `FROM`{.dockerfile} qui indique une image de
départ à utiliser ; `RUN`{.dockerfile} est une commande qui sera exécutée dans départ à utiliser ; `RUN`{.dockerfile} est une commande qui sera exécutée dans
le conteneur, dans le but de le construire. le conteneur intermédiaire, dans le but de construire l'image. De la même
manière que les `docker container run` de la partie précédente.
::::: {.warning}
Vous avez remarqué que la première instruction que l'on utilise est
`FROM`. Chaque image construite par un `Dockerfile` doit dépendre d'une autre
image. Ici nous avons choisi de partir de l'image `ubuntu`.
:::::
Pour lancer la construction de la nouvelle image, créons un nouveau dossier ne Pour lancer la construction de la nouvelle image, créons un nouveau dossier ne
contenant que notre fichier `Dockerfile`, plaçons-nous ensuite dedans, puis contenant que notre fichier `Dockerfile`, plaçons-nous ensuite dedans, puis
@ -33,6 +42,23 @@ docker image build --tag=my_editor .
``` ```
</div> </div>
On utilise l'option `--tag` pour donner un nom et un tag à l'image qui
résultera de l'exécution de cette construction.
::::: {.warning}
#### Attention de ne pas oublier le point à la fin de la commande ! {-}
Vous n'êtes plus sans savoir que Docker se compose d'un client et d'un
serveur. Et c'est la partie serveur qui va s'occuper de construire l'image.
Le client transmet donc tout le contexte autour du Dockerfile (les fichiers,
dossiers, sons-dossiers) à partir du chemin qu'on lui indique en dernier
argument. Le point représente donc ici simplement le dossier courant. Tous les
fichiers et dossiers présents ici seront transmis au daemon.
:::::
Une fois la construction de l'image terminée, nous pouvons la lancer et Une fois la construction de l'image terminée, nous pouvons la lancer et
constater l'existence de notre éditeur favori : constater l'existence de notre éditeur favori :
@ -85,13 +111,17 @@ RUN service mysqld start && mysql -u root -p toor virli < /db.sql
``` ```
</div> </div>
Après le `RUN`{.dockerfile}, MySQL sera de nouveau tué.\ Après le `RUN`{.dockerfile}, MySQL sera de nouveau tué, mais la seconde
commande aura entre-temps pu ajouter des données.\
En aucun cas, une commande exécutée par un `RUN`{.dockerfile} se retrouvera en ::::: {.warning}
**En aucun cas, une commande exécutée par un `RUN`{.dockerfile} se retrouvera en
cours d'exécution lorsque l'on invoquera un conteneur par `docker container cours d'exécution lorsque l'on invoquera un conteneur par `docker container
run`. Seul la commande fournie par l'utilisateur ou la commande par défaut de run`. Seul la commande fournie par l'utilisateur ou la commande par défaut de
l'image sera exécutée au lancement d'un conteneur. l'image sera exécutée au lancement d'un conteneur.**
:::::
### Exposer des ports ### Exposer des ports
@ -131,6 +161,51 @@ Dans un autre terminal, lançons un `docker container ls`, pour consulter la col
Rendez-vous ensuite dans votre navigateur sur <http://localhost:49153/>. Rendez-vous ensuite dans votre navigateur sur <http://localhost:49153/>.
### Copier des fichiers dans l'image
Une autre action très courante est de vouloir recopier un fichier ou un binaire
dans notre image : un fichier de configuration, un produit de compilation, des
scripts pour contrôler l'exécution, ...
On va utiliser pour cela l'instruction `COPY` :
<div lang="en-US">
```
COPY myconfig.conf /etc/nginx/conf.d/my.conf
```
</div>
Cette instruction permet également de copier l'arborescence d'un dossier :
<div lang="en-US">
```
COPY myconfs/ etc/nginx/conf.d/
COPY mywebsite /usr/share/nginx/html/
```
</div>
::::: {.warning}
Le comportement de la copie de dossier est différente du comportement que l'on
a l'habitude d'avoir avec `cp -r`. Si la source du `COPY` est un dossier, c'est
son contenu qui sera recopié récursivement, habituellement avec `cp` le dossier
recopié puis son contenu.
Pour obtenir le même comportement, il faut bien indiquer une cible
incluant le nom du dossier :
<div lang="en-US">
```
COPY docker-entrypoint.d /docker-entrypoint.d
```
</div>
Le dossier sera créé s'il n'existe pas, et le contenu du dossier source ser
recopié.
:::::
:::::: {.exercice} :::::: {.exercice}
#### À vous de jouer {-} #### À vous de jouer {-}
@ -166,11 +241,76 @@ build`.
Les couches du cache peuvent être partagées entre plusieurs conteneurs, c'est Les couches du cache peuvent être partagées entre plusieurs conteneurs, c'est
ainsi que vous pouvez partager facilement une plus grosse partie du système de ainsi que vous pouvez partager facilement une plus grosse partie du système de
fichiers (rappelez-vous le principe d'union FS). fichiers.\
Pour profiter du cache, on va placer de préférence les étapes les plus Pour profiter au mieux du cache, on place les instructions qui sont le moins
génériques (qui seraient les plus susceptibles d'apparaître dans d'autres susceptibles de changer en haut du `Dockerfile`, celles qui changent le plus
images), en haut du `Dockerfile`. régulièrement à la fin. Ainsi, lorsqu'une reconstruction de l'image sera
nécessaire, on gagnera du temps puisque le cache sera utilisé jusqu'à la
première instruction changeante. Un `Dockerfile` bien ordonné peu facilement
faire gagner de nombreuses minutes à ses utilisateurs.
::::: {.question}
#### Quelle place cela prend-t-il sur mon disque ? {-}
Nous pouvons afficher la taille de chaque image via la commande `docker image
ls` :
<div lang="en-US">
```
42sh$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 2d389e545974 6 days ago 142MB
debian stable 9b4953ae981c 7 days ago 124MB
nemunaire/youp0m latest 2c06880e48aa 12 days ago 25MB
```
</div>
Si vous avez beaucoup d'images, cela peut paraître beaucoup, mais rappelez-vous
que les images sont composées de couches qui sont souvent partagées entre
plusieurs conteneurs.
Si on regarde l'espace vraiment utilisé, il est moindre :
<div lang="en-US">
```
42sh$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 3 3 167MB 0B
Containers 0 0 0B 0B
Local Volumes 0 0 0B 0B
Build Cache 0 0 0B 0B
```
</div>
:::::
Les couches partagées sont un gain non négligeable pour l'espace de stockage !
Par exemple, prenons le `Dockerfile` suivait :
<div lang="en-US">
```Dockerfile
FROM python:3.10
COPY build /usr/lib/python/grapher
EXPOSE 8080
RUN pip install pillow pygal
```
</div>
Il y a de fortes chances pour que vous travailliez sur le code de
l'application, le dossier `build` sera donc très souvent mis à jour, alors que
les dépendances ne bougeront sans doute plus ...
Avec un tel `Dockerfile`, dès que le dossier `build` sera mis à jour les
dépendances seront à nouveau téléchargées, puisque toutes les couches suivant
la première qui change sont invalidées.
Une approche plus optimale serait donc de faire la `COPY` en dernier, car c'est
l'opération qui changera le plus souvent. L'idéal étant que 90 % des
reconstructions ne refassent que la dernière instruction, toutes les autres
devraient être récupérées du cache.
### Métadonnées pures ### Métadonnées pures
@ -181,7 +321,7 @@ sous forme de clef/valeur.
Une métadonnée courante[^MAINTAINER] est d'indiquer le nom du Une métadonnée courante[^MAINTAINER] est d'indiquer le nom du
mainteneur de l'image : mainteneur de l'image :
[^MAINTAINER]: Voir par exemple : <https://github.com/nginxinc/docker-nginx/blob/master/stable/debian/Dockerfile#L8> [^MAINTAINER]: Voir par exemple : <https://github.com/nginxinc/docker-nginx/blob/master/stable/debian/Dockerfile#L8>
<div lang="en-US"> <div lang="en-US">
```dockerfile ```dockerfile
@ -222,6 +362,9 @@ constatez via un `docker container ls` que le conteneur s'arrête directement,
retirez cette option pour voir ce qui ne va pas, ou utilisez la commande retirez cette option pour voir ce qui ne va pas, ou utilisez la commande
`docker container logs`. `docker container logs`.
Comme les `LABEL`, ce n'est pas une instruction qui change régulièrement. On la
place plutôt au début du `Dockerfile`.
### Construire son application au moment de la construction du conteneur ? ### Construire son application au moment de la construction du conteneur ?
@ -257,8 +400,8 @@ CMD ["/hello"]
``` ```
</div> </div>
Dans cet exemple, deux conteneurs distincts sont créés : le premier à partir de Dans cet exemple, deux images distinctes sont créées : la première à partir de
l'image `gcc`, il contient tout le nécessaire pour compiler notre l'image `gcc`, elle contient tout le nécessaire pour compiler notre
`hello.c`. Mais l'image finale (le dernier `FROM`{.dockerfile} de notre `hello.c`. Mais l'image finale (le dernier `FROM`{.dockerfile} de notre
`Dockerfile`) est l'image vide, dans laquelle nous recopions simplement le `Dockerfile`) est l'image vide, dans laquelle nous recopions simplement le
produit de notre compilation. produit de notre compilation.
@ -302,10 +445,23 @@ sélectionnera ainsi avec l'option `--target` l'un ou l'autre en fonction de
l'environnement dans lequel on souhaite se déployer. l'environnement dans lequel on souhaite se déployer.
### Déclarer des volumes
Tout comme nous pouvons déclarer préalablement dans le `Dockerfile` les ports qui
sont normalement exposés par le conteneur, nous pouvons déclarer les
volumes. L'instruction pour cela est `VOLUME`.
Il convient de l'utiliser pour déclarer les emplacements qui vont par défaut
contenir des données à faire persister. Ce serait le cas de `/var/lib/mysql`
pour les conteneurs MariaDB ou MySQL, `/images/` pour notre image `youp0m` ...
### D'autres instructions ? ### D'autres instructions ?
Consultez <https://docs.docker.com/engine/reference/builder/> pour la liste Nous avons fait le tour des principales instructions et de leurs différents
complète des instructions reconnues. usages *classiques*. Il existe quelques autres instructions que nous n'avons
pas présentées ici, pour aller plus loin, consultez la référence sur :\
<https://docs.docker.com/engine/reference/builder/>
::::: {.exercice} ::::: {.exercice}
@ -324,11 +480,16 @@ Pour compiler le projet, vous pouvez utiliser dans votre `Dockerfile`
<div lang="en-US"> <div lang="en-US">
```dockerfile ```dockerfile
FROM golang:1.16 FROM golang:1.18
COPY . /go/src/git.nemunai.re/youp0m COPY . /go/src/git.nemunai.re/youp0m
WORKDIR /go/src/git.nemunai.re/youp0m WORKDIR /go/src/git.nemunai.re/youp0m
RUN go build -tags dev -v RUN go build -tags dev -v
``` ```
</div> </div>
Remarquez la puissance de Docker : vous n'avez sans doute pas de compilateur Go
installé sur votre machine, et pourtant, en quelques minutes et à partir du
seul code source de l'application et d'un `Dockerfile`, vous avez pu compiler sur
votre poste le binaire attendu. WOW, non ?
::::: :::::

View File

@ -70,7 +70,7 @@ possibilité de le surcharger au moyen d'un argument :
``` ```
</div> </div>
::::: {.exerice} ::::: {.exercice}
## Personnalisation basique ## Personnalisation basique
@ -187,3 +187,23 @@ You are not allowed to perform this request.
</div> </div>
::::: :::::
## Étendre un `ENTRYPOINT` existant
Vous venez de réaliser un script d'*entrypoint* pour votre conteneur. Il ajoute
assurément de nombreuses fonctionnalités indispensables. Mais que se passe-t-il
si quelqu'un souhaite étendre votre image, ou simplement pour ajouter une
fonctionnalité ?
La plupart des images officielles[^cf-nginx] prêtes à l'emploi disposent d'un
dossier `/docker-entrypoint.d`, à la racine de l'image ; et d'un script
d'*entrypoint* qui va se charger d'appeler chacun des scripts du dossier avant
de lancer la commande par défaut.
[^cf-nginx]: Consultez le dépôt de l'image `nginx` par exemple. Il possède 3
scripts pour 3 fonctionnalités différentes.
Chaque fonctionnalité distincte de l'*entrypoint* est placée dans un script
séparé, et quelqu'un qui souhaite ajouter son propre script peut le faire
facilement, soit au moyen d'un volume, soit en étendant l'image.

View File

@ -13,7 +13,7 @@ faire fonctionner notre service de monitoring.
## `RUN` ou script ? ## `RUN` ou script ?
### InfluxDB ### InfluxDB
@ -23,7 +23,7 @@ n'est pas disponible dans les dépôts[^debrepos]. La
télécharger le paquet mis à disposition puis à l'installer via `dpkg -i`. télécharger le paquet mis à disposition puis à l'installer via `dpkg -i`.
[^debrepos]: Le projet met à disposition des dépôts, si vous préférez cette [^debrepos]: Le projet met à disposition des dépôts, si vous préférez cette
méthode, consultez la méthode, consultez-la
[documentation d'installation](https://docs.influxdata.com/influxdb/v1.6/introduction/installation/#ubuntu-debian). [documentation d'installation](https://docs.influxdata.com/influxdb/v1.6/introduction/installation/#ubuntu-debian).
Deux solutions s'offrent à nous : Deux solutions s'offrent à nous :
@ -33,7 +33,7 @@ Deux solutions s'offrent à nous :
préalable de `wget`/`curl`). préalable de `wget`/`curl`).
La copie étant définitive (supprimer le fichier ne le supprimera pas des La copie étant définitive (supprimer le fichier ne le supprimera pas des
couches où il a pu exister), on préférera la seconde méthode, malgré que `wget` couches où il a pu exister), on préférera la seconde méthode, bien que `wget`
restera en déchet. La première méthode aura plus sa place dans un dépôt de restera en déchet. La première méthode aura plus sa place dans un dépôt de
projet où les binaires auront été préalablement compilés, il ne restera plus projet où les binaires auront été préalablement compilés, il ne restera plus
qu'à les copier dans le conteneur au bon emplacement. qu'à les copier dans le conteneur au bon emplacement.
@ -48,8 +48,8 @@ d'InfluxDB, qui va l'installer et supprimer le fichier.
Il est possible que vous ayez à écraser le fichier de configuration via un Il est possible que vous ayez à écraser le fichier de configuration via un
`COPY` (ou de manière plus maligne en utilisant `--volume` au moment du `docker `COPY` (ou de manière plus maligne en utilisant `--volume` au moment du `docker
run`, cela ne fonctionne pas qu'avec les dossiers !). Ou peut-être ferez-vous run`, cela ne fonctionne pas qu'avec les dossiers !). Ou peut-être ferez-vous
un `ENTRYPOINT` ? un `ENTRYPOINT` ?
### `telegraf` ### `telegraf`

View File

@ -1,5 +1,3 @@
\newpage
Les bonnes pratiques Les bonnes pratiques
-------------------- --------------------
@ -247,3 +245,28 @@ processus par conteneur. Il est préférable de répartir chaque application dan
un conteneur distinct qui n'effectue que le travail pour lequel il est un conteneur distinct qui n'effectue que le travail pour lequel il est
chargé. Les options de liaison entre conteneur sont à votre disposition pour chargé. Les options de liaison entre conteneur sont à votre disposition pour
vous aider à cette tâche. vous aider à cette tâche.
## De l'intérêt de faire des images minimales
À l'inverse de langages comme Javascript, Python, Java et bien
d'autres, le langage Go compile, comme le C, vers du code directement
exécutable par le processeur. Tandis que les langages interprétés ont
besoin de leur interpréteur et de leur environnement d'exécution, les
langages compilés n'ont pas besoin d'être distribués avec leur
compilateur.
Prenons le temps de regarder les tailles des images :
<div lang="en-US">
```
42sh$ docker image ls -f reference=golang -f reference=youp0m
REPOSITORY TAG IMAGE ID CREATED SIZE
golang 1-alpine 155ead2e66ca 3 months ago 328MB
nemunaire/youp0m latest 2c06880e48aa 2 days ago 25MB
```
</div>
L'image contenant le compilateur Go est bien plus lourde que l'image
minimale que l'on a construite avec le binaire compilé. C'est autant
d'espace et de performances gagnées.

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -59,18 +59,86 @@ avec la commande `commit` :
<div lang="en-US"> <div lang="en-US">
```bash ```bash
docker container commit CONTAINER my_nano 42sh$ docker ps
CONTAINER ID IMAGE COMMAND STATUS NAMES
91d17871d730 ubuntu "bash" Exited (0) musing_tu
docker container commit 91d17871d730 my_nano
``` ```
</div> </div>
en remplaçant `CONTAINER` par le nom ou l'identifiant du container qui en remplaçant `91d17871d730` par le nom ou l'identifiant du container qui
doit servir de modèle. `my_nano` est le nom que vous voudrez utiliser doit servir de modèle. `my_nano` est le nom que vous voudrez utiliser
à la place d'`ubuntu`. à la place d'`ubuntu`.
L'action de *commit*, malgré le fait qu'elle crée une nouvelle image est très
rapide : il se trouve que seules les différences avec l'image parente sont
packagées. Les images sont en fait composées de couches : empilant les
différences depuis le système de base !
Cette action va figer la couche la plus haute de systèmes de fichiers, qui
était jusqu'alors en lecture-écriture pour le conteneur ; afin d'en faire la ### À propos des couches
dernière couche de notre nouvelle image.
Revenons quelque-peu en arrière : lorsque nous avons fait notre premier `docker
run hello-world`, rappelez-vous, Docker a téléchargé l'image en nous affichant
la progression, juste avant de lancer le conteneur.
Analysons ensemble ces quelques lignes pour mieux comprendre de quoi les images
se composent. Nous allons pour cela utiliser la commande `pull` pour récupérer
une nouvelle image :
<div lang="en-US">
```bash
42sh$ docker image pull python:3
3: Pulling from library/python
23858da423a6: Pull complete
326f452ade5c: Pull complete
a42821cd14fb: Pull complete
8471b75885ef: Pull complete
8ffa7aaef404: Pull complete
15132af73342: Pull complete
aaf3b07565c2: Pull complete
736f7bc16867: Pull complete
94da21e53a5b: Pull complete
Digest: sha256:e9c35537103a2801a30b15a77d4a56b35532c964489b125ec1ff24f3d5b53409
Status: Downloaded newer image for python:3
docker.io/library/python:3
```
</div>
On remarque que plusieurs téléchargement ont lieu, chacun associé à un
identifiant particulier. Une image est généralement découpée en plusieurs
éléments. On parle en fait de *couches* puisqu'on les empile, dans un ordre
précis.
Les couches sont une astuce formidable pour optimiser tant le téléchargement,
l'espace de stockage nécessaire au cache d'images, que la création des
conteneurs. De nombreux conteneurs vont utiliser les mêmes images de base :
`debian`, `ubuntu`, `alpine`, ... il serait futile de systématiquement
récupérer et stocker autant de systèmes de fichiers de base que d'images. Avec
les couches, si deux images partagent la même version du système de fichiers de
base, il ne sera téléchargé qu'une seule fois. On pourait le schématiser ainsi :
![L'héritage des principales images officielles](image-inheritance.png)
Dans les faits, cela va même encore plus loin car Docker crée de nombreuses
couches intermédiaires, chacune peut être l'occasion d'une bifurcation.\
Chaque couche est en fait un différentiel des dossiers et fichiers qui sont
ajoutés, modifiés ou supprimés par rapport à la couche précédente.
::::: {.question}
#### Comment supprimer les couches d'images que je n'utilise plus ? {-}
Docker gère lui-même les couches, vous n'avez pas à vous en préoccuper. Si une
image est mise à jour ou supprimée, toutes les couches rendues inutiles seront
automatiquement supprimées.
:::::
Revenons au *commit* que nous avons fait précédemment. Nous avons ajouté `nano`
par-dessus une image `ubuntu`. Naturellement, voici ce qu'il s'est passé :
![`docker commit`](commit.png) ![`docker commit`](commit.png)
@ -82,8 +150,13 @@ docker container run -it my_nano /bin/bash
``` ```
</div> </div>
Vous constatez cette fois que vous pouvez lancer `nano`, alors que vous ne Vous constatez cette fois que vous pouvez lancer `nano` !
pouvez toujours pas le faire dans un conteneur issu d'une image `ubuntu` !
Nous avons donc créé une couche, elle contient juste le différentiel des
fichiers ajoutés, à savoir le binaire `nano` et sa configuration par défaut
(mais aussi le cache du gestionnaire de paquets `apt`).
Voyons maintenant comment automatiser cela.
### Scripté ? ### Scripté ?

View File

@ -3,7 +3,7 @@ D'autres méthodes pour créer des images
Les images utilisées par Docker pour lancer les conteneurs répondent avant tout Les images utilisées par Docker pour lancer les conteneurs répondent avant tout
aux spécifications OCI. Le format étant standard, il est normal que d'autres aux spécifications OCI. Le format étant standard, il est normal que d'autres
outils puissent utiliser mais aussi créer des images. Nous allons voir dans outils puissent utiliser, mais aussi créer des images. Nous allons voir dans
cette partie l'avenir des `Dockerfile` ou simplement d'autres outils plus cette partie l'avenir des `Dockerfile` ou simplement d'autres outils plus
spécifiques. spécifiques.
@ -30,7 +30,7 @@ vous pouvez l'installer comme ceci :
<div lang="en-US"> <div lang="en-US">
``` ```
V="v0.6.3" V="v0.9.1"
mkdir -p ~/.docker/cli-plugins mkdir -p ~/.docker/cli-plugins
curl -L -s -S -o ~/.docker/cli-plugins/docker-buildx \ curl -L -s -S -o ~/.docker/cli-plugins/docker-buildx \
https://github.com/docker/buildx/releases/download/$V/buildx-$V.linux-amd64 https://github.com/docker/buildx/releases/download/$V/buildx-$V.linux-amd64
@ -63,12 +63,12 @@ Actions* :\
Parfois on peut se sentir un peu frustré par la syntaxe des `Dockerfile` ou par Parfois on peut se sentir un peu frustré par la syntaxe des `Dockerfile` ou par
son manque d'évolutivité. Avec BuildKit, il est possible de préciser un parseur son manque d'évolutivité. Avec BuildKit, il est possible de préciser un parseur
à utiliser pour l'évaluation de la syntaxe du `Dockerfile`. Les parseurs à utiliser pour l'évaluation de la syntaxe du `Dockerfile`. Les parseurs
(*frontend* dans la documentation en anglais) sont des images Docker, on (*frontend* dans la documentation anglaise) sont des images Docker : on indique
indique leur nom dans un commentaire au tout début du fichier : leur nom dans un commentaire au tout début du fichier :
<div lang="en-US"> <div lang="en-US">
```dockerfile ```dockerfile
# syntax=docker/dockerfile:1.2 # syntax=docker/dockerfile:1.4
FROM ubuntu FROM ubuntu
RUN apt-get update && apt-get install gimp RUN apt-get update && apt-get install gimp
``` ```
@ -105,11 +105,10 @@ notamment :
`Dockerfile`, et autres scripts de CI et de tests. `Dockerfile`, et autres scripts de CI et de tests.
#### `docker/dockerfile:1.3` #### `docker/dockerfile:1.4`
La version habituelle de la syntaxe des `Dockerfile` est la version 1.1. En La version habituelle de la syntaxe des `Dockerfile` est la version 1.1. En
utilisant BuildKit, nous pouvons dès à présent passer à la version 1.2 (stable) utilisant BuildKit, nous pouvons dès à présent passer à la version 1.4.
ou 1.3 (expérimentale).
Les ajouts par rapport à la syntaxe usuelle sont répertoriés sur cette page :\ Les ajouts par rapport à la syntaxe usuelle sont répertoriés sur cette page :\
<https://hub.docker.com/r/docker/dockerfile>. <https://hub.docker.com/r/docker/dockerfile>.
@ -128,7 +127,9 @@ Il est aussi possible de se passer complètement de Docker. La plupart des
outils qui sont capables de générer des images de machines virtuelles, sont outils qui sont capables de générer des images de machines virtuelles, sont
aussi capables de générer des images Docker. Citons notamment : aussi capables de générer des images Docker. Citons notamment :
- [Hashicorp Packer](https://www.packer.io/docs/builders/docker), - Buildah : <https://github.com/containers/buildah/> (utilisé par `podman`),
- [Nix et Guix](https://nix.dev/tutorials/building-and-running-docker-images), - Buildpacks : <https://buildpacks.io/>,
- [Kubler](https://github.com/edannenberg/kubler), - Hashicorp Packer : <https://www.packer.io/docs/builders/docker>,
- Nix et Guix : <https://nix.dev/tutorials/building-and-running-docker-images>,
- Kubler : <https://github.com/edannenberg/kubler>,
- et bien d'autres. - et bien d'autres.