Update tuto2
This commit is contained in:
parent
5f097b4221
commit
2c5317f4f9
@ -12,7 +12,7 @@ abstract: |
|
|||||||
|
|
||||||
Le TP se termine par un petit projet à rendre à <virli@nemunai.re> au
|
Le TP se termine par un petit projet à rendre à <virli@nemunai.re> au
|
||||||
plus tard le **mercredi 22 septembre 2021 à 23 h 42**. Consultez la
|
plus tard le **mercredi 22 septembre 2021 à 23 h 42**. Consultez la
|
||||||
dernière section de chaque partie pour plus d'information sur les
|
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
|
éléments à rendre. Et n'oubliez pas de répondre aux [questions de
|
||||||
cours](https://virli.nemunai.re/quiz/11).
|
cours](https://virli.nemunai.re/quiz/11).
|
||||||
|
|
||||||
|
@ -1,15 +1,21 @@
|
|||||||
include ../pandoc-opts.mk
|
include ../pandoc-opts.mk
|
||||||
|
|
||||||
SOURCES = tutorial.md \
|
SOURCES = tutorial.md \
|
||||||
../dockerfiles/interactive.md ../dockerfiles/dockerfile.md ../dockerfiles/goodpractices.md ../dockerfiles/entrypoint.md \
|
../dockerfiles/what.md ../dockerfiles/interactive.md ../dockerfiles/dockerfile.md ../dockerfiles/goodpractices.md ../dockerfiles/others.md ../dockerfiles/entrypoint.md \
|
||||||
../docker-internals/clair.md \
|
../docker-internals/vulnerability-scan.md ../docker-internals/clair-tiny.md ../docker-internals/vulnerability-scan-ex.md \
|
||||||
rendu.md
|
rendu.md
|
||||||
|
|
||||||
|
SOURCES_CLAIR = tutorial-clair.md \
|
||||||
|
../docker-internals/clair.md
|
||||||
|
|
||||||
all: tutorial.pdf
|
|
||||||
|
|
||||||
tutorial.pdf: ${SOURCES}
|
all: tutorial-2.pdf tutorial-2-clair.pdf
|
||||||
|
|
||||||
|
tutorial-2.pdf: ${SOURCES}
|
||||||
|
pandoc ${PANDOCOPTS} -o $@ $+
|
||||||
|
|
||||||
|
tutorial-2-clair.pdf: ${SOURCES_CLAIR}
|
||||||
pandoc ${PANDOCOPTS} -o $@ $+
|
pandoc ${PANDOCOPTS} -o $@ $+
|
||||||
|
|
||||||
clean::
|
clean::
|
||||||
rm tutorial.pdf
|
rm tutorial-2.pdf
|
||||||
|
2621
tutorial/2/mysql-vulns.html
Normal file
2621
tutorial/2/mysql-vulns.html
Normal file
File diff suppressed because it is too large
Load Diff
1
tutorial/2/quay-vulns.png
Symbolic link
1
tutorial/2/quay-vulns.png
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../docker-internals/quay-vulns.png
|
@ -39,8 +39,10 @@ login_x-TP2/youp0m/Dockerfile
|
|||||||
login_x-TP2/youp0m/entrypoint.sh
|
login_x-TP2/youp0m/entrypoint.sh
|
||||||
login_x-TP2/youp0m/.dockerignore
|
login_x-TP2/youp0m/.dockerignore
|
||||||
login_x-TP2/youp0m/...
|
login_x-TP2/youp0m/...
|
||||||
login_x-TP2/clair/docker-compose.yml
|
login_x-TP2/mysql:latest.html # rapport d'analyse PAclair, Trivy, ...
|
||||||
login_x-TP2/clair/clair_config/config.yaml
|
login_x-TP2/....html
|
||||||
login_x-TP2/nginx:mainline.html # rapport d'analyse PAclair
|
|
||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
Inutile d'inclure le contenu du dépôt `youp0m` dans votre tarball. Placez-y
|
||||||
|
uniquement les fichiers que vous avez ajouté.
|
||||||
|
17
tutorial/2/tutorial-clair.md
Normal file
17
tutorial/2/tutorial-clair.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
title: Virtualisation légère -- TP n^o^ 2
|
||||||
|
subtitle: Construire des images Docker et leur sécurité -- Annexe
|
||||||
|
author: Pierre-Olivier *nemunaire* [Mercier]{.smallcaps}
|
||||||
|
institute: EPITA
|
||||||
|
date: Jeudi 23 septembre 2021
|
||||||
|
abstract: |
|
||||||
|
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
|
||||||
|
retrouverez dans cette annexe un guide pour le mettre en place et faire vos
|
||||||
|
premiers pas avec.
|
||||||
|
...
|
||||||
|
|
||||||
|
![Rapport d'analyse statique des vulnérabilités d'un conteneur](paclair.png)
|
||||||
|
|
||||||
|
Une vision plus Clair de la sécurité des images
|
||||||
|
-----------------------------------------------
|
@ -6,16 +6,16 @@ institute: EPITA
|
|||||||
date: Jeudi 23 septembre 2021
|
date: Jeudi 23 septembre 2021
|
||||||
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, 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}
|
\vspace{1em}
|
||||||
|
|
||||||
Tous les éléments de ce TP (exercices et projet) sont à rendre à
|
Tous les éléments de ce TP (exercices et projet) sont à rendre à
|
||||||
<virli@nemunai.re> au plus tard le **jeudi 22 octobre 2020 à 12 h
|
<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'information
|
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
|
sur les éléments à rendre. Et n'oubliez pas de répondre aux [questions de
|
||||||
cours](https://virli.nemunai.re/quiz/4).
|
cours](https://virli.nemunai.re/quiz/12).
|
||||||
|
|
||||||
En tant que personnes sensibilisées à la sécurité des échanges électroniques,
|
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 à
|
vous devrez m'envoyer vos rendus signés avec votre clef PGP. Pensez à
|
||||||
|
@ -13,7 +13,7 @@ abstract: |
|
|||||||
|
|
||||||
Certains éléments de ce TP sont à rendre à <virli@nemunai.re> au
|
Certains éléments de ce TP sont à rendre à <virli@nemunai.re> au
|
||||||
plus tard le jeudi 12 novembre 2020 à 12 h 42. Consultez la
|
plus tard le jeudi 12 novembre 2020 à 12 h 42. Consultez la
|
||||||
dernière section de chaque partie pour plus d'information sur les
|
dernière section de chaque partie pour plus d'informations sur les
|
||||||
éléments à rendre.
|
éléments à rendre.
|
||||||
|
|
||||||
En tant que personnes sensibilisées à la sécurité des échanges électroniques,
|
En tant que personnes sensibilisées à la sécurité des échanges électroniques,
|
||||||
|
@ -12,7 +12,7 @@ abstract: |
|
|||||||
|
|
||||||
Tous les éléments de ce TP (exercices et projet) sont à rendre à
|
Tous les éléments de ce TP (exercices et projet) sont à rendre à
|
||||||
<virli@nemunai.re> au plus tard le **mercredi 4 novembre 2020 à 12 h
|
<virli@nemunai.re> au plus tard le **mercredi 4 novembre 2020 à 12 h
|
||||||
42**. Consultez la dernière section de chaque partie pour plus d'information
|
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
|
sur les éléments à rendre. Et n'oubliez pas de répondre aux [questions de
|
||||||
cours](https://virli.nemunai.re/quiz/5).
|
cours](https://virli.nemunai.re/quiz/5).
|
||||||
|
|
||||||
|
1
tutorial/docker-advanced/orchestrer.md
Normal file
1
tutorial/docker-advanced/orchestrer.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
\newpage
|
4
tutorial/docker-basis/discover.md
Normal file
4
tutorial/docker-basis/discover.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
\newpage
|
||||||
|
|
||||||
|
Découvrons Docker
|
||||||
|
=================
|
@ -50,10 +50,10 @@ proposait pas d'image et que quelqu'un s'est dévoué pour la faire, soit parce
|
|||||||
qu'il avait des besoins plus spécifiques qui n'étaient pas couvert par l'image
|
qu'il avait des besoins plus spécifiques qui n'étaient pas couvert par l'image
|
||||||
originale. Il est important de garder en tête que vous téléchargez des
|
originale. Il est important de garder en tête que vous téléchargez des
|
||||||
exécutables, et bien qu'ils s'exécutent dans un environnement isolé, ils
|
exécutables, et bien qu'ils s'exécutent dans un environnement isolé, ils
|
||||||
peuvent contenir du code malveillant. De la même manière que vous devez être
|
peuvent contenir du code malveillant. **De la même manière que vous devez être
|
||||||
attentif aux binaires que vous exécutez sur votre machine et au contexte de son
|
attentif aux binaires que vous exécutez sur votre machine et au contexte de
|
||||||
téléchargement, ici assurez-vous d'avoir confiance dans la personne affiliée à
|
leurs téléchargements, ici assurez-vous d'avoir confiance dans la personne
|
||||||
l'image.
|
affiliée à l'image.**
|
||||||
|
|
||||||
|
|
||||||
### Arguments de la ligne de commande
|
### Arguments de la ligne de commande
|
||||||
@ -167,8 +167,6 @@ que lorsque nous exécutons une commande modifiant les fichiers d'un conteneur,
|
|||||||
cela ne modifie pas l'image de base. La modification reste contenue dans la
|
cela ne modifie pas l'image de base. La modification reste contenue dans la
|
||||||
couche propre au conteneur dans l'UnionFS.
|
couche propre au conteneur dans l'UnionFS.
|
||||||
|
|
||||||
![Images vs. conteneurs](img-vs-cntr.png "Images vs. conteneurs"){ width=85% }
|
|
||||||
|
|
||||||
Dans le schéma ci-après, on considère les images comme étant la partie figée de
|
Dans le schéma ci-après, on considère les images comme étant la partie figée de
|
||||||
Docker à partir desquelles on peut créer des conteneurs.
|
Docker à partir desquelles on peut créer des conteneurs.
|
||||||
|
|
||||||
@ -176,6 +174,8 @@ Si l'on souhaite qu'une modification faite dans un conteneur (par exemple
|
|||||||
l'installation d'un paquet) s'applique à d'autres conteneurs, il va falloir
|
l'installation d'un paquet) s'applique à d'autres conteneurs, il va falloir
|
||||||
créer une nouvelle image à partir de ce conteneur.
|
créer une nouvelle image à partir de ce conteneur.
|
||||||
|
|
||||||
|
![Images vs. conteneurs](img-vs-cntr.png "Images vs. conteneurs"){ width=85% }
|
||||||
|
|
||||||
|
|
||||||
### Programme par défaut
|
### Programme par défaut
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
include ../pandoc-opts.mk
|
include ../pandoc-opts.mk
|
||||||
|
|
||||||
SOURCES = tutorial.md oci.md runc.md linuxkit.md rendu.md
|
SOURCES = tutorial.md oci.md runc.md linuxkit.md linuxkit-admin.md linuxkit-content.md rendu.md
|
||||||
|
|
||||||
|
|
||||||
all: tutorial.pdf
|
all: tutorial.pdf
|
||||||
|
20
tutorial/docker-internals/clair-tiny.md
Normal file
20
tutorial/docker-internals/clair-tiny.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
[`Clair`](https://github.com/coreos/clair/) est un projet de CoreOS, similaire
|
||||||
|
à Trivy : il va rechercher parmi sa base de vulnérabilités lesquels concernent
|
||||||
|
les images qu'on lui donne.
|
||||||
|
|
||||||
|
Contrairement à Trivy, il ne va pas tenter d'analyser les dépendances
|
||||||
|
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
|
||||||
|
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 :
|
||||||
|
|
||||||
|
![Rapport d'analyse statique des vulnérabilités par Clair](paclair.png)
|
@ -1,53 +1,20 @@
|
|||||||
\newpage
|
### Clair
|
||||||
|
|
||||||
Une vision plus Clair de la sécurité
|
Un outil complet indexer et chercher des vulnérabilités est
|
||||||
====================================
|
|
||||||
|
|
||||||
Nous avons vu, au travers de nos TPs jusqu'à présent, que Docker nous apportait
|
|
||||||
un certain degré de sécurité d'emblée au lancement du conteneur. Cela peut sans
|
|
||||||
doute paraître quelque peu rassurant pour la personne chargée d'administrer la
|
|
||||||
machine hébergeant les conteneurs, car cela lui apporte des garanties quant à
|
|
||||||
l'effort de cloisonnement mis en place.
|
|
||||||
|
|
||||||
Mais doit-on pour autant s'arrêter là et considérer que nous avons réglé
|
|
||||||
l'ensemble des problématiques de sécurité liées aux conteneurs ?
|
|
||||||
|
|
||||||
Évidemment, non : une fois nos services lancés dans des conteneurs, il ne sont
|
|
||||||
pas moins exposés aux bugs et autres failles applicatives ; qu'elles soient
|
|
||||||
dans notre code ou celui d'une bibliothèque, accessible par rebond, ...
|
|
||||||
|
|
||||||
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
|
|
||||||
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
|
|
||||||
lorsqu'un des programmes ou bibliothèques que l'on a installé ensuite.
|
|
||||||
|
|
||||||
Convaincu ? Cela sonne encore comme des bonnes pratiques difficile à mettre en
|
|
||||||
œuvre, pouvant mettre en péril tout un système d'information. Pour s'en
|
|
||||||
protéger, nous allons avoir besoin de réaliser à intervalles réguliers une
|
|
||||||
analyse statique de nos conteneurs.
|
|
||||||
|
|
||||||
![Rapport d'analyse statique des vulnérabilités d'un conteneur](paclair.png)
|
|
||||||
|
|
||||||
|
|
||||||
## Clair
|
|
||||||
|
|
||||||
Le principal outil pour indexer et chercher des vulnérabilités est
|
|
||||||
[`Clair`](https://github.com/coreos/clair/), du projet CoreOS. À partir des
|
[`Clair`](https://github.com/coreos/clair/), du projet CoreOS. À partir des
|
||||||
informations mises à disposition par les équipes de sécurités des principales
|
informations mises à disposition par les équipes de sécurités des principales
|
||||||
distributions, cela alimente en continu une base de données qui sera accéder au
|
distributions, cela alimente en continu une base de données qui sera accéder au
|
||||||
moment de l'analyse.
|
moment de l'analyse.
|
||||||
|
|
||||||
L'outil se présente sous la forme d'un serveur autonome dans la récupération
|
L'outil se présente sous la forme d'un serveur autonome dans la récupération
|
||||||
de ses données sources, auquel nous pourrons interagir au moyen d'une API :
|
de ses données sources, auquel nous pourrons interagir au moyen d'une API :
|
||||||
pour lui envoyer des images et lui demander une analyse. Les clients de cette
|
pour lui envoyer des images et lui demander une analyse. Les clients de cette
|
||||||
API seront soit les registres directement, soit un programme dédié.
|
API seront soit les registres directement, soit un programme dédié.
|
||||||
|
|
||||||
![Scan de vulnérabilités sur le Docker Hub](hubvuln.png)
|
---
|
||||||
|
|
||||||
|
|
||||||
Commençons par lancer notre propre instance de `Clair`, à l'aide d'un
|
Commençons par lancer notre propre instance de `Clair`, à l'aide d'un
|
||||||
`docker-compose.yml` :
|
`docker-compose.yml` :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```yml
|
```yml
|
||||||
@ -77,10 +44,10 @@ services:
|
|||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Prenez quelques minutes pour comprendre ce `docker-compose.yml` : notez la
|
Prenez quelques minutes pour comprendre ce `docker-compose.yml` : notez la
|
||||||
présence de la variable d'environnement `POSTGRES_PASSWORD`, non définie : ce
|
présence de la variable d'environnement `POSTGRES_PASSWORD`, non définie : ce
|
||||||
sera la variable présente dans votre environnement, au moment du
|
sera la variable présente dans votre environnement, au moment du
|
||||||
`docker-compose up` qui sera utilisée. N'oubliez pas de la définir :
|
`docker-compose up` qui sera utilisée. N'oubliez pas de la définir :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -99,7 +66,7 @@ pas de changer le nom d'hôte et le mot de passe pour se connecter au conteneur
|
|||||||
de base de données.**
|
de base de données.**
|
||||||
|
|
||||||
Une fois lancé, la base nécessite d'être initialisée. L'opération peut prendre
|
Une fois lancé, la base nécessite d'être initialisée. L'opération peut prendre
|
||||||
plusieurs minutes. Vous pouvez suivre l'avancement de l'ajout via :
|
plusieurs minutes. Vous pouvez suivre l'avancement de l'ajout via :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -109,11 +76,11 @@ curl http://localhost:6060/v1/namespaces/debian:9/vulnerabilities?limit=10
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
## PAClair
|
### PAClair
|
||||||
|
|
||||||
Afin de pouvoir réaliser à la demande et sans registre privé, l'analyse de
|
Afin de pouvoir réaliser à la demande et sans registre privé, l'analyse de
|
||||||
conteneur, nous allons utiliser le programme
|
conteneur, nous allons utiliser le programme
|
||||||
[`paclair`](https://github.com/yebinama/paclair) :
|
[`paclair`](https://github.com/yebinama/paclair) :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -121,7 +88,7 @@ pip3 install paclair
|
|||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Il nécessite un fichier de configuration pour être utilisé, essayez :
|
Il nécessite un fichier de configuration pour être utilisé, essayez :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```yml
|
```yml
|
||||||
@ -134,7 +101,7 @@ Plugins:
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
Pour obtenir un rapport d'analyse, on commence par envoyer les couches de
|
Pour obtenir un rapport d'analyse, on commence par envoyer les couches de
|
||||||
l'image à `Clair` :
|
l'image à `Clair` :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -142,7 +109,7 @@ paclair --conf conf.yml Docker nemunaire/fic-admin push
|
|||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Puis on lui demande la génération d'un rapport `html` :
|
Puis on lui demande la génération d'un rapport `html` :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -150,7 +117,7 @@ paclair --conf conf.yml Docker nemunaire/fic-admin analyse --output-format html
|
|||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Si l'on souhaite uniquement avoir des statistiques dans la console :
|
Si l'on souhaite uniquement avoir des statistiques dans la console :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -161,10 +128,3 @@ Medium: 5
|
|||||||
High: 4
|
High: 4
|
||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
## 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`, ...
|
|
||||||
|
11
tutorial/docker-internals/linuxkit-adlin.md
Normal file
11
tutorial/docker-internals/linuxkit-adlin.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Si vous vous rappelez du cours d'AdLin[^adlin] en début d'années, toutes les
|
||||||
|
VMs que vous avez utilisées reposaient entièrement sur `linuxkit`. En fait,
|
||||||
|
chaque conteneur représentait alors une machine différente : un conteneur
|
||||||
|
postgres d'un côté, un conteneur `miniflux` directement issu du DockerHub, un
|
||||||
|
conteneur `unbound` pour faire office de serveur DNS, et les machines clientes
|
||||||
|
étaient de simples conteneurs exécutant un client DHCP.
|
||||||
|
|
||||||
|
[^adlin]: toutes les sources des machines sont dans ce dépôt :
|
||||||
|
<https://git.nemunai.re/srs/adlin>. Les fichiers de construction
|
||||||
|
LinuxKit sont `challenge.yml`, `server.yml`, `tuto2.yml`,
|
||||||
|
`tuto3.yml`
|
243
tutorial/docker-internals/linuxkit-content.md
Normal file
243
tutorial/docker-internals/linuxkit-content.md
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
## Prérequis
|
||||||
|
|
||||||
|
Si vous n'avez pas déjà le binaire `linuxkit`, vous pouvez télécharger ici :\
|
||||||
|
<https://github.com/linuxkit/linuxkit/releases/latest>.
|
||||||
|
|
||||||
|
Notez qu'étant donné qu'il est écrit en Go, aucune dépendance n'est nécessaire
|
||||||
|
en plus du binaire[^lollibc] ;-)
|
||||||
|
|
||||||
|
[^lollibc]: à condition tout de même que vous utilisiez une libc habituelle.
|
||||||
|
|
||||||
|
Vous aurez également besoin de QEMU pour tester vos créations.
|
||||||
|
|
||||||
|
|
||||||
|
## Structure d'un fichier `linuxkit.yml`
|
||||||
|
|
||||||
|
Le fichier utilisé pour construire notre image se décompose en plusieurs
|
||||||
|
parties :
|
||||||
|
|
||||||
|
- `kernel` : il est attendu ici une image OCI contenant le nécessaire pour
|
||||||
|
pouvoir utiliser un noyau : l'image du noyau, ses modules et un initramfs ;
|
||||||
|
- `init` : l'ensemble des images OCI de cette liste seront fusionnés pour
|
||||||
|
donner naissance au *rootfs* de la machine. On n'y place normalement qu'un
|
||||||
|
gestionnaire de conteneur, qui sera chargé de lancer chaque conteneur au bon
|
||||||
|
moment ;
|
||||||
|
- `onboot`, `onshutdown` et `services` : il s'agit de conteneurs qui seront
|
||||||
|
lancés par le système disponible dans l'`init`, au bon moment. Les conteneurs
|
||||||
|
indiqués dans `onboot` seront lancés **séquentiellement** au démarrage de la
|
||||||
|
machine, ceux dans `onshutdown` seront lancés lors de l'arrêt de la
|
||||||
|
machine. Les conteneurs dans `services` seront lancés simultanément une fois
|
||||||
|
que le dernier conteneur de `onboot` aura rendu la main ;
|
||||||
|
- `files` : des fichiers supplémentaires à placer dans le rootfs.
|
||||||
|
|
||||||
|
Le format est documenté
|
||||||
|
[ici](https://github.com/linuxkit/linuxkit/blob/master/docs/yaml.md).
|
||||||
|
|
||||||
|
|
||||||
|
## Hello?
|
||||||
|
|
||||||
|
L'image la plus simple que l'on puisse réaliser pourrait être :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```yaml
|
||||||
|
kernel:
|
||||||
|
image: linuxkit/kernel:4.14.80
|
||||||
|
cmdline: "console=tty0 console=ttyS0"
|
||||||
|
init:
|
||||||
|
- linuxkit/init:c563953a2277eb73a89d89f70e4b6dcdcfebc2d1
|
||||||
|
- linuxkit/runc:83d0edb4552b1a5df1f0976f05f442829eac38fe
|
||||||
|
- linuxkit/containerd:326b096cd5fbab0f864e52721d036cade67599d6
|
||||||
|
onboot:
|
||||||
|
- name: dhcpcd
|
||||||
|
image: linuxkit/dhcpcd:v0.6
|
||||||
|
command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
|
||||||
|
services:
|
||||||
|
- name: getty
|
||||||
|
image: linuxkit/getty:2eb742cd7a68e14cf50577c02f30147bc406e478
|
||||||
|
env:
|
||||||
|
- INSECURE=true
|
||||||
|
trust:
|
||||||
|
org:
|
||||||
|
- linuxkit
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
L'image `getty` est très pratique pour déboguer, car elle permet d'avoir un
|
||||||
|
shell sur la machine !
|
||||||
|
|
||||||
|
On notera cependant que, positionné dans `services`, le shell que nous
|
||||||
|
obtiendrons sera lui-même exécuté dans un conteneur, nous n'aurons donc pas un
|
||||||
|
accès entièrement privilégier. Pour déboguer, il faut placer cette image dans
|
||||||
|
la partie `init`, elle sera alors lancé comme un équivalent de
|
||||||
|
`init=/bin/sh`.[^infogetty]
|
||||||
|
|
||||||
|
[^infogetty]: Plus d'infos à
|
||||||
|
<https://github.com/linuxkit/linuxkit/blob/master/pkg/getty/README.md#linuxkit-debug>
|
||||||
|
|
||||||
|
|
||||||
|
## `namespaces`
|
||||||
|
|
||||||
|
Chaque nouveau conteneur est donc lancé dans un espace distinct où il ne pourra
|
||||||
|
pas interagir avec les autres, ou déborder s'il s'avérait qu'il expose une
|
||||||
|
faille exploitable.
|
||||||
|
|
||||||
|
Néanmoins, contrairement à Docker qui va de base nous dissocier du maximum de
|
||||||
|
*namespaces*, `linuxkit` ne le fait pas pour les *namespaces* `net`, `ipc` et
|
||||||
|
`uts`. C'est-à-dire que, par défaut, la pile réseau est partagée entre tous les
|
||||||
|
conteneurs, tout comme les IPC et le nom de la machine.
|
||||||
|
|
||||||
|
Il reste possible de se dissocier également de ces namespaces, en précisant :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```yaml
|
||||||
|
- name: getty
|
||||||
|
image: linuxkit/getty:2eb742cd7a68e14cf50577c02f30147bc406e478
|
||||||
|
net: new
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Ou inversement, pour persister dans le namespace initial :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```yaml
|
||||||
|
- name: getty
|
||||||
|
image: linuxkit/getty:2eb742cd7a68e14cf50577c02f30147bc406e478
|
||||||
|
pid: host
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
### Partage de `namespace`
|
||||||
|
|
||||||
|
Dans le cas où l'on souhaite que deux conteneurs partagent le même *namespace*,
|
||||||
|
il faut passer le chemin vers la structure du noyau correspondante.
|
||||||
|
|
||||||
|
On commence donc d'abord par créer le nouveau *namespace*, en prenant soin de
|
||||||
|
*bind mount* la structure du noyau à un emplacement connu :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```yaml
|
||||||
|
- name: getty
|
||||||
|
image: linuxkit/getty:2eb742cd7a68e14cf50577c02f30147bc406e478
|
||||||
|
net: new
|
||||||
|
runtime:
|
||||||
|
bindNS: /run/netns/mynewnetns
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
À la création du *namespace* `net`, le lien vers la structure du noyau
|
||||||
|
correspondante sera *bind mount* sur `/run/netns/synchro`. On pourra alors
|
||||||
|
réutiliser plus tard ce chemin, en remplacement du mot clef `new` :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```yaml
|
||||||
|
- name: xxxx
|
||||||
|
image: linuxkit/xxxx:v0.6
|
||||||
|
net: /run/netns/mynewnetns
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
## Construction et démarrage
|
||||||
|
|
||||||
|
Toute la puissance de `linuxkit` repose dans son système de construction et
|
||||||
|
surtout de lancement. En effet, il peut construire des images pour un grand
|
||||||
|
nombre de plate-forme, mais il est également possible d'utiliser les API de ces
|
||||||
|
plates-formes pour aller y lancer des instances de cette image !
|
||||||
|
|
||||||
|
Pour construire l'image faite précédemment :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```bash
|
||||||
|
linuxkit build hello.yml
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Cela va générer plusieurs fichiers dont un noyau (extrait de l'image de la
|
||||||
|
partie `kernel`) ainsi qu'une image. Exactement ce qu'attend QEMU ! Pour
|
||||||
|
tester, n'attendons pas davantage pour lancer :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```bash
|
||||||
|
linuxkit run qemu -gui hello
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
## Ajouter un service
|
||||||
|
|
||||||
|
Maintenant que notre machine fonctionne, que nous pouvons interagir avec elle,
|
||||||
|
tentons de se passer de l'interface de QEMU (option `-gui`) en ajoutant un
|
||||||
|
serveur SSH aux `services` :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```yaml
|
||||||
|
- name: sshd
|
||||||
|
image: linuxkit/sshd:c4bc89cf0d66733c923ab9cb46198b599eb99320
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Comme nous n'avons définis aucun mot de passe, il va falloir utiliser une clef
|
||||||
|
SSH pour se connecter. Voilà un bon début d'utilisation de la section `files` :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```yaml
|
||||||
|
- path: root/.ssh/authorized_keys
|
||||||
|
source: ~/.ssh/id_rsa.pub
|
||||||
|
mode: "0600"
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Ceci va aller chercher votre clef RSA sur votre machine, pour la placer dans
|
||||||
|
|
||||||
|
Notons qu'il est inutile d'ajouter un *bind mount* du dossier `.ssh` ainsi
|
||||||
|
recopié, car le *package* `linuxkit/sshd` défini déjà cela :
|
||||||
|
[pkg/sshd/build.yml#L5](https://github.com/linuxkit/linuxkit/blob/master/pkg/sshd/build.yml#L5).
|
||||||
|
|
||||||
|
|
||||||
|
## Interface réseau virtuelle
|
||||||
|
|
||||||
|
Lorsque l'on souhaite se dissocier d'un *namespace* `net` afin de s'isoler,
|
||||||
|
mais que l'on veut tout de même pouvoir communiquer, il est nécessaire de créer
|
||||||
|
une interface `virtual ethernet` :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```yaml
|
||||||
|
- name: db
|
||||||
|
image: mariadb:latest
|
||||||
|
net: new
|
||||||
|
runtime:
|
||||||
|
bindNS:
|
||||||
|
net: /run/netns/db
|
||||||
|
interfaces:
|
||||||
|
- name: vethin-db
|
||||||
|
add: veth
|
||||||
|
peer: veth-db
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
## Exercice {-}
|
||||||
|
|
||||||
|
Réalisez une recette `vault.yml` démarrant une instance du gestionnaire de
|
||||||
|
secrets [Hashicorp Vault](https://www.vaultproject.io/), utilisant une [base de
|
||||||
|
données au
|
||||||
|
choix](https://www.vaultproject.io/docs/configuration/storage/index.html)
|
||||||
|
(Consul, Etcd, MySQL, Cassandra, ...).
|
||||||
|
|
||||||
|
Au démarrage, Vault devra déjà être configuré pour parler à sa base de données,
|
||||||
|
qui devra se trouver dans un conteneur isolé et non accessible d'internet. Il
|
||||||
|
faudra donc établir un lien `virtual ethernet` entre les deux conteneurs ; et
|
||||||
|
ne pas oublier de le configurer (automatiquement au *runtime*, grâce à un
|
||||||
|
[`poststart`
|
||||||
|
*hook*](https://github.com/opencontainers/runtime-spec/blob/master/config.md#posix-platform-hooks)
|
||||||
|
ou bien à un conteneur issu du *package*
|
||||||
|
[`ip`](https://github.com/linuxkit/linuxkit/tree/master/pkg/ip)).
|
||||||
|
|
||||||
|
Les permissions étant généralement très strictes, vous aurez sans doute besoin
|
||||||
|
de les assouplir un peu en ajoutant des *capabilities* autorisées à vos
|
||||||
|
conteneurs, sans quoi vos conteneurs risquent d'être tués prématurément.
|
||||||
|
|
||||||
|
En bonus, vous pouvez gérer la [persistance des
|
||||||
|
données](https://github.com/linuxkit/linuxkit/blob/master/examples/swap.yml)
|
||||||
|
stockées dans Vault.
|
@ -13,258 +13,3 @@ des images pour les différents fournisseurs de cloud !
|
|||||||
Bien entendu, au sein de ce système, tout est fait de conteneur ! Alors quand
|
Bien entendu, au sein de ce système, tout est fait de conteneur ! Alors quand
|
||||||
il s'agit de donner une IP publique utilisable par l'ensemble des conteneurs,
|
il s'agit de donner une IP publique utilisable par l'ensemble des conteneurs,
|
||||||
il faut savoir jouer avec les *namespaces* pour arriver à ses fins !
|
il faut savoir jouer avec les *namespaces* pour arriver à ses fins !
|
||||||
|
|
||||||
Si vous vous rappelez du cours d'AdLin[^adlin] en début d'années, toutes les
|
|
||||||
VMs que vous avez utilisées reposaient entièrement sur `linuxkit`. En fait,
|
|
||||||
chaque conteneur représentait alors une machine différente : un conteneur
|
|
||||||
mattermost d'un côté, un conteneur `unbound` pour faire office de serveur DNS,
|
|
||||||
et les machines clientes étaient de simples conteneurs exécutant un client
|
|
||||||
dhcp.
|
|
||||||
|
|
||||||
[^adlin]: toutes les sources des machines sont dans ce dépôt :
|
|
||||||
<https://git.nemunai.re/?p=lectures/adlin.git;a=tree>
|
|
||||||
|
|
||||||
|
|
||||||
## Prérequis
|
|
||||||
|
|
||||||
Si vous n'avez pas déjà le binaire `linuxkit`, vous pouvez télécharger ici :
|
|
||||||
<https://github.com/linuxkit/linuxkit/releases/latest>.
|
|
||||||
|
|
||||||
Notez qu'étant donné qu'il est écrit en Go, aucune dépendance n'est nécessaire
|
|
||||||
en plus du binaire[^lollibc] ;-)
|
|
||||||
|
|
||||||
[^lollibc]: à condition tout de même que vous utilisiez une libc habituelle.
|
|
||||||
|
|
||||||
Vous aurez également besoin de QEMU pour tester vos créations.
|
|
||||||
|
|
||||||
|
|
||||||
## Structure d'un fichier `linuxkit.yml`
|
|
||||||
|
|
||||||
Le fichier utilisé pour construire notre image se décompose en plusieurs
|
|
||||||
parties :
|
|
||||||
|
|
||||||
- `kernel` : il est attendu ici une image OCI contenant le nécessaire pour
|
|
||||||
pouvoir utiliser un noyau : l'image du noyau, ses modules et un initramfs ;
|
|
||||||
- `init` : l'ensemble des images OCI de cette liste seront fusionnés pour
|
|
||||||
donner naissance au *rootfs* de la machine. On n'y place normalement qu'un
|
|
||||||
gestionnaire de conteneur, qui sera chargé de lancer chaque conteneur au bon
|
|
||||||
moment ;
|
|
||||||
- `onboot`, `onshutdown` et `services` : il s'agit de conteneurs qui seront
|
|
||||||
lancés par le système disponible dans l'`init`, au bon moment. Les conteneurs
|
|
||||||
indiqués dans `onboot` seront lancés **séquentiellement** au démarrage de la
|
|
||||||
machine, ceux dans `onshutdown` seront lancés lors de l'arrêt de la
|
|
||||||
machine. Les conteneurs dans `services` seront lancés simultanément une fois
|
|
||||||
que le dernier conteneur de `onboot` aura rendu la main ;
|
|
||||||
- `files` : des fichiers supplémentaires à placer dans le rootfs.
|
|
||||||
|
|
||||||
Le format est documenté
|
|
||||||
[ici](https://github.com/linuxkit/linuxkit/blob/master/docs/yaml.md).
|
|
||||||
|
|
||||||
|
|
||||||
## Hello?
|
|
||||||
|
|
||||||
L'image la plus simple que l'on puisse réaliser pourrait être :
|
|
||||||
|
|
||||||
<div lang="en-US">
|
|
||||||
```yaml
|
|
||||||
kernel:
|
|
||||||
image: linuxkit/kernel:4.14.80
|
|
||||||
cmdline: "console=tty0 console=ttyS0"
|
|
||||||
init:
|
|
||||||
- linuxkit/init:c563953a2277eb73a89d89f70e4b6dcdcfebc2d1
|
|
||||||
- linuxkit/runc:83d0edb4552b1a5df1f0976f05f442829eac38fe
|
|
||||||
- linuxkit/containerd:326b096cd5fbab0f864e52721d036cade67599d6
|
|
||||||
onboot:
|
|
||||||
- name: dhcpcd
|
|
||||||
image: linuxkit/dhcpcd:v0.6
|
|
||||||
command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
|
|
||||||
services:
|
|
||||||
- name: getty
|
|
||||||
image: linuxkit/getty:2eb742cd7a68e14cf50577c02f30147bc406e478
|
|
||||||
env:
|
|
||||||
- INSECURE=true
|
|
||||||
trust:
|
|
||||||
org:
|
|
||||||
- linuxkit
|
|
||||||
```
|
|
||||||
</div>
|
|
||||||
|
|
||||||
L'image `getty` est très pratique pour déboguer, car elle permet d'avoir un
|
|
||||||
shell sur la machine !
|
|
||||||
|
|
||||||
On notera cependant que, positionné dans `services`, le shell que nous
|
|
||||||
obtiendrons sera lui-même exécuté dans un conteneur, nous n'aurons donc pas un
|
|
||||||
accès entièrement privilégier. Pour déboguer, il faut placer cette image dans
|
|
||||||
la partie `init`, elle sera alors lancé comme un équivalent de
|
|
||||||
`init=/bin/sh`.[^infogetty]
|
|
||||||
|
|
||||||
[^infogetty]: Plus d'infos à
|
|
||||||
<https://github.com/linuxkit/linuxkit/blob/master/pkg/getty/README.md#linuxkit-debug>
|
|
||||||
|
|
||||||
|
|
||||||
## `namespaces`
|
|
||||||
|
|
||||||
Chaque nouveau conteneur est donc lancé dans un espace distinct où il ne pourra
|
|
||||||
pas interagir avec les autres, ou déborder s'il s'avérait qu'il expose une
|
|
||||||
faille exploitable.
|
|
||||||
|
|
||||||
Néanmoins, contrairement à Docker qui va de base nous dissocier du maximum de
|
|
||||||
*namespaces*, `linuxkit` ne le fait pas pour les *namespaces* `net`, `ipc` et
|
|
||||||
`uts`. C'est-à-dire que, par défaut, la pile réseau est partagée entre tous les
|
|
||||||
conteneurs, tout comme les IPC et le nom de la machine.
|
|
||||||
|
|
||||||
Il reste possible de se dissocier également de ces namespaces, en précisant :
|
|
||||||
|
|
||||||
<div lang="en-US">
|
|
||||||
```yaml
|
|
||||||
- name: getty
|
|
||||||
image: linuxkit/getty:2eb742cd7a68e14cf50577c02f30147bc406e478
|
|
||||||
net: new
|
|
||||||
```
|
|
||||||
</div>
|
|
||||||
|
|
||||||
Ou inversement, pour persister dans le namespace initial :
|
|
||||||
|
|
||||||
<div lang="en-US">
|
|
||||||
```yaml
|
|
||||||
- name: getty
|
|
||||||
image: linuxkit/getty:2eb742cd7a68e14cf50577c02f30147bc406e478
|
|
||||||
pid: host
|
|
||||||
```
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
### Partage de `namespace`
|
|
||||||
|
|
||||||
Dans le cas où l'on souhaite que deux conteneurs partagent le même *namespace*,
|
|
||||||
il faut passer le chemin vers la structure du noyau correspondante.
|
|
||||||
|
|
||||||
On commence donc d'abord par créer le nouveau *namespace*, en prenant soin de
|
|
||||||
*bind mount* la structure du noyau à un emplacement connu :
|
|
||||||
|
|
||||||
<div lang="en-US">
|
|
||||||
```yaml
|
|
||||||
- name: getty
|
|
||||||
image: linuxkit/getty:2eb742cd7a68e14cf50577c02f30147bc406e478
|
|
||||||
net: new
|
|
||||||
runtime:
|
|
||||||
bindNS: /run/netns/mynewnetns
|
|
||||||
```
|
|
||||||
</div>
|
|
||||||
|
|
||||||
À la création du *namespace* `net`, le lien vers la structure du noyau
|
|
||||||
correspondante sera *bind mount* sur `/run/netns/synchro`. On pourra alors
|
|
||||||
réutiliser plus tard ce chemin, en remplacement du mot clef `new` :
|
|
||||||
|
|
||||||
<div lang="en-US">
|
|
||||||
```yaml
|
|
||||||
- name: xxxx
|
|
||||||
image: linuxkit/xxxx:v0.6
|
|
||||||
net: /run/netns/mynewnetns
|
|
||||||
```
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
## Construction et démarrage
|
|
||||||
|
|
||||||
Toute la puissance de `linuxkit` repose dans son système de construction et
|
|
||||||
surtout de lancement. En effet, il peut construire des images pour un grand
|
|
||||||
nombre de plate-forme, mais il est également possible d'utiliser les API de ces
|
|
||||||
plates-formes pour aller y lancer des instances de cette image !
|
|
||||||
|
|
||||||
Pour construire l'image faite précédemment :
|
|
||||||
|
|
||||||
<div lang="en-US">
|
|
||||||
```bash
|
|
||||||
linuxkit build hello.yml
|
|
||||||
```
|
|
||||||
</div>
|
|
||||||
|
|
||||||
Cela va générer plusieurs fichiers dont un noyau (extrait de l'image de la
|
|
||||||
partie `kernel`) ainsi qu'une image. Exactement ce qu'attend QEMU ! Pour
|
|
||||||
tester, n'attendons pas davantage pour lancer :
|
|
||||||
|
|
||||||
<div lang="en-US">
|
|
||||||
```bash
|
|
||||||
linuxkit run qemu -gui hello
|
|
||||||
```
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
## Ajouter un service
|
|
||||||
|
|
||||||
Maintenant que notre machine fonctionne, que nous pouvons interagir avec elle,
|
|
||||||
tentons de se passer de l'interface de QEMU (option `-gui`) en ajoutant un
|
|
||||||
serveur SSH aux `services` :
|
|
||||||
|
|
||||||
<div lang="en-US">
|
|
||||||
```yaml
|
|
||||||
- name: sshd
|
|
||||||
image: linuxkit/sshd:c4bc89cf0d66733c923ab9cb46198b599eb99320
|
|
||||||
```
|
|
||||||
</div>
|
|
||||||
|
|
||||||
Comme nous n'avons définis aucun mot de passe, il va falloir utiliser une clef
|
|
||||||
SSH pour se connecter. Voilà un bon début d'utilisation de la section `files` :
|
|
||||||
|
|
||||||
<div lang="en-US">
|
|
||||||
```yaml
|
|
||||||
- path: root/.ssh/authorized_keys
|
|
||||||
source: ~/.ssh/id_rsa.pub
|
|
||||||
mode: "0600"
|
|
||||||
```
|
|
||||||
</div>
|
|
||||||
|
|
||||||
Ceci va aller chercher votre clef RSA sur votre machine, pour la placer dans
|
|
||||||
|
|
||||||
Notons qu'il est inutile d'ajouter un *bind mount* du dossier `.ssh` ainsi
|
|
||||||
recopié, car le *package* `linuxkit/sshd` défini déjà cela :
|
|
||||||
[pkg/sshd/build.yml#L5](https://github.com/linuxkit/linuxkit/blob/master/pkg/sshd/build.yml#L5).
|
|
||||||
|
|
||||||
|
|
||||||
## Interface réseau virtuelle
|
|
||||||
|
|
||||||
Lorsque l'on souhaite se dissocier d'un *namespace* `net` afin de s'isoler,
|
|
||||||
mais que l'on veut tout de même pouvoir communiquer, il est nécessaire de créer
|
|
||||||
une interface `virtual ethernet` :
|
|
||||||
|
|
||||||
<div lang="en-US">
|
|
||||||
```yaml
|
|
||||||
- name: db
|
|
||||||
image: mariadb:latest
|
|
||||||
net: new
|
|
||||||
runtime:
|
|
||||||
bindNS:
|
|
||||||
net: /run/netns/db
|
|
||||||
interfaces:
|
|
||||||
- name: vethin-db
|
|
||||||
add: veth
|
|
||||||
peer: veth-db
|
|
||||||
```
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
## Exercice {-}
|
|
||||||
|
|
||||||
Réalisez une recette `vault.yml` démarrant une instance du gestionnaire de
|
|
||||||
secrets [Hashicorp Vault](https://www.vaultproject.io/), utilisant une [base de
|
|
||||||
données au
|
|
||||||
choix](https://www.vaultproject.io/docs/configuration/storage/index.html)
|
|
||||||
(Consul, Etcd, MySQL, Cassandra, ...).
|
|
||||||
|
|
||||||
Au démarrage, Vault devra déjà être configuré pour parler à sa base de données,
|
|
||||||
qui devra se trouver dans un conteneur isolé et non accessible d'internet. Il
|
|
||||||
faudra donc établir un lien `virtual ethernet` entre les deux conteneurs ; et
|
|
||||||
ne pas oublier de le configurer (automatiquement au *runtime*, grâce à un
|
|
||||||
[`poststart`
|
|
||||||
*hook*](https://github.com/opencontainers/runtime-spec/blob/master/config.md#posix-platform-hooks)
|
|
||||||
ou bien à un conteneur issu du *package*
|
|
||||||
[`ip`](https://github.com/linuxkit/linuxkit/tree/master/pkg/ip)).
|
|
||||||
|
|
||||||
Les permissions étant généralement très strictes, vous aurez sans doute besoin
|
|
||||||
de les assouplir un peu en ajoutant des *capabilities* autorisées à vos
|
|
||||||
conteneurs, sans quoi vos conteneurs risquent d'être tués prématurément.
|
|
||||||
|
|
||||||
En bonus, vous pouvez gérer la [persistance des
|
|
||||||
données](https://github.com/linuxkit/linuxkit/blob/master/examples/swap.yml)
|
|
||||||
stockées dans Vault.
|
|
||||||
|
@ -7,7 +7,7 @@ Formée en juin 2015, l'Open Container Initiative (OCI) a pour but d'établir le
|
|||||||
standard commun aux programmes de contenerisation, afin d'éviter une
|
standard commun aux programmes de contenerisation, afin d'éviter une
|
||||||
fragmentation de l'écosystème.
|
fragmentation de l'écosystème.
|
||||||
|
|
||||||
Trois spécifications ont été écrites :
|
Trois spécifications ont été écrites :
|
||||||
|
|
||||||
- [`runtime-spec`](https://github.com/opencontainers/runtime-spec/blob/master/spec.md#platforms): définit les paramètres du démarrage d'un conteneur ;
|
- [`runtime-spec`](https://github.com/opencontainers/runtime-spec/blob/master/spec.md#platforms): définit les paramètres du démarrage d'un conteneur ;
|
||||||
- [`image-spec`](https://github.com/opencontainers/image-spec/blob/master/spec.md): définit la construction, le transport et la préparation des images ;
|
- [`image-spec`](https://github.com/opencontainers/image-spec/blob/master/spec.md): définit la construction, le transport et la préparation des images ;
|
||||||
@ -24,8 +24,8 @@ d'avoir un fichier de configuration `config.json` ainsi qu'un dossier où l'on
|
|||||||
peut trouver la racine de notre conteneur.
|
peut trouver la racine de notre conteneur.
|
||||||
|
|
||||||
Le plus gros de la spécification concerne le format de ce fichier de
|
Le plus gros de la spécification concerne le format de ce fichier de
|
||||||
configuration : il contient en effet l'ensemble des paramètres avec lesquels il
|
configuration : il contient en effet l'ensemble des paramètres avec lesquels il
|
||||||
faudra créer le conteneur : tant d'un point de vue isolement (on peut par
|
faudra créer le conteneur : tant d'un point de vue isolement (on peut par
|
||||||
exemple choisir de quel *namespace* on souhaite se dissocier, ou le(s)quel(s)
|
exemple choisir de quel *namespace* on souhaite se dissocier, ou le(s)quel(s)
|
||||||
rejoindre), quelles *capabilities* resteront disponibles, quels nouveaux points
|
rejoindre), quelles *capabilities* resteront disponibles, quels nouveaux points
|
||||||
de montages, ... Voir [la
|
de montages, ... Voir [la
|
||||||
@ -45,8 +45,8 @@ fichiers, d'une configuration ainsi qu'un index d'image optionnel.
|
|||||||
|
|
||||||
Le
|
Le
|
||||||
[manifest](https://github.com/opencontainers/image-spec/blob/master/manifest.md)
|
[manifest](https://github.com/opencontainers/image-spec/blob/master/manifest.md)
|
||||||
est toujours le point d'entrée d'une image : il référence l'emplacement où
|
est toujours le point d'entrée d'une image : il référence l'emplacement où
|
||||||
trouver les différents éléments : configuration et couches. Lorsqu'une même
|
trouver les différents éléments : configuration et couches. Lorsqu'une même
|
||||||
image a des variation en fonction de l'architecture du processeur, du système
|
image a des variation en fonction de l'architecture du processeur, du système
|
||||||
d'exploitation, ... dans ce cas [l'index
|
d'exploitation, ... dans ce cas [l'index
|
||||||
d'image](https://github.com/opencontainers/image-spec/blob/master/image-index.md)
|
d'image](https://github.com/opencontainers/image-spec/blob/master/image-index.md)
|
||||||
@ -54,7 +54,7 @@ est utilisé pour sélectionner le bon manifest.
|
|||||||
|
|
||||||
Le format des [couches de système de
|
Le format des [couches de système de
|
||||||
fichiers](https://github.com/opencontainers/image-spec/blob/master/layer.md)
|
fichiers](https://github.com/opencontainers/image-spec/blob/master/layer.md)
|
||||||
sont spécifiées : il est nécessaire de passer par des formats standards (comme
|
sont spécifiées : il est nécessaire de passer par des formats standards (comme
|
||||||
les tarballs), contenant éventuellement des fichiers et dossiers spéciaux
|
les tarballs), contenant éventuellement des fichiers et dossiers spéciaux
|
||||||
contenant les modifications, suppressions, ... éventuelles de la couche
|
contenant les modifications, suppressions, ... éventuelles de la couche
|
||||||
représentée.
|
représentée.
|
||||||
@ -64,14 +64,14 @@ La
|
|||||||
contient l'ensemble des métadonnées qui serviront par exemple à construire le
|
contient l'ensemble des métadonnées qui serviront par exemple à construire le
|
||||||
`config.json` attendu par `runc` lorsqu'il faudra lancer l'image (c'est
|
`config.json` attendu par `runc` lorsqu'il faudra lancer l'image (c'est
|
||||||
là-dedans que finissent toutes les métadonnées que l'on inscrit dans nos
|
là-dedans que finissent toutes les métadonnées que l'on inscrit dans nos
|
||||||
`Dockerfile` : `CMD`, `VOLUME`, `PORT`, ...). On y retrouve également l'ordre
|
`Dockerfile` : `CMD`, `VOLUME`, `PORT`, ...). On y retrouve également l'ordre
|
||||||
des couches du système de fichiers, ainsi que l'historique de l'image.
|
des couches du système de fichiers, ainsi que l'historique de l'image.
|
||||||
|
|
||||||
|
|
||||||
## `distribution-spec`
|
## `distribution-spec`
|
||||||
|
|
||||||
Dernière née de l'organisme, cette spécification fédère la notion de
|
Dernière née de l'organisme, cette spécification fédère la notion de
|
||||||
*registre* : une API REST sur HTTP où l'on peut récupérer des images, mais
|
*registre* : une API REST sur HTTP où l'on peut récupérer des images, mais
|
||||||
aussi en envoyer.
|
aussi en envoyer.
|
||||||
|
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ aussi en envoyer.
|
|||||||
|
|
||||||
Si maintenant `docker` fait appel à un programme externe pour lancer
|
Si maintenant `docker` fait appel à un programme externe pour lancer
|
||||||
effectivement nos conteneurs, c'est que l'on peut changer cette implémentation
|
effectivement nos conteneurs, c'est que l'on peut changer cette implémentation
|
||||||
? la réponse dans l'article :
|
? la réponse dans l'article :
|
||||||
<https://ops.tips/blog/run-docker-with-forked-runc/>
|
<https://ops.tips/blog/run-docker-with-forked-runc/>
|
||||||
|
|
||||||
Et `containerd` dans l'histoire ?
|
Et `containerd` dans l'histoire ?
|
||||||
|
BIN
tutorial/docker-internals/quay-vulns.png
Normal file
BIN
tutorial/docker-internals/quay-vulns.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 83 KiB |
@ -3,14 +3,14 @@
|
|||||||
Registres
|
Registres
|
||||||
=========
|
=========
|
||||||
|
|
||||||
**Outils nécessaires :** `curl`, `gunzip`, `jq`, `tar`.
|
**Outils nécessaires :** `curl`, `gunzip`, `jq`, `tar`.
|
||||||
|
|
||||||
* * * * *
|
* * * * *
|
||||||
|
|
||||||
Nous allons appréhender le fonctionnement d'un registre OCI,
|
Nous allons appréhender le fonctionnement d'un registre OCI,
|
||||||
et préparer le *rootfs* d'une image de base (Debian, Ubuntu, hello, ...) : en
|
et préparer le *rootfs* d'une image de base (Debian, Ubuntu, hello, ...) : en
|
||||||
nous préoccupant simplement de la couche la plus basse (qui ne contient pas de
|
nous préoccupant simplement de la couche la plus basse (qui ne contient pas de
|
||||||
modification ou de suppression : chaque fichier est normal).
|
modification ou de suppression : chaque fichier est normal).
|
||||||
|
|
||||||
|
|
||||||
## Authentification
|
## Authentification
|
||||||
@ -18,7 +18,7 @@ modification ou de suppression : chaque fichier est normal).
|
|||||||
L'authentification est facultative et est laissée à l'appréciation du
|
L'authentification est facultative et est laissée à l'appréciation du
|
||||||
fournisseur de service. Étant donné que nous allons utiliser le [Docker
|
fournisseur de service. Étant donné que nous allons utiliser le [Docker
|
||||||
Hub](https://hub.docker.com/), le registre par défaut de `docker`, nous allons
|
Hub](https://hub.docker.com/), le registre par défaut de `docker`, nous allons
|
||||||
devoir nous plier à leur mécanisme d'authentification : chaque requête au
|
devoir nous plier à leur mécanisme d'authentification : chaque requête au
|
||||||
registre doit être effectuée avec un jeton, que l'on obtient en s'authentifiant
|
registre doit être effectuée avec un jeton, que l'on obtient en s'authentifiant
|
||||||
auprès d'un service dédié. Ce service peut délivrer un jeton sans authentifier
|
auprès d'un service dédié. Ce service peut délivrer un jeton sans authentifier
|
||||||
l'interlocuteur, en restant anonyme ; dans ce cas, on ne pourra accéder qu'aux
|
l'interlocuteur, en restant anonyme ; dans ce cas, on ne pourra accéder qu'aux
|
||||||
@ -26,8 +26,8 @@ images publiques. Ça tombe bien, c'est ce qui nous intéresse aujourd'hui !
|
|||||||
|
|
||||||
Il n'en reste pas moins que le jeton est forgé pour un service donné (dans
|
Il n'en reste pas moins que le jeton est forgé pour un service donné (dans
|
||||||
notre cas `registry.docker.io`) et avec un objectif bien cerné (pour nous, on
|
notre cas `registry.docker.io`) et avec un objectif bien cerné (pour nous, on
|
||||||
souhaite récupérer le contenu du dépôt[^quiddepot] `hello-world` :
|
souhaite récupérer le contenu du dépôt[^quiddepot] `hello-world` :
|
||||||
<span lang="en-US">`repository:hello-world:pull`</span>). Ce qui nous donne :
|
<span lang="en-US">`repository:hello-world:pull`</span>). Ce qui nous donne :
|
||||||
|
|
||||||
[^quiddepot]: Dans un registre, les fichiers qui composent l'image forment un
|
[^quiddepot]: Dans un registre, les fichiers qui composent l'image forment un
|
||||||
dépôt (*repository*).
|
dépôt (*repository*).
|
||||||
@ -50,7 +50,7 @@ souhaite récupérer le contenu du dépôt[^quiddepot] `hello-world` :
|
|||||||
C'est le `token` qu'il faudra fournir lors de nos prochaines requêtes au
|
C'est le `token` qu'il faudra fournir lors de nos prochaines requêtes au
|
||||||
registre.
|
registre.
|
||||||
|
|
||||||
Avec `jq`, on peut l'extraire grâce à :
|
Avec `jq`, on peut l'extraire grâce à :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -58,7 +58,7 @@ Avec `jq`, on peut l'extraire grâce à :
|
|||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
**Attention :** le token expire ! Pensez à le renouveler régulièrement.
|
**Attention :** le token expire ! Pensez à le renouveler régulièrement.
|
||||||
|
|
||||||
En cas d'erreur inexplicable, vous pouvez ajouter un `-v` à la ligne de
|
En cas d'erreur inexplicable, vous pouvez ajouter un `-v` à la ligne de
|
||||||
commande `curl`, afin d'afficher les en-têtes. Prêtez une attention toute
|
commande `curl`, afin d'afficher les en-têtes. Prêtez une attention toute
|
||||||
@ -68,7 +68,7 @@ particulière à `Www-Authenticate`.
|
|||||||
## Lecture de l'index d'images
|
## Lecture de l'index d'images
|
||||||
|
|
||||||
Une fois en possession de notre jeton, nous pouvons maintenant demander l'index
|
Une fois en possession de notre jeton, nous pouvons maintenant demander l'index
|
||||||
d'images à notre registre :
|
d'images à notre registre :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -87,7 +87,7 @@ somme de contrôle.
|
|||||||
## Lecture du manifest
|
## Lecture du manifest
|
||||||
|
|
||||||
Demandons maintenant le manifest correspondant à notre matériel et à notre
|
Demandons maintenant le manifest correspondant à notre matériel et à notre
|
||||||
système d'exploitation :
|
système d'exploitation :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -109,7 +109,7 @@ répertoire `blobs`, il ne s'agit en effet plus de manifest. Si les manifests
|
|||||||
sont toujours stockés par le registre lui-même, les blobs peuvent être délégués
|
sont toujours stockés par le registre lui-même, les blobs peuvent être délégués
|
||||||
à un autre service, par exemple dans le cloud, chez Amazon S3, un CDN, etc.
|
à un autre service, par exemple dans le cloud, chez Amazon S3, un CDN, etc.
|
||||||
|
|
||||||
Pour récupérer la configuration de l'image :
|
Pour récupérer la configuration de l'image :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -120,7 +120,7 @@ curl -s --location \
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
Enfin, armé du `digest` de notre couche, il ne nous reste plus qu'à la demander gentiment :
|
Enfin, armé du `digest` de notre couche, il ne nous reste plus qu'à la demander gentiment :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -134,7 +134,7 @@ wget --header "Authorization: Bearer ${TOKEN}" \
|
|||||||
|
|
||||||
Le type indiqué par le manifest pour cette couche était
|
Le type indiqué par le manifest pour cette couche était
|
||||||
`application/vnd.docker.image.rootfs.diff.tar.gzip`, il s'agit donc d'une
|
`application/vnd.docker.image.rootfs.diff.tar.gzip`, il s'agit donc d'une
|
||||||
tarball compressée au format gzip :
|
tarball compressée au format gzip :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -143,7 +143,7 @@ tar xzf ${DL_LAYER} -C rootfs
|
|||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Et voilà, nous avons extrait notre première image, nous devrions pouvoir :
|
Et voilà, nous avons extrait notre première image, nous devrions pouvoir :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -156,7 +156,7 @@ Hello from Docker!
|
|||||||
|
|
||||||
## Exercice {-}
|
## Exercice {-}
|
||||||
|
|
||||||
Réalisez un script pour automatiser l'ensemble de ces étapes :
|
Réalisez un script pour automatiser l'ensemble de ces étapes :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
|
@ -26,7 +26,7 @@ Tous les fichiers identifiés comme étant à rendre pour ce TP sont à
|
|||||||
placer dans une tarball (pas d'archive ZIP, RAR, ...).
|
placer dans une tarball (pas d'archive ZIP, RAR, ...).
|
||||||
|
|
||||||
Voici une arborescence type (vous pourriez avoir des fichiers supplémentaires,
|
Voici une arborescence type (vous pourriez avoir des fichiers supplémentaires,
|
||||||
cela dépendra de votre avancée dans le projet) :
|
cela dépendra de votre avancée dans le projet) :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```
|
```
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
======
|
======
|
||||||
|
|
||||||
`runc` est le programme qui est responsable de la création effective du
|
`runc` est le programme qui est responsable de la création effective du
|
||||||
conteneur : c'est lui qui va mettre en place toute la machinerie, les points de
|
conteneur : c'est lui qui va mettre en place toute la machinerie, les points de
|
||||||
montages ou volumes, ... Attention, son rôle reste limité à la mise en place de
|
montages ou volumes, ... Attention, son rôle reste limité à la mise en place de
|
||||||
l'environnement conteneurisé, ce n'est pas lui qui télécharge l'image, ni fait
|
l'environnement conteneurisé, ce n'est pas lui qui télécharge l'image, ni fait
|
||||||
l'assemblage des couches de système de fichiers, entre autres.
|
l'assemblage des couches de système de fichiers, entre autres.
|
||||||
@ -21,17 +21,17 @@ essayer de lancer un shell `alpine` avec un volume dans notre home.
|
|||||||
## Prérequis
|
## Prérequis
|
||||||
|
|
||||||
Vous devriez avoir le binaire `runc` ou `docker-runc`. Si ce n'est pas le cas,
|
Vous devriez avoir le binaire `runc` ou `docker-runc`. Si ce n'est pas le cas,
|
||||||
vous pouvez télécharger la dernière version :
|
vous pouvez télécharger la dernière version :
|
||||||
<https://github.com/opencontainers/runc/releases>. La 1.0.0-rc92 est Ok.
|
<https://github.com/opencontainers/runc/releases>. La 1.0.0-rc92 est Ok.
|
||||||
|
|
||||||
|
|
||||||
## Extraction du rootfs
|
## Extraction du rootfs
|
||||||
|
|
||||||
À l'aide du script d'extraction de registre réalisé dans le TP 3, extrayons le
|
À l'aide du script d'extraction de registre réalisé dans le TP 3, extrayons le
|
||||||
rootfs d'alpine : `library/alpine` dans le registre Docker.
|
rootfs d'alpine : `library/alpine` dans le registre Docker.
|
||||||
|
|
||||||
Si vous n'avez pas eu le temps de terminer le script d'extraction, vous pouvez
|
Si vous n'avez pas eu le temps de terminer le script d'extraction, vous pouvez
|
||||||
utiliser :
|
utiliser :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -44,7 +44,7 @@ docker image save alpine | tar xv -C rootfs
|
|||||||
|
|
||||||
L'écriture complète d'un fichier `config.json` pour `runc` est plutôt
|
L'écriture complète d'un fichier `config.json` pour `runc` est plutôt
|
||||||
fastidieux et répétitif, nous allons donc gagner du temps et utiliser la
|
fastidieux et répétitif, nous allons donc gagner du temps et utiliser la
|
||||||
commande suivante, qui nous créera un modèle que nous adapterons un peu :
|
commande suivante, qui nous créera un modèle que nous adapterons un peu :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -52,7 +52,7 @@ runc spec
|
|||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Pour savoir à quoi correspondent tous ces éléments, vous pouvez consulter :
|
Pour savoir à quoi correspondent tous ces éléments, vous pouvez consulter :
|
||||||
<https://github.com/opencontainers/runtime-spec/blob/master/config.md>
|
<https://github.com/opencontainers/runtime-spec/blob/master/config.md>
|
||||||
|
|
||||||
Nous verrons dans les prochains TP, plus en détails tout ce qui porte sur les
|
Nous verrons dans les prochains TP, plus en détails tout ce qui porte sur les
|
||||||
@ -61,7 +61,7 @@ aujourd'hui.
|
|||||||
|
|
||||||
## Test brut
|
## Test brut
|
||||||
|
|
||||||
Voici comment nous pouvons tester le fonctionnement de notre *bundle* :
|
Voici comment nous pouvons tester le fonctionnement de notre *bundle* :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```
|
```
|
||||||
@ -75,7 +75,7 @@ rootfs/ config.json
|
|||||||
|
|
||||||
Quelques informations sont disponibles, mais il ne faut pas s'attendre à
|
Quelques informations sont disponibles, mais il ne faut pas s'attendre à
|
||||||
retrouver tout l'écosystème de `docker` ; ici il n'y a pas de gestion des
|
retrouver tout l'écosystème de `docker` ; ici il n'y a pas de gestion des
|
||||||
journaux, etc. :
|
journaux, etc. :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -92,7 +92,7 @@ virli1 12345 running /tmp/work/runctest 2012-12-12T12:12:12.123456789Z root
|
|||||||
## Attacher notre `home`
|
## Attacher notre `home`
|
||||||
|
|
||||||
Dans le modèle de `config.json`, il y a déjà de nombreux systèmes de fichiers
|
Dans le modèle de `config.json`, il y a déjà de nombreux systèmes de fichiers
|
||||||
qui sont montés. Nous pouvons les filtrer avec :
|
qui sont montés. Nous pouvons les filtrer avec :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -110,7 +110,7 @@ qui sont montés. Nous pouvons les filtrer avec :
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
Pour avoir notre équivalent du `-v /home:/home` de `docker`, il va donc falloir
|
Pour avoir notre équivalent du `-v /home:/home` de `docker`, il va donc falloir
|
||||||
ajouter un élément à cette liste, demandant de *bind* :
|
ajouter un élément à cette liste, demandant de *bind* :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```json
|
```json
|
||||||
@ -143,8 +143,8 @@ stocker les photos (dossier `/srv/images`)[^chmod].
|
|||||||
simple pour l'instant serait d'attribuer les permissions `0777` à la
|
simple pour l'instant serait d'attribuer les permissions `0777` à la
|
||||||
source, temporairement.
|
source, temporairement.
|
||||||
|
|
||||||
Pour ce TP, considérez que vous avez réussi si vous voyez s'afficher :
|
Pour ce TP, considérez que vous avez réussi si vous voyez s'afficher :
|
||||||
|
|
||||||
> `Ready, listening on :8080`
|
> `Ready, listening on :8080`
|
||||||
|
|
||||||
Il faudra attendre les TP suivants pour avoir du réseau dans notre conteneur.
|
Il faudra attendre les TP suivants pour avoir du réseau dans notre conteneur.
|
||||||
|
12
tutorial/docker-internals/vulnerability-scan-ex.md
Normal file
12
tutorial/docker-internals/vulnerability-scan-ex.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
## 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`, ...
|
||||||
|
|
||||||
|
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**
|
||||||
|
contenant les vulnérabilités les plus inquiétantes. Vous placerez ce rapport
|
||||||
|
dans un fichier `${IMAGE}:${TAG}.html` ou `${IMAGE}:${TAG}.txt`.
|
||||||
|
|
||||||
|
Veillez à utiliser une image __différente__ de `mysql`, utilisée en exemple.
|
259
tutorial/docker-internals/vulnerability-scan.md
Normal file
259
tutorial/docker-internals/vulnerability-scan.md
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
\newpage
|
||||||
|
|
||||||
|
Analyse de vulnérabilité
|
||||||
|
========================
|
||||||
|
|
||||||
|
Nous avons vu jusqu'à présent que Docker nous apportait un certain degré de
|
||||||
|
sécurité d'emblée, au lancement de nos conteneurs. Cela peut sans doute
|
||||||
|
paraître quelque peu rassurant pour une personne chargée d'administrer une
|
||||||
|
machine hébergeant des conteneurs, car cela lui apporte des garanties quant à
|
||||||
|
l'effort de cloisonnement mis en place.
|
||||||
|
|
||||||
|
Mais doit-on pour autant s'arrêter là et considérer que nous avons réglé
|
||||||
|
l'ensemble des problématiques de sécurité liées aux conteneurs ?
|
||||||
|
|
||||||
|
Évidemment, non : une fois nos services lancés dans des conteneurs, il ne sont
|
||||||
|
pas moins exposés aux bugs et autres failles applicatives ; qu'elles soient
|
||||||
|
dans notre code ou celui d'une bibliothèque, accessible par rebond, ...
|
||||||
|
|
||||||
|
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
|
||||||
|
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
|
||||||
|
lorsqu'un des programmes ou l'une des bibliothèques que l'on a installés
|
||||||
|
ensuite est mise à jour.
|
||||||
|
|
||||||
|
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
|
||||||
|
protéger, nous allons avoir besoin de réaliser à intervalles réguliers une
|
||||||
|
analyse statique de nos conteneurs.
|
||||||
|
|
||||||
|
![Scan de vulnérabilités sur le Docker Hub](hubvuln.png){ width=90% }
|
||||||
|
|
||||||
|
Selon une étude[^dockerhubvulnerability] réalisée sur les images du Docker Hub,
|
||||||
|
elles présenteraient en moyenne 180 vulnérabilités, beaucoup ne sont pas mises
|
||||||
|
à jour depuis trop longtemps et les vulnérabilités ont surtout tendance à se
|
||||||
|
propager à cause de l'usage d'une image parente pas à jour.
|
||||||
|
|
||||||
|
[^dockerhubvulnerability]: <https://www.enck.org/pubs/shu-codaspy17.pdf>
|
||||||
|
|
||||||
|
Une mesure efficace consiste à reconstruire régulièrement (et surtout
|
||||||
|
automatiquement) les images que l'on publie sur un registre public, sans
|
||||||
|
oublier de mettre à jour l'image de base.
|
||||||
|
|
||||||
|
D'ailleurs, avez-vous vérifié qu'une mise à jour de l'image `nemunaire/youp0m`
|
||||||
|
n'était pas disponible depuis que vous avez commencé à l'utiliser ? Docker ne
|
||||||
|
vérifie jamais si une mise à jour des images que vous avez précédemment
|
||||||
|
téléchargées. Pensez donc régulièrement à appeler :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```
|
||||||
|
42sh$ docker pull IMAGE
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
## Docker Scan
|
||||||
|
|
||||||
|
Pour faire face à ces problèmes de sécurité qui prennent de l'ampleur, le
|
||||||
|
Docker Hub, dans son modèle payant, permet d'analyser régulièrement ses images,
|
||||||
|
pour avoir une idée sur la nécessité de les reconstruire.
|
||||||
|
|
||||||
|
Un plugin existe pour réaliser des scans d'images présentes sur votre machine,
|
||||||
|
à travers les données du Docker Hub. Cela nécessite d'avoir un compte Docker,
|
||||||
|
si vous n'en avez pas, nous verrons dans la section suivante `trivy` qui permet
|
||||||
|
de réaliser ses scans directement sur notre machine, sans passer par un
|
||||||
|
intermédiaire.
|
||||||
|
|
||||||
|
#### Attention {-}
|
||||||
|
|
||||||
|
Par cette méthode, vous êtes limité à 10 scans par mois.
|
||||||
|
|
||||||
|
|
||||||
|
### Installation du plugin
|
||||||
|
|
||||||
|
#### Windows et MacOS {-}
|
||||||
|
|
||||||
|
Avec Docker Desktop, le plugin est déjà installé. Il faut que vous vous soyez
|
||||||
|
préalablement connecté à votre compte Docker avec la commande `docker login`.
|
||||||
|
|
||||||
|
#### Linux {-}
|
||||||
|
|
||||||
|
Comme `docker scan` est un plugin, suivant la méthode d'installation que vous
|
||||||
|
avez suivie, il n'a pas forcément été installé. Si vous obtenez un message
|
||||||
|
d'erreur en lançant la commande, [voici comment récupérer le plugin et
|
||||||
|
l'installer manuellement :](https://github.com/docker/scan-cli-plugin#on-linux)
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```
|
||||||
|
mkdir -p ~/.docker/cli-plugins
|
||||||
|
curl https://github.com/docker/scan-cli-plugin/releases/latest/download/docker-scan_linux_amd64 \
|
||||||
|
-L -s -S -o ~/.docker/cli-plugins/docker-scan
|
||||||
|
chmod +x ~/.docker/cli-plugins/docker-scan
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### Utilisation
|
||||||
|
|
||||||
|
Une fois le plugin installé et la licence du service acceptée, nous pouvons
|
||||||
|
commencer notre analyse :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```
|
||||||
|
42sh$ docker scan nemunaire/fic-admin
|
||||||
|
|
||||||
|
Testing nemunaire/fic-admin...
|
||||||
|
|
||||||
|
Package manager: apk
|
||||||
|
Project name: docker-image|nemunaire/fic-admin
|
||||||
|
Docker image: nemunaire/fic-admin
|
||||||
|
Platform: linux/amd64
|
||||||
|
Base image: alpine:3.14.2
|
||||||
|
|
||||||
|
✓ Tested 16 dependencies for known vulnerabilities, no vulnerable paths found.
|
||||||
|
|
||||||
|
According to our scan, you are currently using the most secure version of the selected base image
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```
|
||||||
|
$ docker scan mysql
|
||||||
|
|
||||||
|
Testing mysql...
|
||||||
|
|
||||||
|
✗ Low severity vulnerability found in util-linux/libuuid1
|
||||||
|
[...]
|
||||||
|
|
||||||
|
✗ High severity vulnerability found in gcc-8/libstdc++6
|
||||||
|
Description: Insufficient Entropy
|
||||||
|
Info: https://snyk.io/vuln/SNYK-DEBIAN10-GCC8-469413
|
||||||
|
Introduced through: apt@1.8.2.3, mysql-community/mysql-community-client@8.0.26-1debian10, mysql-community/mysql-community-server-core@8.0.26-1debian10, mecab-ipadic@2.7.0-20070801+main-2.1, meta-common-packages@meta
|
||||||
|
From: apt@1.8.2.3 > gcc-8/libstdc++6@8.3.0-6
|
||||||
|
From: mysql-community/mysql-community-client@8.0.26-1debian10 > gcc-8/libstdc++6@8.3.0-6
|
||||||
|
From: mysql-community/mysql-community-server-core@8.0.26-1debian10 > gcc-8/libstdc++6@8.3.0-6
|
||||||
|
and 7 more...
|
||||||
|
Image layer: Introduced by your base image (mysql:8.0.26)
|
||||||
|
|
||||||
|
Package manager: deb
|
||||||
|
Project name: docker-image|mysql
|
||||||
|
Docker image: mysql
|
||||||
|
Platform: linux/amd64
|
||||||
|
Base image: mysql:8.0.26
|
||||||
|
|
||||||
|
Tested 135 dependencies for known vulnerabilities, found 79 vulnerabilities.
|
||||||
|
|
||||||
|
According to our scan, you are currently using the most secure version of the selected base image
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
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
|
||||||
|
vulnérabilités dont 11 *high*.
|
||||||
|
|
||||||
|
|
||||||
|
## Trivy
|
||||||
|
|
||||||
|
Le principal outil pour chercher des vulnérabilités connues dans les images
|
||||||
|
Docker est [`trivy`](https://www.aquasec.com/products/trivy/), édité par Aqua
|
||||||
|
security.
|
||||||
|
|
||||||
|
À partir des informations mises à disposition par les équipes de sécurité des
|
||||||
|
principales distributions, `trivy` va générer un rapport, pour chacune de nos
|
||||||
|
images, indiquant les vulnérabilités connues au sein de l'image.
|
||||||
|
|
||||||
|
L'outil se présente sous la forme d'un binaire ou d'une image Docker, prenant
|
||||||
|
un certain nombre d'arguments, notamment le nom de l'image à analyser.
|
||||||
|
|
||||||
|
|
||||||
|
### Utilisation
|
||||||
|
|
||||||
|
Tentons à nouveau d'analyser l'image `mysql` :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```
|
||||||
|
42sh$ docker run --rm aquasec/trivy mysql
|
||||||
|
2021-09-22T10:27:46.509Z INFO Need to update DB
|
||||||
|
2021-09-22T10:27:46.509Z INFO Downloading DB... 100.00% 14.41 MiB p/s 2s
|
||||||
|
2021-09-22T10:27:56.556Z INFO Detected OS: debian
|
||||||
|
2021-09-22T10:27:56.556Z INFO Detecting Debian vulnerabilities...
|
||||||
|
2021-09-22T10:27:56.579Z INFO Number of language-specific files: 0
|
||||||
|
|
||||||
|
mysql (debian 10.10)
|
||||||
|
====================
|
||||||
|
Total: 158 (UNKNOWN: 5, LOW: 19, MEDIUM: 64, HIGH: 61, CRITICAL: 9)
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
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
|
||||||
|
elles ne sont heureusement pas forcément exploitable directement.
|
||||||
|
|
||||||
|
Voyons maintenant s'il y a des différentes avec l'image `nemunaire/fic-admin` :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```
|
||||||
|
42sh$ docker run --rm aquasec/trivy nemunaire/fic-admin
|
||||||
|
2021-09-22T10:29:48.091Z INFO Need to update DB
|
||||||
|
2021-09-22T10:29:48.091Z INFO Downloading DB... 100.00% 15.98 MiB p/s 1s
|
||||||
|
2021-09-22T10:29:51.902Z INFO Detected OS: alpine
|
||||||
|
2021-09-22T10:29:51.902Z INFO Detecting Alpine vulnerabilities...
|
||||||
|
2021-09-22T10:29:51.903Z INFO Number of language-specific files: 1
|
||||||
|
2021-09-22T10:29:51.903Z INFO Detecting gobinary vulnerabilities...
|
||||||
|
|
||||||
|
nemunaire/fic-admin (alpine 3.14.2)
|
||||||
|
===================================
|
||||||
|
Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
|
||||||
|
|
||||||
|
|
||||||
|
srv/admin (gobinary)
|
||||||
|
====================
|
||||||
|
Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
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
|
||||||
|
`/srv/admin`.
|
||||||
|
|
||||||
|
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,
|
||||||
|
Go, ...
|
||||||
|
|
||||||
|
|
||||||
|
### Usage du cache
|
||||||
|
|
||||||
|
Pour éviter de surcharger les serveurs de distributions de la base de données
|
||||||
|
de vulnérabilités, nous devrions utiliser un cache pour faire nos
|
||||||
|
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
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### Format de génération du rapport
|
||||||
|
|
||||||
|
Lorsque nous appelons `trivy` directement, il génère un rapport au format texte
|
||||||
|
lisible directement dans notre terminal. Il peut être pourtant pratique de
|
||||||
|
pouvoir l'exporter pour l'afficher dans un navigateur (par exemple pour le
|
||||||
|
mettre à disposition des développeurs, lors d'une analyse automatique).
|
||||||
|
|
||||||
|
Pour ce faire, on peut ajouter les options suivantes à la ligne de commande de
|
||||||
|
notre conteneur :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```bash
|
||||||
|
--quiet --format template --template "@contrib/html.tpl"
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
En redirigeant la sortie standard vers un fichier, vous pourrez l'ouvrir dans
|
||||||
|
votre navigateur favori.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
![Scan de vulnérabilités sur le registre Quay.io](quay-vulns.png){ width=90% }
|
||||||
|
|
||||||
|
## Clair
|
@ -1,12 +1,12 @@
|
|||||||
\newpage
|
\newpage
|
||||||
|
|
||||||
Ma première image ... par `Dockerfile`
|
Ma première image ... par `Dockerfile`
|
||||||
======================================
|
--------------------------------------
|
||||||
|
|
||||||
Pour construire une image, nous ne sommes pas obligés de passer par une série
|
Pour construire une image, nous ne sommes pas obligés de passer par une série
|
||||||
de *commits*. Docker dispose d'un mécanisme permettant d'automatiser la
|
de *commits*. Docker dispose d'un mécanisme permettant d'automatiser la
|
||||||
construction de nouvelles images. Nous pouvons arriver au même résultat que ce
|
construction de nouvelles images. Nous pouvons arriver au même résultat que ce
|
||||||
que l'on a réussi à faire précédemment en utilisant le `Dockerfile` suivant :
|
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
|
||||||
@ -17,7 +17,7 @@ RUN apt-get install -y nano
|
|||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
La syntaxe d'un `Dockerfile` est simple : le premier mot de chaque ligne est
|
La syntaxe d'un `Dockerfile` est simple : le premier mot de chaque ligne est
|
||||||
l'intitulé d'une instruction (que l'on écrit généralement en majuscule), elle
|
l'intitulé d'une instruction (que l'on écrit généralement en majuscule), elle
|
||||||
est suivie de ses arguments.
|
est suivie de ses arguments.
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ le conteneur, dans le but de le construire.
|
|||||||
|
|
||||||
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 votre fichier `Dockerfile`, plaçons-nous ensuite dedans, puis
|
contenant que votre fichier `Dockerfile`, plaçons-nous ensuite dedans, puis
|
||||||
lançons la commande `build` :
|
lançons la commande `build` :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -36,7 +36,7 @@ docker image build --tag=my_editor .
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
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 :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -46,13 +46,13 @@ docker container run -it my_editor /bin/bash
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
## `RUN` dans le `Dockerfile`
|
### `RUN` dans le `Dockerfile`
|
||||||
|
|
||||||
Dans un `Dockerfile`, chaque ligne est exécutée indépendamment des autres et
|
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
|
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 dans la partie précédente.
|
||||||
|
|
||||||
Cela signifie que l'exemple suivant **ne fonctionne pas** :
|
Cela signifie que l'exemple suivant **ne fonctionne pas** :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```dockerfile
|
```dockerfile
|
||||||
@ -63,11 +63,11 @@ RUN mysql -u root -p toor virli < /db.sql
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
Cet exemple ne fonctionne pas car le serveur MySQL est bien lancé dans le
|
Cet exemple ne fonctionne pas car le serveur MySQL est bien lancé dans le
|
||||||
premier `RUN`{.dockerfile}, mais il se trouve brûtalement arrêté dès lors que
|
premier `RUN`{.dockerfile}, mais il se trouve brutalement arrêté dès lors que
|
||||||
la commande `service` se termine. En fait, à chaque instruction, Docker réalise
|
la commande `service` se termine. En fait, à chaque instruction, Docker réalise
|
||||||
automatiquement l'équivalent un `docker run` suivi d'un `commit`. Et vous
|
automatiquement l'équivalent un `docker run` suivi d'un `commit`. Et vous
|
||||||
pouvez constater par vous-même que, en créant l'image `tinysql` à partir d'un
|
pouvez constater par vous-même que, en créant l'image `tinysql` à partir d'un
|
||||||
simple `apt install mysql` :
|
simple `apt install mysql` :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -78,7 +78,7 @@ docker container run tinysql service mysqld start
|
|||||||
rend la main directement, sans laisser de `mysqld` dans l'arborescence de
|
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 :
|
Pour avoir le résultat escompté, il faut exécuter les commandes ensemble :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```dockerfile
|
```dockerfile
|
||||||
@ -95,9 +95,9 @@ 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
|
||||||
|
|
||||||
Construisons maintenant un conteneur avec un service web :
|
Construisons maintenant un conteneur avec un service web :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```dockerfile
|
```dockerfile
|
||||||
@ -114,10 +114,10 @@ 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
|
(é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).
|
||||||
|
|
||||||
En précisant tous les ports qu'exposent une image dans ses métadonnées, ces
|
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
|
ports seront automatiquement exposés en utilisant l'option `-P` du `run` : cela
|
||||||
assigne une redirection de port aléatoire sur la machine hôte vers votre
|
assigne une redirection de port aléatoire sur la machine hôte vers votre
|
||||||
conteneur :
|
conteneur :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```
|
```
|
||||||
@ -132,13 +132,15 @@ Dans un autre terminal, lancer un `docker container ls` et consulter la colonne
|
|||||||
|
|
||||||
Rendez-vous ensuite dans votre navigateur sur <http://localhost:49153/>.
|
Rendez-vous ensuite dans votre navigateur sur <http://localhost:49153/>.
|
||||||
|
|
||||||
**À vous de jouer :** utilisez l'instruction `COPY`{.dockerfile} pour afficher votre propre
|
#### À vous de jouer {-}
|
||||||
|
|
||||||
|
Utilisez l'instruction `COPY`{.dockerfile} pour afficher votre propre
|
||||||
`index.html` remplaçant celui installé de base par `nginx`. Si vous manquez
|
`index.html` remplaçant celui installé de base par `nginx`. Si vous manquez
|
||||||
d'inspiration, utilisez [cette page de compte à
|
d'inspiration, utilisez [cette page de compte à
|
||||||
rebours](https://virli.nemunai.re/countdown.html).
|
rebours](https://virli.nemunai.re/countdown.html).
|
||||||
|
|
||||||
|
|
||||||
## Les caches
|
### Les caches
|
||||||
|
|
||||||
Nous avons vu que chaque instruction de notre `Dockerfile` est exécutée dans un
|
Nous avons vu que chaque instruction de notre `Dockerfile` est exécutée dans un
|
||||||
conteneur, qui génère une image intermédiaire. Cette image intermédiaire sert
|
conteneur, qui génère une image intermédiaire. Cette image intermédiaire sert
|
||||||
@ -164,19 +166,19 @@ Les couches du cache peuvent être partagées entre plusieurs conteneur, 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 (rappelez-vous le principe d'union FS).
|
||||||
|
|
||||||
Pour profiter du cache, on va placer de préférences les étapes les plus
|
Pour profiter du cache, on va placer de préférence les étapes les plus
|
||||||
génériques (qui seraient les plus susceptibles d'apparaître dans d'autres
|
génériques (qui seraient les plus susceptibles d'apparaître dans d'autres
|
||||||
images), en haut du `Dockerfile`.
|
images), en haut du `Dockerfile`.
|
||||||
|
|
||||||
|
|
||||||
## Métadonnées pures
|
### Métadonnées pures
|
||||||
|
|
||||||
L'instruction `LABEL`{.dockerfile} permet d'ajouter une métadonnée à une image,
|
L'instruction `LABEL`{.dockerfile} permet d'ajouter une métadonnée à une image,
|
||||||
sous forme de clef/valeur.
|
sous forme de clef/valeur.
|
||||||
|
|
||||||
Une métadonnée
|
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/mainline/stretch/Dockerfile#L3)
|
||||||
est d'indiquer le nom du mainteneur de l'image :
|
est d'indiquer le nom du mainteneur de l'image :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```dockerfile
|
```dockerfile
|
||||||
@ -194,10 +196,10 @@ On le place dès le début, car comme c'est une information qui n'est pas amener
|
|||||||
à changer, elle sera toujours retrouvée en cache.
|
à changer, elle sera toujours retrouvée en cache.
|
||||||
|
|
||||||
|
|
||||||
## Commande par défaut
|
### Commande par défaut
|
||||||
|
|
||||||
Vous pouvez placer dans un `Dockerfile` une instruction `CMD`{.dockerfile} qui
|
Vous pouvez placer dans un `Dockerfile` une instruction `CMD`{.dockerfile} qui
|
||||||
sera exécutée si aucune commande n'est passée lors du `run`, par exemple :
|
sera exécutée si aucune commande n'est passée lors du `run`, par exemple :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```dockerfile
|
```dockerfile
|
||||||
@ -218,7 +220,7 @@ retirez cette option pour voir ce qui ne va pas, ou utilisez la commande
|
|||||||
`docker container logs`.
|
`docker container logs`.
|
||||||
|
|
||||||
|
|
||||||
## Construire son application au moment de la construction du conteneur ?
|
### Construire son application au moment de la construction du conteneur ?
|
||||||
|
|
||||||
Comment faire lorsque l'on a besoin de compiler une application avant de
|
Comment faire lorsque l'on a besoin de compiler une application avant de
|
||||||
l'intégrer dans le conteneur ?
|
l'intégrer dans le conteneur ?
|
||||||
@ -230,14 +232,14 @@ versions de ces outils existent, laquelle choisir ? ... Ok c'est trop
|
|||||||
compliqué.
|
compliqué.
|
||||||
|
|
||||||
D'un autre côté, si l'on fait cela dans un conteneur, celui-ci contiendra dans
|
D'un autre côté, si l'on fait cela dans un conteneur, celui-ci contiendra dans
|
||||||
ses couches des données inutiles à l'exécution : les sources, les produits
|
ses couches des données inutiles à l'exécution : les sources, les produits
|
||||||
intermédiaires de compilation, le compilateur, n'ont rien à faire dans les
|
intermédiaires de compilation, le compilateur, n'ont rien à faire dans les
|
||||||
couches de notre image.
|
couches de notre image.
|
||||||
|
|
||||||
Le meilleur des deux mondes se trouve dans les *Multi-stage builds* : au sein
|
Le meilleur des deux mondes se trouve dans les *Multi-stage builds* : au sein
|
||||||
du même `Dockerfile`, on va réaliser les opérations de préparation dans un ou
|
du même `Dockerfile`, on va réaliser les opérations de préparation dans un ou
|
||||||
plusieurs conteneurs, avant d'agréger le contenu compilé au sein du conteneur
|
plusieurs conteneurs, avant d'agréger le contenu compilé au sein du conteneur
|
||||||
final :
|
final :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```dockerfile
|
```dockerfile
|
||||||
@ -252,7 +254,7 @@ CMD ["/hello"]
|
|||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Dans cet exemple, deux conteneurs distincts sont créés : le premier à partir de
|
Dans cet exemple, deux conteneurs distincts sont créés : le premier à partir de
|
||||||
l'image `gcc`, il contient tout le nécessaire pour compiler notre
|
l'image `gcc`, il 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
|
||||||
@ -261,12 +263,12 @@ produit de notre compilation.
|
|||||||
L'image ainsi générée est minime, car elle ne contient rien d'autre que le
|
L'image ainsi générée est minime, car elle ne contient rien d'autre que le
|
||||||
strict nécessaire pour s'exécuter.
|
strict nécessaire pour s'exécuter.
|
||||||
|
|
||||||
### Étapes nommées
|
#### Étapes nommées\
|
||||||
|
|
||||||
Nous avons utilisé `--from=0` pour désigner la première image de notre
|
Nous avons utilisé `--from=0` pour désigner la première image de notre
|
||||||
`Dockerfile`. Lorsque l'on réalise des montages plus complexe, on peut vouloir
|
`Dockerfile`. Lorsque l'on réalise des montages plus complexes, on peut vouloir
|
||||||
donner des noms à chaque image, plutôt que de devoir jongler avec les
|
donner des noms à chaque image, plutôt que de devoir jongler avec les
|
||||||
numéros. Dans ce cas, on indiquera :
|
numéros. Dans ce cas, on indiquera :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```dockerfile
|
```dockerfile
|
||||||
@ -281,9 +283,9 @@ CMD ["/hello"]
|
|||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Par défaut la dernière étape du `Dockerfile` est retenu comme étant l'image que
|
Par défaut la dernière étape du `Dockerfile` est retenue comme étant l'image que
|
||||||
l'on souhaite `tagger`, mais il est possible de préciser quelle image
|
l'on souhaite `tagger`, mais il est possible de préciser quelle image
|
||||||
spécifiquement on souhaite construire avec l'option `--target` :
|
spécifiquement on souhaite construire avec l'option `--target` :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```
|
```
|
||||||
@ -297,13 +299,13 @@ 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'autres instructions ?
|
### D'autres instructions ?
|
||||||
|
|
||||||
Consultez <https://docs.docker.com/engine/reference/builder/> pour la liste
|
Consultez <https://docs.docker.com/engine/reference/builder/> pour la liste
|
||||||
complète des instructions reconnues.
|
complète des instructions reconnues.
|
||||||
|
|
||||||
|
|
||||||
## Exercice {-}
|
### Exercice {-}
|
||||||
|
|
||||||
Pour mettre en application tout ce que nous venons de voir, réalisons le
|
Pour mettre en application tout ce que nous venons de voir, réalisons le
|
||||||
`Dockerfile` du service web [`youp0m`](https://you.p0m.fr/) que nous avons
|
`Dockerfile` du service web [`youp0m`](https://you.p0m.fr/) que nous avons
|
||||||
@ -312,14 +314,14 @@ utilisé la semaine dernière.
|
|||||||
Pour réaliser ce genre de contribution, on ajoute généralement un `Dockerfile`
|
Pour réaliser ce genre de contribution, on ajoute généralement un `Dockerfile`
|
||||||
à la racine du dépôt.
|
à la racine du dépôt.
|
||||||
|
|
||||||
Vous pouvez cloner le dépôts de sources de `youp0m` à :
|
Vous pouvez cloner le dépôt de sources de `youp0m` à :
|
||||||
<https://gitea.nemunai.re/nemunaire/youp0m.git>
|
<https://git.nemunai.re/nemunaire/youp0m.git>
|
||||||
|
|
||||||
Pour compiler le projet, vous pouvez utiliser dans votre `Dockerfile`
|
Pour compiler le projet, vous pouvez utiliser dans votre `Dockerfile`
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```dockerfile
|
```dockerfile
|
||||||
FROM golang:1.13
|
FROM golang:1.16
|
||||||
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
|
||||||
|
@ -1,31 +1,99 @@
|
|||||||
\newpage
|
\newpage
|
||||||
|
|
||||||
Personnalisation du point d'entrée du conteneur
|
Le point d'entrée du conteneur
|
||||||
===============================================
|
==============================
|
||||||
|
|
||||||
## Point d'entrée basique
|
Le point d'entrée ou l'*entrypoint* correspond à la ligne de commande qui sera
|
||||||
|
exécutée au lancement du conteneur. Deux paramètres de notre `Dockerfile`
|
||||||
|
permettent de changer cette ligne de commande : `CMD`{.dockerfile} et
|
||||||
|
`ENTRYPOINT`{.dockerfile}.
|
||||||
|
|
||||||
Afin de faire bénéficier à nos utilisateurs d'une immersion parfaite, nous
|
- **`CMD`{.dockerfile}** est la commande par défaut : lorsqu'au moment de
|
||||||
allons faire en sorte que notre image puisse être utilisée ainsi :
|
`run`, aucun paramètre n'est passé après le nom de l'image, le contenu du
|
||||||
|
dernier `CMD`{.dockerfile} rencontré sera utilisé.
|
||||||
|
|
||||||
|
- `ENTRYPOINT`{.dockerfile}, s'il est défini, sera réellement exécuté, qu'il y
|
||||||
|
ait ou non des arguments pour remplacer la ligne de commande. Lorsque des
|
||||||
|
arguments sont passés ou qu'un `CMD`{.dockerfile}, ceux-ci sont passés en
|
||||||
|
argument de l'`ENTRYPOINT`{.dockerfile}.
|
||||||
|
|
||||||
|
Par exemple, avec le `Dockerfile` suivant, construisant l'image `sample-echo` :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```dockerfile
|
||||||
|
FROM ubuntu
|
||||||
|
CMD ["world"]
|
||||||
|
ENTRYPOINT ["/bin/echo", "Hello"]
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Nous obtenons les résultats suivants :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
docker run -d -p 80:80 youp0m -bind :80
|
42sh$ docker run sample-echo
|
||||||
|
Hello world
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Dans ce premier cas, il n'y a pas d'argument après le nom de l'image, c'est
|
||||||
|
donc le contenu de `CMD`{.dockerfile} qui est utilisé ; il est donc passé en
|
||||||
|
argument à l'`ENTRYPOINT`{.dockerfile}. Concrètement, la première ligne de
|
||||||
|
commande exécutée est :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```json
|
||||||
|
["/bin/echo", "Hello", "world"]
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Essayons maintenant avec des arguments :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```sh
|
||||||
|
42sh$ docker run sample-echo $USER
|
||||||
|
Hello neo
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Le contenu de la variable `$USER`, interprété par notre shell, est utilisé à la
|
||||||
|
place de `CMD`{.dockerfile}.
|
||||||
|
|
||||||
|
|
||||||
|
Si l'on a besoin d'exécuter un `ENTRYPOINT`{.dockerfile} différent, il reste la
|
||||||
|
possibilité de le surcharger au moyen d'un argument :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```sh
|
||||||
|
42sh$ docker run --entrypoint /bin/sh sample-echo
|
||||||
|
01abc345# _
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
## Personnalisation basique
|
||||||
|
|
||||||
|
Afin de faire bénéficier à nos utilisateurs d'une immersion parfaite, nous
|
||||||
|
allons faire en sorte que notre image puisse être utilisée ainsi :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```bash
|
||||||
|
docker run -d -p 80:80 youp0m -bind :80
|
||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
Plutôt que de laisser l'utilisateur se débrouiller avec le chemin interne dans
|
Plutôt que de laisser l'utilisateur se débrouiller avec le chemin interne dans
|
||||||
lequel il va trouver le bon binaire :
|
lequel il va trouver le bon binaire :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
docker run -d -p 80:80 youp0m /srv/youp0m -bind :80
|
docker run -d -p 80:80 youp0m /srv/youp0m -bind :80
|
||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Essayez les deux commandes, si vous avez utilisé l'instruction
|
Essayez les deux commandes, si vous avez utilisé l'instruction
|
||||||
`CMD`{.dockerfile} dans votre `Dockerfile` jusqu'à présent, vous devez vous
|
`CMD`{.dockerfile} dans votre `Dockerfile` jusqu'à présent, vous devriez vous
|
||||||
trouver dans le deuxième cas.
|
trouver dans le deuxième cas.
|
||||||
|
|
||||||
Pour améliorer la situation, définissez
|
Pour améliorer la situation, définissez
|
||||||
@ -35,13 +103,13 @@ de votre image sur le binaire `/srv/youp0m`.
|
|||||||
|
|
||||||
## Point d'entrée avancé
|
## Point d'entrée avancé
|
||||||
|
|
||||||
Dans certains cas, il peut être nécessaire au lancement d'un conteneur, de
|
Dans certains cas, il peut être nécessaire au lancement d'un conteneur de
|
||||||
faire un minimum d'étapes d'initialisation avant que le conteneur ne soit
|
faire un minimum d'étapes d'initialisation avant que le conteneur ne soit
|
||||||
opérationnel (rappelez-vous les options que l'on passait à l'image `mysql` pour
|
opérationnel (rappelez-vous les options que l'on passait à l'image `mysql` pour
|
||||||
créer un utilisateur et une base).
|
créer un utilisateur et une base).
|
||||||
|
|
||||||
Notre but, dans cette partie, sera de créer un utilisateur administrateur
|
Notre but, dans cette partie, sera de créer un utilisateur administrateur
|
||||||
(pouvant passer le contrôle d'accès <http://localhost:8080/admin/>) :
|
(pouvant passer le contrôle d'accès <http://localhost:8080/admin/>) :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -60,7 +128,7 @@ utilisation de ceux-ci, de leur modification, ...
|
|||||||
|
|
||||||
À la fin d'un script d'`ENTRYPOINT`{.dockerfile}, afin de garder comme premier
|
À la fin d'un script d'`ENTRYPOINT`{.dockerfile}, afin de garder comme premier
|
||||||
processus du conteneur le programme qui nous intéresse, on réalise un
|
processus du conteneur le programme qui nous intéresse, on réalise un
|
||||||
`execve(2)`, sans `fork(2)` :
|
`execve(2)`, sans `fork(2)` :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -68,7 +136,7 @@ exec /srv/youp0m $@
|
|||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Dans cet exemple : `exec` est la commande interne à notre shell pour lui
|
Dans cet exemple : `exec` est la commande interne à notre shell pour lui
|
||||||
indiquer de remplacer son fil d'exécution par cette commande (sans `exec`, il
|
indiquer de remplacer son fil d'exécution par cette commande (sans `exec`, il
|
||||||
va `fork(2)` avant). `$@` est ici pour transmettre tel quel la liste des
|
va `fork(2)` avant). `$@` est ici pour transmettre tel quel la liste des
|
||||||
arguments passés au script (il s'agit de ceux donnés par l'utilisateur, sur la
|
arguments passés au script (il s'agit de ceux donnés par l'utilisateur, sur la
|
||||||
@ -78,8 +146,8 @@ l'utilisateur n'a rien précisé).
|
|||||||
|
|
||||||
### Format du fichier `htpasswd`
|
### Format du fichier `htpasswd`
|
||||||
|
|
||||||
Le format attendu est celui d'un fichier `htpasswd` typique d'Apache. Vous
|
Le format attendu est celui d'un fichier `htpasswd` typique d'Apache. Nous
|
||||||
pourriez obtenir un fichier valide avec :
|
pouvons obtenir un fichier valide avec :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -102,11 +170,12 @@ d'environnement, à la recherche de `YOUP0M_USERNAME` et `YOUP0M_PASSWORD` pour
|
|||||||
initialiser le fichier `.htpasswd` qui sera ajouté à la liste des arguments à
|
initialiser le fichier `.htpasswd` qui sera ajouté à la liste des arguments à
|
||||||
passer au service.
|
passer au service.
|
||||||
|
|
||||||
Par exemple :
|
Par exemple :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```
|
```
|
||||||
42sh$ docker run -d -p 8081:8081 -e YOUP0M_USERNAME=admin -e YOUP0M_PASSWORD=admin youp0m -bind=:8081
|
42sh$ docker run -d -p 8081:8081 -e YOUP0M_USERNAME=admin \
|
||||||
|
-e YOUP0M_PASSWORD=admin youp0m -bind=:8081
|
||||||
|
|
||||||
42sh$ curl -u admin:badpasswd http://localhost:8081/admin/
|
42sh$ curl -u admin:badpasswd http://localhost:8081/admin/
|
||||||
You are not allowed to perform this request.
|
You are not allowed to perform this request.
|
||||||
|
@ -4,7 +4,7 @@ Premières étapes
|
|||||||
================
|
================
|
||||||
|
|
||||||
Dans un premier temps, nous allons créer une image Docker comme si l'on
|
Dans un premier temps, nous allons créer une image Docker comme si l'on
|
||||||
réalisait une installation sur une machine classique : en suivant une recette,
|
réalisait une installation sur une machine classique : en suivant une recette,
|
||||||
sans trop se préoccuper des fonctionnalités que propose Docker.
|
sans trop se préoccuper des fonctionnalités que propose Docker.
|
||||||
|
|
||||||
La machine (notre première image Docker) contiendra tout le nécessaire pour
|
La machine (notre première image Docker) contiendra tout le nécessaire pour
|
||||||
@ -26,7 +26,7 @@ télécharger le paquet mis à disposition puis à l'installer via `dpkg -i`.
|
|||||||
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 :
|
||||||
|
|
||||||
* télécharger le paquet hors du conteneur, le copier, puis l'installer.
|
* télécharger le paquet hors du conteneur, le copier, puis l'installer.
|
||||||
* faire un `RUN` avec toutes ces opérations (sans oublier l'installation
|
* faire un `RUN` avec toutes ces opérations (sans oublier l'installation
|
||||||
@ -64,7 +64,7 @@ InfluxDB. Nous allons installer `telegraf` sur notre machine à l'aide de la
|
|||||||
[documentation](https://docs.influxdata.com/telegraf/v1.8/introduction/installation/).
|
[documentation](https://docs.influxdata.com/telegraf/v1.8/introduction/installation/).
|
||||||
|
|
||||||
Ces quelques lignes devraient suffir à lancer la collecte, à condition que
|
Ces quelques lignes devraient suffir à lancer la collecte, à condition que
|
||||||
votre InfluxDB écoute sur le port 8086 local :
|
votre InfluxDB écoute sur le port 8086 local :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -78,7 +78,7 @@ TELEGRAF_CONFIG_PATH=./telegraf/etc/telegraf/telegraf.conf ./telegraf/usr/bin/te
|
|||||||
Rendez-vous ensuite dans [l'interface d'InfluxDB](http://localhost:8083/) pour
|
Rendez-vous ensuite dans [l'interface d'InfluxDB](http://localhost:8083/) pour
|
||||||
voir si la collecte se passe bien.
|
voir si la collecte se passe bien.
|
||||||
|
|
||||||
Dans l'interface sélectionnez la base `telegraf` puis explorez les valeurs :
|
Dans l'interface sélectionnez la base `telegraf` puis explorez les valeurs :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```sql
|
```sql
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
\newpage
|
\newpage
|
||||||
|
|
||||||
Retour sur les bonnes pratiques
|
Les bonnes pratiques
|
||||||
===============================
|
--------------------
|
||||||
|
|
||||||
Pour chaque bonne pratique ci-dessous, vérifiez que vous la respectez
|
Pour chaque bonne pratique ci-dessous, vérifiez que vous la respectez
|
||||||
bien, faites les modifications nécessaires dans votre `Dockerfile`.
|
bien, faites les modifications nécessaire dans votre `Dockerfile`.
|
||||||
|
|
||||||
## Utilisez le fichier `.dockerignore`
|
### Utilisez le fichier `.dockerignore`
|
||||||
|
|
||||||
Dans la plupart des cas, vos `Dockerfile` seront dans des dossiers contenant
|
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
|
beaucoup de fichiers qui ne sont pas nécessaire à la construction de votre
|
||||||
@ -25,7 +25,7 @@ Pour plus d'informations, vous pouvez consulter la documentation accessible à
|
|||||||
<https://docs.docker.com/engine/reference/builder/#dockerignore-file>.
|
<https://docs.docker.com/engine/reference/builder/#dockerignore-file>.
|
||||||
|
|
||||||
|
|
||||||
## N'installez rien de superflu
|
### N'installez rien de superflu
|
||||||
|
|
||||||
Afin de réduire la quantité de dépendances à installer, n'installez pas de
|
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
|
||||||
@ -33,19 +33,30 @@ 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
|
comme serveur web. Un autre conteneur pourra contenir cet éditeur de texte dans
|
||||||
les cas où vous avez besoin de modifier des données.
|
les cas où vous avez besoin de modifier des données.
|
||||||
|
|
||||||
En plus, cela réduira le temps de build et la taille des images produites !
|
En plus, cela réduira le temps de construction et la taille des images
|
||||||
|
produites !
|
||||||
|
|
||||||
|
Avec `apt` par exemple, vous pouvez ajouter l'option `--no-install-recommends`
|
||||||
|
lors vous installer un paquet qui vient avec de nombreuses recommandations
|
||||||
|
inutiles. C'est le cas par exemple de `ffmpeg` ou de `gstreamer`, qui viennent
|
||||||
|
tous deux avec de nombreux *codecs*, mais peut-être que vous savez exactement
|
||||||
|
de quels *codecs* vous avez besoin.
|
||||||
|
|
||||||
|
|
||||||
## Minimisez le nombre de couches
|
### Minimisez le nombre de couches
|
||||||
|
|
||||||
Vous devez trouver l'équilibre idéal entre la lisibilité de votre `Dockerfile`
|
Vous devez trouver l'équilibre idéal entre la lisibilité de votre `Dockerfile`
|
||||||
(qui assure la maintenabilité sur le long-terme) et le nombre de couches
|
(qui assure la maintenabilité sur le long terme) et le nombre de couches
|
||||||
créées.
|
créées.
|
||||||
|
|
||||||
|
Utilisez les constructions en plusieurs étapes pour n'en recopier que les
|
||||||
|
éléments utiles dans l'image finale. C'est le meilleur moyen de gagner de la
|
||||||
|
place.
|
||||||
|
|
||||||
## Ordonnez vos lignes de commandes complexes
|
|
||||||
|
|
||||||
### Allez à la ligne pour séparer les longues lignes de commandes complexes
|
### Ordonnez vos lignes de commandes complexes
|
||||||
|
|
||||||
|
#### Allez à la ligne pour séparer les longues lignes de commandes complexes
|
||||||
|
|
||||||
Aérez vos `Dockerfile` !
|
Aérez vos `Dockerfile` !
|
||||||
|
|
||||||
@ -64,7 +75,7 @@ RUN apt-get update && apt-get install -y \
|
|||||||
|
|
||||||
Notez les backslashs à la fin des lignes, indiquant qu'elle n'est pas terminée.
|
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
|
Lorsque c'est possible, ordonnez vos lignes suivant un ordre logique. Par
|
||||||
exemple :
|
exemple :
|
||||||
@ -81,7 +92,7 @@ RUN apt-get update && apt-get install -y \
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
## Profitez du système de cache
|
### Profitez du système de cache
|
||||||
|
|
||||||
Le processus de construction de votre image Docker va lire les informations de
|
Le processus de construction de votre image Docker va lire les informations de
|
||||||
votre Dockerfile dans l'ordre. Pour chaque instruction, Docker va essayer de
|
votre Dockerfile dans l'ordre. Pour chaque instruction, Docker va essayer de
|
||||||
@ -93,7 +104,7 @@ Il y a un certain nombre de règles à connaître pour bien utiliser ce mécanis
|
|||||||
- En démarrant d'une image de base déjà présente dans le cache (`docker
|
- 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
|
images`), l'instruction suivante est comparée avec toutes les autres images
|
||||||
existantes qui en dérivent directement. Si aucune image correspondant n'est
|
existantes qui en dérivent directement. Si aucune image correspondant n'est
|
||||||
trouvé pour l'instruction, le cache est invalidé pour le reste de cette
|
trouvée pour l'instruction, le cache est invalidé pour le reste de cette
|
||||||
construction.
|
construction.
|
||||||
- Dans la plupart des cas, Docker va simplement comparer l'instruction lue avec
|
- Dans la plupart des cas, Docker va simplement comparer l'instruction lue avec
|
||||||
le(s) différente(s) image(s) qui dérive(nt) de la commande précédente. Si
|
le(s) différente(s) image(s) qui dérive(nt) de la commande précédente. Si
|
||||||
@ -106,7 +117,7 @@ Il y a un certain nombre de règles à connaître pour bien utiliser ce mécanis
|
|||||||
dans le `Dockerfile` vont être exécutées.
|
dans le `Dockerfile` vont être exécutées.
|
||||||
|
|
||||||
|
|
||||||
## Concevez des conteneur éphémères
|
### 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
|
devraient pouvoir être arrêtés, détruits et recréés sans nécessiter d'étape de
|
||||||
@ -114,23 +125,19 @@ reconfiguration. La configuration devrait se faire au lancement du conteneur ou
|
|||||||
lors de sa construction.
|
lors de sa construction.
|
||||||
|
|
||||||
|
|
||||||
## Cas d'`apt-get` et des gestionnaires de paquets
|
### Cas d'`apt-get` et des gestionnaires de paquets
|
||||||
|
|
||||||
- N'exécutez pas `apt-get update` seul sur une ligne. Cela risque de poser des
|
- N'exécutez pas `apt-get update` seul sur une ligne. Cela risque de poser des
|
||||||
problèmes de cache, car la ligne ne va jamais changer et le cache sera
|
problèmes de cache, car la ligne ne va jamais changer et le cache sera
|
||||||
toujours utilisé. Vous risquez de récupérer des paquets qui ne sont pas à
|
toujours utilisé. Vous risquez de récupérer des paquets qui ne sont pas à
|
||||||
jour.
|
jour.
|
||||||
- Évitez de mettre à jour le système fourni (via `apt-get upgrade` ou `apt-get
|
|
||||||
update`). Si l'image n'est pas à jour, contactez son mainteneur. Si vous avez
|
|
||||||
besoin d'une version à jour d'un paquet distribué avec l'image, préférez
|
|
||||||
l'utilisation d'`apt-get install -y foo` qui mettra à jour exclusivement le
|
|
||||||
paquet `foo`, sans altérer le reste du système.
|
|
||||||
- Pour assurer une bonne gestion du cache, n'hésitez pas à indiquer les
|
- Pour assurer une bonne gestion du cache, n'hésitez pas à indiquer les
|
||||||
versions des programmes que vous voulez installer sur votre ligne de commande
|
versions des programmes que vous voulez installer sur votre ligne de commande
|
||||||
`apt-get`.
|
`apt-get`. Lors d'un changement de version, vous changerez la ligne, le cache
|
||||||
|
ne sera donc pas utilisé.
|
||||||
|
|
||||||
|
|
||||||
## Exposez les ports standards
|
### Exposez les ports standards
|
||||||
|
|
||||||
La commande `EXPOSE`{.dockerfile} vous permet d'indiquer les ports sur lesquels
|
La commande `EXPOSE`{.dockerfile} vous permet d'indiquer les ports sur lesquels
|
||||||
votre conteneur s'attend à recevoir des paquets venant de l'extérieur. Ces
|
votre conteneur s'attend à recevoir des paquets venant de l'extérieur. Ces
|
||||||
@ -145,7 +152,7 @@ S'il y a un conflit sur la machine hôte, il sera toujours temps de créer une
|
|||||||
redirection à ce moment là.
|
redirection à ce moment là.
|
||||||
|
|
||||||
|
|
||||||
## La bonne utilisation de l'`ENTRYPOINT`
|
### La bonne utilisation de l'`ENTRYPOINT`
|
||||||
|
|
||||||
L'entrypoint peut être utilisé de deux manières différentes :
|
L'entrypoint peut être utilisé de deux manières différentes :
|
||||||
|
|
||||||
@ -185,7 +192,7 @@ exec "$@"
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
## `[""]`, `'` et sans `[]`
|
### `[""]`, `'` et sans `[]`
|
||||||
|
|
||||||
Les instructions `ENTRYPOINT`{.dockerfile} et `CMD`{.dockerfile} peuvent
|
Les instructions `ENTRYPOINT`{.dockerfile} et `CMD`{.dockerfile} peuvent
|
||||||
prendre deux formes :
|
prendre deux formes :
|
||||||
@ -200,13 +207,13 @@ 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 simple quotes.
|
||||||
|
|
||||||
|
|
||||||
## Volumes
|
### Volumes
|
||||||
|
|
||||||
L'instruction `VOLUME`{.dockerfile} doit être utilisée pour exposer tous les
|
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
|
### Réduisez les privilèges
|
||||||
|
|
||||||
Utilisez l'instruction `USER`{.dockerfile} dès que vous le pouvez, lorsqu'un
|
Utilisez l'instruction `USER`{.dockerfile} dès que vous le pouvez, lorsqu'un
|
||||||
service ne réclame pas de privilège particulier.
|
service ne réclame pas de privilège particulier.
|
||||||
@ -214,7 +221,7 @@ 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
|
### Profitez du système de liaison et de résolution de nom
|
||||||
|
|
||||||
Dès lors que vous effectuez un lien avec un autre conteneur, son nom (ou son
|
Dès lors que vous effectuez un lien avec un autre conteneur, son nom (ou son
|
||||||
alias) est ajouté au fichier `/etc/hosts`. Cela signifie que lorsqu'un nom de
|
alias) est ajouté au fichier `/etc/hosts`. Cela signifie que lorsqu'un nom de
|
||||||
@ -226,7 +233,7 @@ Au moment du `docker run`, vous pouvez préciser d'autres noms d'ĥôtes
|
|||||||
particuliers en utilisant l'option `--add-host`.
|
particuliers en utilisant l'option `--add-host`.
|
||||||
|
|
||||||
|
|
||||||
## Exécutez un seul processus par conteneur
|
### Exécutez un seul processus par conteneur
|
||||||
|
|
||||||
Dans la majorité des cas, vous ne devriez jamais lancer plus d'un seul
|
Dans la majorité des cas, vous ne devriez jamais lancer plus d'un seul
|
||||||
processus par conteneur. Il est préférable de répartir chaque application dans
|
processus par conteneur. Il est préférable de répartir chaque application dans
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
\newpage
|
|
||||||
|
|
||||||
Modification interactive
|
Modification interactive
|
||||||
========================
|
------------------------
|
||||||
|
|
||||||
Pour créer une image, commençons par entrer dans un nouveau conteneur :
|
Pour créer une image, commençons par entrer dans un nouveau conteneur :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -12,11 +10,11 @@ docker container run -it ubuntu /bin/bash
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
Nous voilà maintenant dans le conteneur ! Il est assez épuré, il n'y a rien de
|
Nous voilà maintenant dans le conteneur ! Il est assez épuré, il n'y a rien de
|
||||||
superflu : même pas d'éditeur de texte : ni vim, ni emacs, même pas `vi` !
|
superflu : même pas d'éditeur de texte : ni vim, ni emacs, même pas `vi` !
|
||||||
|
|
||||||
La première chose à faire est de télécharger la liste des paquets. En effet,
|
La première chose à faire est de télécharger la liste des paquets. En effet,
|
||||||
afin de ne pas livrer de superflu, la liste des paquets et son cache ne sont
|
afin de ne pas livrer de superflu, la liste des paquets et son cache ne sont
|
||||||
pas incluses dans le conteneur.
|
pas inclus dans le conteneur.
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -31,14 +29,14 @@ jour automatiques et systématiques des éléments présents dans l'image,
|
|||||||
qui apporte des changements peut altérer le comportement du conteneur,
|
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.
|
||||||
|
|
||||||
[^SECURITY_UPDATE]: Voir cet article :
|
[^SECURITY_UPDATE]: Voir cet article :
|
||||||
<https://pythonspeed.com/articles/security-updates-in-docker/>
|
<https://pythonspeed.com/articles/security-updates-in-docker/>
|
||||||
|
|
||||||
Si vous souhaitez disposez d'une nouvelle version de l'image, il est
|
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
|
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.
|
||||||
|
|
||||||
Installons maintenant un programme :
|
Installons maintenant un programme :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -50,7 +48,7 @@ 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
|
Sauvegardons nos modifications en tant que nouvelle image Docker, avec
|
||||||
la commande `commit` :
|
la commande `commit` :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -69,7 +67,7 @@ dernière couche de notre nouvelle image.
|
|||||||
|
|
||||||
![`docker commit`](commit.png)
|
![`docker commit`](commit.png)
|
||||||
|
|
||||||
Testons alors sans plus attendre notre nouvelle image :
|
Testons alors sans plus attendre notre nouvelle image :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -81,9 +79,9 @@ Vous constatez cette fois que vous pouvez lancer `nano`, alors que vous ne
|
|||||||
pouvez toujours pas le faire dans un conteneur issu d'une image `ubuntu` !
|
pouvez toujours pas le faire dans un conteneur issu d'une image `ubuntu` !
|
||||||
|
|
||||||
|
|
||||||
## Scripté ?
|
### Scripté ?
|
||||||
|
|
||||||
On peut automatiser les étapes ci-dessus avec un script qui ressemblerait à ça :
|
On peut automatiser les étapes ci-dessus avec un script qui ressemblerait à ça :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -94,7 +92,7 @@ docker container commit $(docker container ls -lq) my_nano
|
|||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
On obtiendra de la même manière notre image `my_nano` :
|
On obtiendra de la même manière notre image `my_nano` :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
|
4
tutorial/dockerfiles/intro.md
Normal file
4
tutorial/dockerfiles/intro.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
\newpage
|
||||||
|
|
||||||
|
Créer une image
|
||||||
|
===============
|
122
tutorial/dockerfiles/others.md
Normal file
122
tutorial/dockerfiles/others.md
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
\newpage
|
||||||
|
|
||||||
|
D'autres méthodes pour créer des images
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
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
|
||||||
|
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
|
||||||
|
spécifiques.
|
||||||
|
|
||||||
|
### `buildx`
|
||||||
|
|
||||||
|
Docker `buildx` est un plugin qui apporte
|
||||||
|
[BuildKit](https://github.com/moby/buildkit). Tout en étant compatible avec la
|
||||||
|
syntaxe des `Dockerfile` existant, BuildKit apporte une gestion concurrente des
|
||||||
|
nœuds de construction : très utile lorsque l'on construit une image pour
|
||||||
|
plusieurs architectures.
|
||||||
|
|
||||||
|
|
||||||
|
#### Installation Windows et MacOS {-}
|
||||||
|
|
||||||
|
Avec Docker Desktop, le plugin est déjà installé, vous n'avez aucune action
|
||||||
|
supplémentaire à effectuer, vous pouvez commencer à l'utiliser.
|
||||||
|
|
||||||
|
#### Installation Linux {-}
|
||||||
|
|
||||||
|
En fonction de la méthode d'installation que vous avez suivie, vous avez
|
||||||
|
peut-être déjà le plugin installé. Si vous n'avez pas d'erreur en exécutant
|
||||||
|
`docker buildx`, mais que vous voyez l'aide de la commande, c'est bon. Sinon,
|
||||||
|
vous pouvez l'installer comme ceci :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```
|
||||||
|
mkdir -p ~/.docker/cli-plugins
|
||||||
|
curl https://github.com/docker/buildx/releases/download/v0.6.3/buildx-v0.6.3.linux-amd64 \
|
||||||
|
-L -s -S -o ~/.docker/cli-plugins/docker-buildx
|
||||||
|
chmod +x ~/.docker/cli-plugins/docker-buildx
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
#### Utilisation\
|
||||||
|
|
||||||
|
Nous pouvons réutiliser le `Dockerfile` que vous avez écrit pour `youp0m`, en
|
||||||
|
remplaçant simplement la ligne de `docker build` par celle-ci :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```
|
||||||
|
docker buildx build .
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Nous ne rentrerons pas plus dans les détails de cette nouvelle commande, mais
|
||||||
|
sachez qu'on la retrouve particulièrement fréquemment dans les *GitHub
|
||||||
|
Actions* : <https://github.com/marketplace/actions/docker-setup-buildx>
|
||||||
|
|
||||||
|
|
||||||
|
#### Changer la syntaxe de nos `Dockerfile`\
|
||||||
|
|
||||||
|
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
|
||||||
|
à utiliser pour l'évaluation de la syntaxe du `Dockerfile`. Les parseurs
|
||||||
|
(*frontend* dans la documentation en anglais) sont des images Docker, on
|
||||||
|
indique leur nom dans un commentaire au tout début du fichier :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```dockerfile
|
||||||
|
# syntax=docker/dockerfile:1.2
|
||||||
|
FROM ubuntu
|
||||||
|
RUN apt-get update && apt-get install gimp
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
La possibilité d'avoir plusieurs implémentations de `Dockerfile` apporte pas mal
|
||||||
|
d'avantages :
|
||||||
|
|
||||||
|
- La version de l'image *frontend* est systématiquement comparée en ligne au
|
||||||
|
début du parsing du `Dockerfile`, ce qui assure la récupération des derniers
|
||||||
|
correctifs/versions, sans nécessiter une mise à jour du *daemon* Docker.
|
||||||
|
- On s'assure que chaque développeur/utilisateur utilise la même
|
||||||
|
implémentation, avec la même version.
|
||||||
|
- L'évolution de la syntaxe peut être plus souple car elle ne dépend plus de la
|
||||||
|
version de Docker installée, mais de la version déclarée dans le
|
||||||
|
`Dockerfile`.
|
||||||
|
- On peut même créer de nouvelles syntaxes facilement.
|
||||||
|
|
||||||
|
Les images de parseur sont chargées, à partir d'un fichier lisible et
|
||||||
|
compréhensible par un humain, de créer une représentation intermédiaire
|
||||||
|
(*LLB*). Cette représentation intermédiaire se compose d'une liste d'opérations
|
||||||
|
basiques (*ExecOp*, *CacheOp*, *SecretOp*, *SourceOp*, *CopyOp*, ...).
|
||||||
|
|
||||||
|
N'hésitez pas à jeter un œil aux autres langages de `Dockerfile` existants,
|
||||||
|
notamment :
|
||||||
|
|
||||||
|
- [Gockerfile](https://github.com/po3rin/gockerfile) : bien que dépassé faute
|
||||||
|
de mise à jour, cette implémentation est très simple à comprendre : elle a
|
||||||
|
pour but de créer une image contenant un unique binaire Go, à partir du nom
|
||||||
|
de son dépôt.
|
||||||
|
- [hlb](https://openllb.github.io/hlb/) : une syntaxe prometteuse, plus proche
|
||||||
|
pour les développeurs.
|
||||||
|
- [Earthly](https://earthly.dev/) : qui tend à regrouper `Makefile`,
|
||||||
|
`Dockerfile`, et autres scripts de CI et de tests.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Des images sans Docker
|
||||||
|
|
||||||
|
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
|
||||||
|
aussi capable de générer des images Docker. Citons notamment :
|
||||||
|
|
||||||
|
- [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.
|
||||||
|
|
||||||
|
|
||||||
|
### 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.
|
@ -9,7 +9,7 @@ Projet
|
|||||||
Avec l'aide d'un `Dockerfile` *multi-stage*, réalisez l'image la plus petite
|
Avec l'aide d'un `Dockerfile` *multi-stage*, réalisez l'image la plus petite
|
||||||
possible (partant d'un `FROM scratch`{.dockerfile}), qui permette d'utiliser la
|
possible (partant d'un `FROM scratch`{.dockerfile}), qui permette d'utiliser la
|
||||||
[page de compte à rebours](https://virli.nemunai.re/countdown.html) avec cette
|
[page de compte à rebours](https://virli.nemunai.re/countdown.html) avec cette
|
||||||
configuration pour nginx :
|
configuration pour nginx :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```conf
|
```conf
|
||||||
@ -35,7 +35,7 @@ http {
|
|||||||
Vous pouvez envisager dans un premier temps d'extraire de l'image `nginx`, le
|
Vous pouvez envisager dans un premier temps d'extraire de l'image `nginx`, le
|
||||||
binaire `nginx` lui-même et observer les différents problèmes. Vous pourrez
|
binaire `nginx` lui-même et observer les différents problèmes. Vous pourrez
|
||||||
ensuite par exemple envisager de compiler `nginx` (vous trouverez les sources
|
ensuite par exemple envisager de compiler `nginx` (vous trouverez les sources
|
||||||
du projet : <http://nginx.org/download>).
|
du projet : <http://nginx.org/download>).
|
||||||
|
|
||||||
Dans tous les cas, votre `Dockerfile` devra être facilement maintenable
|
Dans tous les cas, votre `Dockerfile` devra être facilement maintenable
|
||||||
(notamment en cas de nouvelle version du serveur web), et vous devrez apporter
|
(notamment en cas de nouvelle version du serveur web), et vous devrez apporter
|
||||||
@ -79,7 +79,7 @@ Tous les fichiers identifiés comme étant à rendre pour ce TP sont à
|
|||||||
placer dans une tarball (pas d'archive ZIP, RAR, ...).
|
placer dans une tarball (pas d'archive ZIP, RAR, ...).
|
||||||
|
|
||||||
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">
|
||||||
```
|
```
|
||||||
|
@ -13,7 +13,7 @@ abstract: |
|
|||||||
Tous les éléments de ce TP (exercices et projet) sont à rendre à
|
Tous les éléments de ce TP (exercices et projet) sont à rendre à
|
||||||
<virli@nemunai.re> au plus tard le mercredi 23 octobre 2019 à 13
|
<virli@nemunai.re> au plus tard le mercredi 23 octobre 2019 à 13
|
||||||
h 42. Consultez la dernière section de chaque partie pour plus
|
h 42. Consultez la dernière section de chaque partie pour plus
|
||||||
d'information sur les éléments à rendre.
|
d'informations sur les éléments à rendre.
|
||||||
|
|
||||||
En tant que personnes sensibilisées à la sécurité des échanges
|
En tant que personnes sensibilisées à la sécurité des échanges
|
||||||
électroniques, vous devrez m'envoyer vos rendus signés avec votre
|
électroniques, vous devrez m'envoyer vos rendus signés avec votre
|
||||||
|
12
tutorial/dockerfiles/what.md
Normal file
12
tutorial/dockerfiles/what.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
\newpage
|
||||||
|
|
||||||
|
Construire des images
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Jusqu'à maintenant, nous avons profité des images présentes sur les registres
|
||||||
|
pour utiliser Docker. Sur ces registres, on trouve d'ailleurs non seulement des
|
||||||
|
images officielles proposées directement par les éditeurs (`nginx`, `mysql`,
|
||||||
|
...), mais aussi des images conçues par les utilisateurs pour leurs propres
|
||||||
|
besoins.
|
||||||
|
|
||||||
|
Et si nous aussi, nous construisions nos propres images ? Ça vous dit ?
|
Loading…
Reference in New Issue
Block a user