tuto2 corrected and ready

This commit is contained in:
nemunaire 2021-09-24 17:12:07 +02:00
parent 2c5317f4f9
commit 15236db9af
14 changed files with 124 additions and 136 deletions

Binary file not shown.

View File

@ -12,18 +12,20 @@ jour.
Le service doit être accessible sur votre réseau local, sur un port
configurable.
Votre playbook devrait se limiter au module
[`docker-container`](https://docs.ansible.com/ansible/latest/modules/docker_container_module.html)
(ie. sans utiliser `docker-compose` ou `docker stack` que l'on verra dans un
second temps).
Sur la partie Docker, votre playbook devra se limiter aux modules
[`docker-container`](https://docs.ansible.com/ansible/latest/collections/community/docker/docker_container_module.html),
[`docker-network`](https://docs.ansible.com/ansible/latest/collections/community/docker/docker_network_module.html),
[`docker-volume`](https://docs.ansible.com/ansible/latest/collections/community/docker/docker_volume_module.html)
(ie. sans utiliser `docker-compose` ou `docker stack`).
Cette instance devra utiliser une base de données MySQL ou Postgres (lancée par
vos soins dans un autre conteneur) et contenir ses données dans un ou plusieurs
volumes (afin qu'elles persistent notamment à une mise à jour des conteneurs).
Cette instance devra utiliser une base de données MySQL/MariaDB ou Postgres
(lancée par vos soins dans un autre conteneur) et contenir ses données dans un
ou plusieurs volumes (afin qu'elles persistent notamment à une mise à jour des
conteneurs).
L'exécution doit être la plus sécurisée possible (pas de port MySQL exposé sur
l'hôte par exemple, etc.) et la plus respectueuse des bonnes pratiques que l'on
a pu voir durant ce premier cours.
a pu voir durant le cours.
## Exemple d'exécution

View File

@ -16,8 +16,10 @@ 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.
Par ailleurs, n'oubliez pas de répondre à
[l'évaluation du cours](https://www.epitaf.fr/moodle/mod/quiz/view.php?id=213).
Afin d'orienter correctement votre rendu, ajoutez une balise `[PROJET1]` 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
@ -31,9 +33,9 @@ cela dépendra de votre avancée dans le projet) :
<div lang="en-US">
```
login_x-TP1/
login_x-TP1/my_cloud.yml
login_x-TP1/roles/...
login_x-project1/
login_x-project1/my_cloud.yml
login_x-project1/roles/...
```
</div>
@ -52,67 +54,3 @@ Pour valider la signature, il est nécessaire d'avoir reçu la clef publique
**séparément**. Vous avez le choix de l'uploader sur un serveur de clefs, soit
de me fournir votre clef en main propre, soit l'envoyer dans un courriel
distinct.
### Signature du courriel
[Enigmail](https://enigmail.net) est une extension très bien réputée pour
signer ses mails depuis Thunderbird.
Utilisez le service automatique <signcheck@nemunai.re> pour savoir si votre
courriel est correctement signé et que je suis en mesure de vérifier la
signature.
### Astuces
#### No public key
Si vous recevez un rapport avec l'erreur suivante :
<div lang="en-US">
```
[FAIL] Bad signature. Here is the gnupg output:
gpg: Signature made Tue Jan 01 16:42:23 2014 CET
gpg: using RSA key 842807A84573CC96
gpg: requesting key E2CCD99DD37BD32E from hkp server keys.openpgp.org
gpg: Can't check signature: No public key
```
</div>
C'est que votre clef publique n'est pas dans mon trousseau et que les
méthodes de récupération automatique n'ont pas permis de la
trouver. Uploadez votre clef sur [un serveur de
clefs](https://keys.openpgp.org/) ou envoyez un courriel au service
avec votre clef publique en pièce-jointe, avant de retenter votre
rendu.
#### Not explicit username
Si vous recevez un rapport avec l'erreur suivante :
<div lang="en-US">
```
[FAIL] The username of your key is not explicit, I can't find you.
```
</div>
Votre clef ne contient sans doute pas vos noms et prénoms ou l'adresse
électronique associée à la clef n'est pas celle que j'ai dans ma base de
données.
#### I've decided to skip your e-mail
Si vous recevez un rapport concluant ainsi :
<div lang="en-US">
```
After analyzing your e-mail, I've decided to SKIP it.
```
</div>
Cela signifie que la lecture de votre courriel qui a été préférée n'est pas
celle d'un rendu. Vérifiez que vous n'envoyez pas votre clef publique avec
votre rendu.

View File

@ -2,5 +2,11 @@
title: Virtualisation légère -- Projet n^o^ 1
author: Pierre-Olivier *nemunaire* Mercier
institute: EPITA
date: EPITA -- SRS 2021
date: EPITA -- Promo 2022
abstract: |
Le rendu de ce projet est attendu par courrier électronique signé à
<virli@nemunai.re> au plus tard le **mercredi 13 octobre 2021 à 23 h
42**.
Ce projet est **obligatoire pour tous les SRS**, et optionnel pour les GISTRE.
...

View File

@ -3,6 +3,16 @@
Rendu
=====
Est attendu d'ici le TP suivant :
- le rendu des exercice de ce TP ;
- vos réponses à [l'évaluation du cours](https://virli.nemunai.re/quiz/12).
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
------------------
@ -18,8 +28,10 @@ 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.
Par ailleurs, n'oubliez pas de répondre à
[l'évaluation du cours](https://virli.nemunai.re/quiz/4).
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
@ -34,12 +46,15 @@ supplémentaires) :
<div lang="en-US">
```
login_x-TP2/
login_x-TP2/youp0m/
login_x-TP2/my_webservice/ # 1.2.2 + 1.3
login_x-TP2/my_webservice/Dockerfile
login_x-TP2/my_webservice/index.html
login_x-TP2/youp0m/ # 1.2.7 + 1.3
login_x-TP2/youp0m/Dockerfile
login_x-TP2/youp0m/entrypoint.sh
login_x-TP2/youp0m/entrypoint.sh # 2.2.2
login_x-TP2/youp0m/.dockerignore
login_x-TP2/youp0m/...
login_x-TP2/mysql:latest.html # rapport d'analyse PAclair, Trivy, ...
login_x-TP2/mysql:latest.html # rapport d'analyse PAclair/Trivy/...
login_x-TP2/....html
```
</div>

View File

@ -1,6 +1,6 @@
include ../pandoc-opts.mk
SOURCES = tutorial.md oci.md runc.md linuxkit.md linuxkit-admin.md linuxkit-content.md rendu.md
SOURCES = tutorial.md oci.md runc.md linuxkit.md linuxkit-adlin.md linuxkit-content.md rendu.md
all: tutorial.pdf

View File

@ -7,14 +7,14 @@ supplémentaires des applications métiers (Trivy est capable d'analyser les
dépendances PHP, Python, Ruby, Go, ...).
La mise en œuvre de Clair est un peu plus complexe car il s'agit d'un *daemon*
qui s'exécute en permanence, et auquel on peut transmettre via une API, nos
qui s'exécute en permanence, et auquel on peut transmettre, via une API, nos
images. Dans un contexte d'intégration continue, ou d'un registre d'images qui
teste régulièrement ses images hébergées, c'est un outil idéal. Néanmoins il
faut le configurer un minimum pour qu'il soit opérationnel. Consultez [l'annexe
dédiée](https://virli.nemunai.re/tutorial-2-clair.pdf) si vous souhaitez opter
pour cette solution.
On notera tout de même que les outils sont donnés pour générer des rapports
HTML avec des graphiques explicites :
On notera tout de même que les outils donnés générent des rapports HTML avec
des graphiques explicites :
![Rapport d'analyse statique des vulnérabilités par Clair](paclair.png)

View File

@ -1,8 +1,7 @@
## Exercice {-}
Déterminez le nombre de vulnérabilités dans les principales images officielles
du [Docker Hub](https://hub.docker.com/explore), notamment `nginx`, `golang`,
`redis`, ...
du [Docker Hub](https://hub.docker.com/explore).
En utilisant l'outil de votre choix, exporter un rapport HTML (ou la sortie
standard de l'outil s'il n'exporte pas en HTML) de l'image **officielle**

View File

@ -229,7 +229,8 @@ analyses. Préférez lancer `trivy` avec les options suivantes :
<div lang="en-US">
```
42sh$ docker run --rm -v /tmp/trivy-cache:/tmp/trivy/ aquasec/trivy --cache-dir /tmp/trivy
42sh$ docker run --rm -v /tmp/trivy-cache:/tmp/trivy/ aquasec/trivy \
--cache-dir /tmp/trivy IMAGE
```
</div>

View File

@ -26,7 +26,7 @@ départ à utiliser ; `RUN`{.dockerfile} est une commande qui sera exécutée da
le conteneur, dans le but de le construire.
Pour lancer la construction de la nouvelle image, créons un nouveau dossier ne
contenant que votre fichier `Dockerfile`, plaçons-nous ensuite dedans, puis
contenant que notre fichier `Dockerfile`, plaçons-nous ensuite dedans, puis
lançons la commande `build` :
<div lang="en-US">
@ -50,7 +50,7 @@ docker container run -it my_editor /bin/bash
Dans un `Dockerfile`, chaque ligne est exécutée indépendamment des autres et
correspondra à une nouvelle couche de notre image. Exactement comme on a
réalisé le script dans la partie précédente.
réalisé le script à la fin de la partie précédente.
Cela signifie que l'exemple suivant **ne fonctionne pas** :
@ -76,7 +76,7 @@ docker container run tinysql service mysqld start
</div>
rend la main directement, sans laisser de `mysqld` dans l'arborescence de
processus.
processus.\
Pour avoir le résultat escompté, il faut exécuter les commandes ensemble :
@ -87,7 +87,7 @@ RUN service mysqld start && mysql -u root -p toor virli < /db.sql
```
</div>
Après le `RUN`{.dockerfile}, MySQL sera de nouveau tué.
Après le `RUN`{.dockerfile}, MySQL sera de nouveau tué.\
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
@ -112,7 +112,8 @@ EXPOSE 80
L'instruction `EXPOSE`{.dockerfile} sera traitée plus tard par le client Docker
(équivalent à l'argument `--expose`). Il s'agit d'une métadonnée qui sera
attachée à l'image (et à toutes ses images filles).
attachée à l'image (et à toutes ses images filles). Elle ne crée d'ailleurs pas
de couche supplémentaire dans notre image.\
En précisant tous les ports qu'expose une image dans ses métadonnées, ces
ports seront automatiquement exposés en utilisant l'option `-P` du `run` : cela
@ -127,8 +128,8 @@ conteneur :
```
</div>
Dans un autre terminal, lancer un `docker container ls` et consulter la colonne
*PORTS* pour connaître le port choisi par Docker pour effectuer la redirection.
Dans un autre terminal, lançons un `docker container ls`, pour consulter la colonne
*PORTS* afin de connaître le port choisi par Docker pour effectuer la redirection.
Rendez-vous ensuite dans votre navigateur sur <http://localhost:49153/>.
@ -177,7 +178,7 @@ L'instruction `LABEL`{.dockerfile} permet d'ajouter une métadonnée à une imag
sous forme de clef/valeur.
Une métadonnée
[courante](https://github.com/nginxinc/docker-nginx/blob/master/mainline/stretch/Dockerfile#L3)
[courante](https://github.com/nginxinc/docker-nginx/blob/master/stable/debian/Dockerfile#L8)
est d'indiquer le nom du mainteneur de l'image :
<div lang="en-US">

View File

@ -159,8 +159,8 @@ pouvons obtenir un fichier valide avec :
```
</div>
Il faut ensuite passer le fichier sur la ligne de commande grâce à l'option
`-htpasswd`.
Il faut ensuite passer le chemin du fichier créé sur la ligne de commande grâce
à l'option `-htpasswd`.
### Exercice {-}

View File

@ -11,14 +11,20 @@ bien, faites les modifications nécessaire dans votre `Dockerfile`.
Dans la plupart des cas, vos `Dockerfile` seront dans des dossiers contenant
beaucoup de fichiers qui ne sont pas nécessaire à la construction de votre
conteneur (par exemple, vous pouvez avoir un `Dockerfile` placé à la racine
d'un dépôt git : il va avoir besoin des binaires compilés, mais pas des
sources).
d'un dépôt git).
Afin d'améliorer les performances lors de la construction, vous pouvez exclure
les fichiers et dossiers inutiles au conteneur en ajoutant un fichier
`.dockerignore` dans le répertoire de votre `Dockerfile`.
Ce fichier fonctionne de la même manière que le `.gitignore` : vous pouvez
Vous pouvez exclure les produits intermédiaires de compilation (`*.o`, ...) si
vous utilisez un langage compilé, excluez également les produits de compilation
si votre image construit le binaire. Dans le cas de NodeJS, vous allez sans
doute vouloir exclure le dossier `node_modules` et faire un `npm install` dans
votre `Dockerfile`. Cela permettra au passage de s'assurer que toutes les
dépendances ont bien été enregistrée.
Ce fichier fonctionne de la même manière que le `.gitignore` : vous pouvez
utiliser du globing.
Pour plus d'informations, vous pouvez consulter la documentation accessible à
@ -28,7 +34,7 @@ Pour plus d'informations, vous pouvez consulter la documentation accessible à
### N'installez rien de superflu
Afin de réduire la quantité de dépendances à installer, n'installez pas de
paquets dont vous n'avez pas vraiment l'utilité : il n'y a pas de raison par
paquets dont vous n'avez pas vraiment l'utilité : il n'y a pas de raison par
exemple d'avoir un éditeur de texte dans un environnement qui sera utilisé
comme serveur web. Un autre conteneur pourra contenir cet éditeur de texte dans
les cas où vous avez besoin de modifier des données.
@ -56,14 +62,14 @@ place.
### Ordonnez vos lignes de commandes complexes
#### Allez à la ligne pour séparer les longues lignes de commandes complexes
#### Allez à la ligne pour séparer les longues lignes de commandes complexes\
Aérez vos `Dockerfile` !
N'hésitez pas à commenter et séparer les blocs logiques ensemble, comme lorsque
vous codez.
Lorsqu'une ligne devient complexe, allez à la ligne :
Lorsqu'une ligne devient complexe, allez à la ligne :
<div lang="en-US">
```dockerfile
@ -75,10 +81,10 @@ RUN apt-get update && apt-get install -y \
Notez les backslashs à la fin des lignes, indiquant qu'elle n'est pas terminée.
#### Triez les arguments par ordre alphabétique
#### Triez les arguments par ordre alphabétique\
Lorsque c'est possible, ordonnez vos lignes suivant un ordre logique. Par
exemple :
exemple :
<div lang="en-US">
```dockerfile
@ -99,7 +105,7 @@ votre Dockerfile dans l'ordre. Pour chaque instruction, Docker va essayer de
trouver si une image n'est pas déjà disponible dans le cache (plutôt que de
créer une nouvelle image identique).
Il y a un certain nombre de règles à connaître pour bien utiliser ce mécanisme :
Il y a un certain nombre de règles à connaître pour bien utiliser ce mécanisme :
- En démarrant d'une image de base déjà présente dans le cache (`docker
images`), l'instruction suivante est comparée avec toutes les autres images
@ -119,7 +125,7 @@ Il y a un certain nombre de règles à connaître pour bien utiliser ce mécanis
### Concevez des conteneur éphémères
Les conteneurs que vous générez doivent être aussi éphémères que possible : ils
Les conteneurs que vous générez doivent être aussi éphémères que possible : ils
devraient pouvoir être arrêtés, détruits et recréés sans nécessiter d'étape de
reconfiguration. La configuration devrait se faire au lancement du conteneur ou
lors de sa construction.
@ -139,14 +145,14 @@ lors de sa construction.
### Exposez les ports standards
La commande `EXPOSE`{.dockerfile} vous permet d'indiquer les ports sur lesquels
La commande `EXPOSE`{.dockerfile} permet d'indiquer les ports sur lesquels
votre conteneur s'attend à recevoir des paquets venant de l'extérieur. Ces
ports ne sont pas partagés avec l'hôte ou les autres conteneur, donc vous
ports ne sont pas partagés avec l'hôte ou les autres conteneurs, donc vous
n'avez pas de raison de ne pas utiliser les ports standards.
Si vous faites cela, il y a de forte chance qu'il n'y ait pas besoin de
modifier la configuration des autres logiciels contenu dans d'autres conteneurs
puis qu'ils sont généralement configurés pour se connecter aux ports standards.
puisqu'ils sont généralement configurés pour se connecter aux ports standards.
S'il y a un conflit sur la machine hôte, il sera toujours temps de créer une
redirection à ce moment là.
@ -154,11 +160,12 @@ redirection à ce moment là.
### La bonne utilisation de l'`ENTRYPOINT`
L'entrypoint peut être utilisé de deux manières différentes :
L'*entrypoint* (on le verra plus en détail dans la partie suivante) peut être
utilisé de deux manières différentes :
- Vous pouvez l'utiliser de telle sorte que la commande passée au `docker run`,
après le nom de l'image, corresponde aux arguments attendu par le programme
indiqué dans l'entrypoint. Par exemple pour nginx :
indiqué dans l'*entrypoint*. Par exemple pour nginx :
<div lang="en-US">
```dockerfile
@ -170,7 +177,7 @@ CMD ["-g", "daemon", "off;"]
- Vous pouvez aussi utiliser un script qui servira à faire les initialisations
ou les configurations nécessaire au bon fonctionnement du conteneur
(rappelez-vous, il doit être éphémère !). Par exemple, le `Dockerfile` pour
l'image de PostgreSQL possède cet entrypoint :
l'image de PostgreSQL possède cet entrypoint :
<div lang="en-US">
```bash
@ -195,22 +202,22 @@ exec "$@"
### `[""]`, `'` et sans `[]`
Les instructions `ENTRYPOINT`{.dockerfile} et `CMD`{.dockerfile} peuvent
prendre deux formes :
prendre deux formes :
- `["cmd", "arg1", "arg2"]` : ici, un simple `execve` sera effectué avec ces
- `["cmd", "arg1", "arg2"]` : ici, un simple `execve` sera effectué avec ces
arguments. Si d'éventuels variables se trouve dans les arguments, elles ne
seront pas remplacées.
- `cmd arg1 arg2` : ici l'exécution se fera au sein d'un `sh -c`, donc les
- `cmd arg1 arg2` : ici l'exécution se fera au sein d'un `sh -c`, donc les
variables seront remplacés et étendues.
Les commandes sous forme de tableau étant parsées par un parser JSON, vous ne
pouvez pas utiliser les simple quotes.
pouvez pas utiliser les *simples quotes*.
### Volumes
L'instruction `VOLUME`{.dockerfile} doit être utilisée pour exposer tous les
espaces de stockage de données, configuration,\ ...
espaces de stockage de données, configuration, ...
### Réduisez les privilèges
@ -218,7 +225,7 @@ espaces de stockage de données, configuration,\ ...
Utilisez l'instruction `USER`{.dockerfile} dès que vous le pouvez, lorsqu'un
service ne réclame pas de privilège particulier.
Il vous faudra sans doute créer l'utilisateur et son groupe dans le Dockerfile.
Il vous faudra sans doute créer l'utilisateur et son groupe dans le `Dockerfile`.
### Profitez du système de liaison et de résolution de nom

View File

@ -27,16 +27,23 @@ jour. De manière générale, il n'est pas recommandé de faire de mises à
jour automatiques et systématiques des éléments présents dans l'image,
à l'exception des mises à jour de sécurité[^SECURITY_UPDATE]. En effet, une mise à jour
qui apporte des changements peut altérer le comportement du conteneur,
en fonction de la date à laquelle on le construit.
en fonction de la date à laquelle on le construit. Car on ne sait pas d'avance
quelles versions de nos dépendances on va récupérer.
[^SECURITY_UPDATE]: Voir cet article :
<https://pythonspeed.com/articles/security-updates-in-docker/>
Si vous souhaitez disposez d'une nouvelle version de l'image, il est
plutôt recommandé de contacter le mainteneur de l'image pour qu'il la
mette à jour, en utilisant un nouveau tag s'il le juge nécessaire.
mette à jour, en utilisant un nouveau tag s'il le juge nécessaire. Si
cette solution n'est pas envisageable, alors il vaut mieux créer votre
propre image, à partir de l'image de base : vous serez alors vous-même
responsable de la bonne continuité de construction des images issues
de votre image, sans que cela soit hasardeux au moment de la
construction.\
Installons maintenant un programme :
La liste des paquets récupérés, installons maintenant un programme : notre
première image pourrait contenir notre éditeur de texte favori :
<div lang="en-US">
```bash
@ -45,10 +52,10 @@ apt-get install nano
</div>
Lorsque l'installation de `nano` est terminée, quittons l'image en tapant
`exit`.
`exit`.\
Sauvegardons nos modifications en tant que nouvelle image Docker, avec
la commande `commit` :
Nous allons sauvegarder nos modifications en tant que nouvelle image Docker,
avec la commande `commit` :
<div lang="en-US">
```bash
@ -100,4 +107,7 @@ docker container run -it my_nano /bin/bash
```
</div>
Contenant notre éditeur de texte favori.
contenant notre éditeur de texte favori.\
On ne va pas réaliser ce script ni l'étoffer, car il existe justement un
mécanisme de construction d'image : le `Dockerfile`.

View File

@ -102,6 +102,22 @@ notamment :
`Dockerfile`, et autres scripts de CI et de tests.
#### `docker/dockerfile:1.3`\
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)
ou 1.3 (expérimentale).
Les ajouts par rapport à la syntaxe usuelle sont répertoriés sur cette page :\
<https://hub.docker.com/r/docker/dockerfile>.
### Exercice {-}
Faites en sorte que le `Dockerfile` que vous avez créé pour `youp0m` indique un
*frontend* BuildKit à utiliser, tout en restant compatible avec la syntaxe du
`docker build` classique.
### Des images sans Docker
@ -113,10 +129,3 @@ aussi capable de générer des images Docker. Citons notamment :
- [Nix et Guix](https://nix.dev/tutorials/building-and-running-docker-images)
- [Kubler](https://github.com/edannenberg/kubler)
- et bien d'autres.
### Exercice {-}
Faites en sorte que le `Dockerfile` que vous avez créé pour `youp0m` indique un
`frontend` BuildKit à utiliser, tout en restant compatible avec la syntaxe du
`docker build` classique.