Update tuto2
This commit is contained in:
parent
5f097b4221
commit
2c5317f4f9
35 changed files with 3587 additions and 471 deletions
|
|
@ -1,12 +1,12 @@
|
|||
\newpage
|
||||
|
||||
Ma première image ... par `Dockerfile`
|
||||
======================================
|
||||
--------------------------------------
|
||||
|
||||
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
|
||||
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">
|
||||
```dockerfile
|
||||
|
|
@ -17,7 +17,7 @@ RUN apt-get install -y nano
|
|||
```
|
||||
</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
|
||||
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
|
||||
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">
|
||||
```bash
|
||||
|
|
@ -36,7 +36,7 @@ docker image build --tag=my_editor .
|
|||
</div>
|
||||
|
||||
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">
|
||||
```bash
|
||||
|
|
@ -46,13 +46,13 @@ docker container run -it my_editor /bin/bash
|
|||
</div>
|
||||
|
||||
|
||||
## `RUN` dans le `Dockerfile`
|
||||
### `RUN` dans le `Dockerfile`
|
||||
|
||||
Dans un `Dockerfile`, chaque ligne est exécutée indépendamment des autres et
|
||||
correspondra à une nouvelle couche de notre image. Exactement comme on a
|
||||
réalisé le script dans la partie précédente.
|
||||
|
||||
Cela signifie que l'exemple suivant **ne fonctionne pas** :
|
||||
Cela signifie que l'exemple suivant **ne fonctionne pas** :
|
||||
|
||||
<div lang="en-US">
|
||||
```dockerfile
|
||||
|
|
@ -63,11 +63,11 @@ RUN mysql -u root -p toor virli < /db.sql
|
|||
</div>
|
||||
|
||||
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
|
||||
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
|
||||
simple `apt install mysql` :
|
||||
simple `apt install mysql` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
@ -78,7 +78,7 @@ docker container run tinysql service mysqld start
|
|||
rend la main directement, sans laisser de `mysqld` dans l'arborescence de
|
||||
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">
|
||||
```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.
|
||||
|
||||
|
||||
## 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">
|
||||
```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
|
||||
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
|
||||
ports seront automatiquement exposés en utilisant l'option `-P` du `run` : cela
|
||||
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
|
||||
assigne une redirection de port aléatoire sur la machine hôte vers votre
|
||||
conteneur :
|
||||
conteneur :
|
||||
|
||||
<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/>.
|
||||
|
||||
**À 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
|
||||
d'inspiration, utilisez [cette page de compte à
|
||||
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
|
||||
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
|
||||
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
|
||||
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,
|
||||
sous forme de clef/valeur.
|
||||
|
||||
Une métadonnée
|
||||
[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">
|
||||
```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.
|
||||
|
||||
|
||||
## Commande par défaut
|
||||
### Commande par défaut
|
||||
|
||||
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">
|
||||
```dockerfile
|
||||
|
|
@ -218,7 +220,7 @@ retirez cette option pour voir ce qui ne va pas, ou utilisez la commande
|
|||
`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
|
||||
l'intégrer dans le conteneur ?
|
||||
|
|
@ -230,14 +232,14 @@ versions de ces outils existent, laquelle choisir ? ... Ok c'est trop
|
|||
compliqué.
|
||||
|
||||
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
|
||||
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
|
||||
plusieurs conteneurs, avant d'agréger le contenu compilé au sein du conteneur
|
||||
final :
|
||||
final :
|
||||
|
||||
<div lang="en-US">
|
||||
```dockerfile
|
||||
|
|
@ -252,7 +254,7 @@ CMD ["/hello"]
|
|||
```
|
||||
</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
|
||||
`hello.c`. Mais l'image finale (le dernier `FROM`{.dockerfile} de notre
|
||||
`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
|
||||
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
|
||||
`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
|
||||
numéros. Dans ce cas, on indiquera :
|
||||
numéros. Dans ce cas, on indiquera :
|
||||
|
||||
<div lang="en-US">
|
||||
```dockerfile
|
||||
|
|
@ -281,9 +283,9 @@ CMD ["/hello"]
|
|||
```
|
||||
</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
|
||||
spécifiquement on souhaite construire avec l'option `--target` :
|
||||
spécifiquement on souhaite construire avec l'option `--target` :
|
||||
|
||||
<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.
|
||||
|
||||
|
||||
## D'autres instructions ?
|
||||
### D'autres instructions ?
|
||||
|
||||
Consultez <https://docs.docker.com/engine/reference/builder/> pour la liste
|
||||
complète des instructions reconnues.
|
||||
|
||||
|
||||
## Exercice {-}
|
||||
### Exercice {-}
|
||||
|
||||
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
|
||||
|
|
@ -312,14 +314,14 @@ utilisé la semaine dernière.
|
|||
Pour réaliser ce genre de contribution, on ajoute généralement un `Dockerfile`
|
||||
à la racine du dépôt.
|
||||
|
||||
Vous pouvez cloner le dépôts de sources de `youp0m` à :
|
||||
<https://gitea.nemunai.re/nemunaire/youp0m.git>
|
||||
Vous pouvez cloner le dépôt de sources de `youp0m` à :
|
||||
<https://git.nemunai.re/nemunaire/youp0m.git>
|
||||
|
||||
Pour compiler le projet, vous pouvez utiliser dans votre `Dockerfile`
|
||||
|
||||
<div lang="en-US">
|
||||
```dockerfile
|
||||
FROM golang:1.13
|
||||
FROM golang:1.16
|
||||
COPY . /go/src/git.nemunai.re/youp0m
|
||||
WORKDIR /go/src/git.nemunai.re/youp0m
|
||||
RUN go build -tags dev -v
|
||||
|
|
|
|||
|
|
@ -1,31 +1,99 @@
|
|||
\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
|
||||
allons faire en sorte que notre image puisse être utilisée ainsi :
|
||||
- **`CMD`{.dockerfile}** est la commande par défaut : lorsqu'au moment de
|
||||
`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">
|
||||
```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>
|
||||
|
||||
|
||||
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">
|
||||
```bash
|
||||
docker run -d -p 80:80 youp0m /srv/youp0m -bind :80
|
||||
docker run -d -p 80:80 youp0m /srv/youp0m -bind :80
|
||||
```
|
||||
</div>
|
||||
|
||||
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.
|
||||
|
||||
Pour améliorer la situation, définissez
|
||||
|
|
@ -35,13 +103,13 @@ de votre image sur le binaire `/srv/youp0m`.
|
|||
|
||||
## 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
|
||||
opérationnel (rappelez-vous les options que l'on passait à l'image `mysql` pour
|
||||
créer un utilisateur et une base).
|
||||
|
||||
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">
|
||||
```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
|
||||
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">
|
||||
```bash
|
||||
|
|
@ -68,7 +136,7 @@ exec /srv/youp0m $@
|
|||
```
|
||||
</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
|
||||
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
|
||||
|
|
@ -78,8 +146,8 @@ l'utilisateur n'a rien précisé).
|
|||
|
||||
### Format du fichier `htpasswd`
|
||||
|
||||
Le format attendu est celui d'un fichier `htpasswd` typique d'Apache. Vous
|
||||
pourriez obtenir un fichier valide avec :
|
||||
Le format attendu est celui d'un fichier `htpasswd` typique d'Apache. Nous
|
||||
pouvons obtenir un fichier valide avec :
|
||||
|
||||
<div lang="en-US">
|
||||
```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 à
|
||||
passer au service.
|
||||
|
||||
Par exemple :
|
||||
Par exemple :
|
||||
|
||||
<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/
|
||||
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
|
||||
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.
|
||||
|
||||
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
|
||||
[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.
|
||||
* 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/).
|
||||
|
||||
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">
|
||||
```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
|
||||
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">
|
||||
```sql
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
\newpage
|
||||
|
||||
Retour sur les bonnes pratiques
|
||||
===============================
|
||||
Les bonnes pratiques
|
||||
--------------------
|
||||
|
||||
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
|
||||
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>.
|
||||
|
||||
|
||||
## N'installez rien de superflu
|
||||
### N'installez rien de superflu
|
||||
|
||||
Afin de réduire la quantité de dépendances à installer, n'installez pas de
|
||||
paquets dont vous n'avez pas vraiment l'utilité : il n'y a pas de raison par
|
||||
|
|
@ -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
|
||||
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`
|
||||
(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.
|
||||
|
||||
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` !
|
||||
|
||||
|
|
@ -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.
|
||||
|
||||
### Triez les arguments par ordre alphabétique
|
||||
#### Triez les arguments par ordre alphabétique
|
||||
|
||||
Lorsque c'est possible, ordonnez vos lignes suivant un ordre logique. Par
|
||||
exemple :
|
||||
|
|
@ -81,7 +92,7 @@ RUN apt-get update && apt-get install -y \
|
|||
</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
|
||||
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
|
||||
images`), l'instruction suivante est comparée avec toutes les autres images
|
||||
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.
|
||||
- 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
|
||||
|
|
@ -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.
|
||||
|
||||
|
||||
## 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
|
||||
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.
|
||||
|
||||
|
||||
## 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
|
||||
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 à
|
||||
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
|
||||
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
|
||||
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à.
|
||||
|
||||
|
||||
## La bonne utilisation de l'`ENTRYPOINT`
|
||||
### La bonne utilisation de l'`ENTRYPOINT`
|
||||
|
||||
L'entrypoint peut être utilisé de deux manières différentes :
|
||||
|
||||
|
|
@ -185,7 +192,7 @@ exec "$@"
|
|||
</div>
|
||||
|
||||
|
||||
## `[""]`, `'` et sans `[]`
|
||||
### `[""]`, `'` et sans `[]`
|
||||
|
||||
Les instructions `ENTRYPOINT`{.dockerfile} et `CMD`{.dockerfile} peuvent
|
||||
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.
|
||||
|
||||
|
||||
## Volumes
|
||||
### Volumes
|
||||
|
||||
L'instruction `VOLUME`{.dockerfile} doit être utilisée pour exposer tous les
|
||||
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
|
||||
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.
|
||||
|
||||
|
||||
## 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
|
||||
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`.
|
||||
|
||||
|
||||
## 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
|
||||
processus par conteneur. Il est préférable de répartir chaque application dans
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
\newpage
|
||||
|
||||
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">
|
||||
```bash
|
||||
|
|
@ -12,11 +10,11 @@ docker container run -it ubuntu /bin/bash
|
|||
</div>
|
||||
|
||||
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,
|
||||
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">
|
||||
```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,
|
||||
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/>
|
||||
|
||||
Si vous souhaitez disposez d'une nouvelle version de l'image, il est
|
||||
plutôt recommandé de contacter le mainteneur de l'image pour qu'il la
|
||||
mette à jour, en utilisant un nouveau tag s'il le juge nécessaire.
|
||||
|
||||
Installons maintenant un programme :
|
||||
Installons maintenant un programme :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
@ -50,7 +48,7 @@ Lorsque l'installation de `nano` est terminée, quittons l'image en tapant
|
|||
`exit`.
|
||||
|
||||
Sauvegardons nos modifications en tant que nouvelle image Docker, avec
|
||||
la commande `commit` :
|
||||
la commande `commit` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
@ -69,7 +67,7 @@ dernière couche de notre nouvelle image.
|
|||
|
||||

|
||||
|
||||
Testons alors sans plus attendre notre nouvelle image :
|
||||
Testons alors sans plus attendre notre nouvelle image :
|
||||
|
||||
<div lang="en-US">
|
||||
```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` !
|
||||
|
||||
|
||||
## 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">
|
||||
```bash
|
||||
|
|
@ -94,7 +92,7 @@ docker container commit $(docker container ls -lq) my_nano
|
|||
```
|
||||
</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">
|
||||
```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
|
||||
possible (partant d'un `FROM scratch`{.dockerfile}), qui permette d'utiliser la
|
||||
[page de compte à rebours](https://virli.nemunai.re/countdown.html) avec cette
|
||||
configuration pour nginx :
|
||||
configuration pour nginx :
|
||||
|
||||
<div lang="en-US">
|
||||
```conf
|
||||
|
|
@ -35,7 +35,7 @@ http {
|
|||
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
|
||||
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
|
||||
(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, ...).
|
||||
|
||||
Voici une arborescence type (vous pourriez avoir des fichiers
|
||||
supplémentaires) :
|
||||
supplémentaires) :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ abstract: |
|
|||
Tous les éléments de ce TP (exercices et projet) sont à rendre à
|
||||
<virli@nemunai.re> au plus tard le mercredi 23 octobre 2019 à 13
|
||||
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
|
||||
é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…
Add table
Add a link
Reference in a new issue