2021-09-23 00:55:18 +00:00
|
|
|
|
Les bonnes pratiques
|
|
|
|
|
--------------------
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2016-09-15 02:27:59 +00:00
|
|
|
|
Pour chaque bonne pratique ci-dessous, vérifiez que vous la respectez
|
2022-05-12 00:46:31 +00:00
|
|
|
|
bien, faites les modifications nécessaires dans votre `Dockerfile`.
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2021-09-23 00:55:18 +00:00
|
|
|
|
### Utilisez le fichier `.dockerignore`
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2016-09-15 02:27:59 +00:00
|
|
|
|
Dans la plupart des cas, vos `Dockerfile` seront dans des dossiers contenant
|
2022-05-12 00:46:31 +00:00
|
|
|
|
beaucoup de fichiers qui ne sont pas nécessaires à la construction de votre
|
2015-10-29 04:45:40 +00:00
|
|
|
|
conteneur (par exemple, vous pouvez avoir un `Dockerfile` placé à la racine
|
2021-09-24 15:12:07 +00:00
|
|
|
|
d'un dépôt git).
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
Afin d'améliorer les performances lors de la construction, vous pouvez exclure
|
|
|
|
|
les fichiers et dossiers inutiles au conteneur en ajoutant un fichier
|
|
|
|
|
`.dockerignore` dans le répertoire de votre `Dockerfile`.
|
|
|
|
|
|
2021-09-24 15:12:07 +00:00
|
|
|
|
Vous pouvez exclure les produits intermédiaires de compilation (`*.o`, ...) si
|
|
|
|
|
vous utilisez un langage compilé, excluez également les produits de compilation
|
|
|
|
|
si votre image construit le binaire. Dans le cas de NodeJS, vous allez sans
|
|
|
|
|
doute vouloir exclure le dossier `node_modules` et faire un `npm install` dans
|
|
|
|
|
votre `Dockerfile`. Cela permettra au passage de s'assurer que toutes les
|
2022-05-12 00:46:31 +00:00
|
|
|
|
dépendances ont bien été enregistrées.
|
2021-09-24 15:12:07 +00:00
|
|
|
|
|
|
|
|
|
Ce fichier fonctionne de la même manière que le `.gitignore` : vous pouvez
|
2015-10-29 04:45:40 +00:00
|
|
|
|
utiliser du globing.
|
|
|
|
|
|
2022-02-24 19:43:43 +00:00
|
|
|
|
Pour plus d'informations, vous pouvez consulter la documentation accessible à\
|
|
|
|
|
<https://docs.docker.com/engine/reference/builder/#dockerignore-file>
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
|
2021-09-23 00:55:18 +00:00
|
|
|
|
### N'installez rien de superflu
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
Afin de réduire la quantité de dépendances à installer, n'installez pas de
|
2021-09-24 15:12:07 +00:00
|
|
|
|
paquets dont vous n'avez pas vraiment l'utilité : il n'y a pas de raison par
|
2015-10-29 04:45:40 +00:00
|
|
|
|
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.
|
|
|
|
|
|
2021-09-23 00:55:18 +00:00
|
|
|
|
En plus, cela réduira le temps de construction et la taille des images
|
2022-02-24 19:43:43 +00:00
|
|
|
|
produites !
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2021-09-23 00:55:18 +00:00
|
|
|
|
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.
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2021-09-23 00:55:18 +00:00
|
|
|
|
|
|
|
|
|
### Minimisez le nombre de couches
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
Vous devez trouver l'équilibre idéal entre la lisibilité de votre `Dockerfile`
|
2021-09-23 00:55:18 +00:00
|
|
|
|
(qui assure la maintenabilité sur le long terme) et le nombre de couches
|
2016-09-15 00:46:46 +00:00
|
|
|
|
créées.
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2021-09-23 00:55:18 +00:00
|
|
|
|
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.
|
|
|
|
|
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2021-09-23 00:55:18 +00:00
|
|
|
|
### Ordonnez vos lignes de commandes complexes
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2022-04-09 00:50:14 +00:00
|
|
|
|
#### Allez à la ligne pour séparer les longues lignes de commandes complexes
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2022-02-24 19:43:43 +00:00
|
|
|
|
Aérez vos `Dockerfile` !
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
N'hésitez pas à commenter et séparer les blocs logiques ensemble, comme lorsque
|
|
|
|
|
vous codez.
|
|
|
|
|
|
2021-09-24 15:12:07 +00:00
|
|
|
|
Lorsqu'une ligne devient complexe, allez à la ligne :
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2018-11-16 01:38:41 +00:00
|
|
|
|
```dockerfile
|
|
|
|
|
RUN apt-get update && apt-get install -y \
|
|
|
|
|
nginx \
|
|
|
|
|
php5-fpm
|
2015-10-29 04:45:40 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
Notez les backslashs à la fin des lignes, indiquant qu'elle n'est pas terminée.
|
|
|
|
|
|
2022-04-09 00:50:14 +00:00
|
|
|
|
#### Triez les arguments par ordre alphabétique
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
Lorsque c'est possible, ordonnez vos lignes suivant un ordre logique. Par
|
2021-09-24 15:12:07 +00:00
|
|
|
|
exemple :
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2018-11-16 01:38:41 +00:00
|
|
|
|
```dockerfile
|
|
|
|
|
RUN apt-get update && apt-get install -y \
|
|
|
|
|
bzr \
|
|
|
|
|
cvs \
|
|
|
|
|
git \
|
|
|
|
|
mercurial \
|
|
|
|
|
subversion
|
2015-10-29 04:45:40 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
|
2021-09-23 00:55:18 +00:00
|
|
|
|
### Profitez du système de cache
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
trouver si une image n'est pas déjà disponible dans le cache (plutôt que de
|
|
|
|
|
créer une nouvelle image identique).
|
|
|
|
|
|
2021-09-24 15:12:07 +00:00
|
|
|
|
Il y a un certain nombre de règles à connaître pour bien utiliser ce mécanisme :
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
- 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
|
2021-09-23 00:55:18 +00:00
|
|
|
|
trouvée pour l'instruction, le cache est invalidé pour le reste de cette
|
2015-10-29 04:45:40 +00:00
|
|
|
|
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
|
|
|
|
|
aucune commande correspondante n'est trouvé, le cache se retrouve invalidé
|
|
|
|
|
pour les instructions suivantes.
|
2018-11-16 01:38:41 +00:00
|
|
|
|
- Pour les instructions `ADD`{.dockerfile} et `COPY`{.dockerfile}, en plus de
|
|
|
|
|
la comparaison précédente, la somme de contrôle du fichier est ajoutée. Si le
|
|
|
|
|
fichier a été modifié, le cache se retrouve invalidé.
|
2015-10-29 04:45:40 +00:00
|
|
|
|
- Une fois que le cache est invalidé, toutes les commandes restantes à exécuter
|
|
|
|
|
dans le `Dockerfile` vont être exécutées.
|
|
|
|
|
|
|
|
|
|
|
2022-05-12 00:46:31 +00:00
|
|
|
|
### Concevez des conteneurs éphémères
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2021-09-24 15:12:07 +00:00
|
|
|
|
Les conteneurs que vous générez doivent être aussi éphémères que possible : ils
|
2016-09-14 20:51:14 +00:00
|
|
|
|
devraient pouvoir être arrêtés, détruits et recréés sans nécessiter d'étape de
|
2015-10-29 04:45:40 +00:00
|
|
|
|
reconfiguration. La configuration devrait se faire au lancement du conteneur ou
|
|
|
|
|
lors de sa construction.
|
|
|
|
|
|
|
|
|
|
|
2021-09-23 00:55:18 +00:00
|
|
|
|
### Cas d'`apt-get` et des gestionnaires de paquets
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
- 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.
|
|
|
|
|
- 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
|
2021-09-23 00:55:18 +00:00
|
|
|
|
`apt-get`. Lors d'un changement de version, vous changerez la ligne, le cache
|
|
|
|
|
ne sera donc pas utilisé.
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
|
2021-09-23 00:55:18 +00:00
|
|
|
|
### Exposez les ports standards
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2021-09-24 15:12:07 +00:00
|
|
|
|
La commande `EXPOSE`{.dockerfile} permet d'indiquer les ports sur lesquels
|
2018-11-16 01:38:41 +00:00
|
|
|
|
votre conteneur s'attend à recevoir des paquets venant de l'extérieur. Ces
|
2021-09-24 15:12:07 +00:00
|
|
|
|
ports ne sont pas partagés avec l'hôte ou les autres conteneurs, donc vous
|
2018-11-16 01:38:41 +00:00
|
|
|
|
n'avez pas de raison de ne pas utiliser les ports standards.
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
Si vous faites cela, il y a de forte chance qu'il n'y ait pas besoin de
|
|
|
|
|
modifier la configuration des autres logiciels contenu dans d'autres conteneurs
|
2021-09-24 15:12:07 +00:00
|
|
|
|
puisqu'ils sont généralement configurés pour se connecter aux ports standards.
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
S'il y a un conflit sur la machine hôte, il sera toujours temps de créer une
|
2022-05-12 00:46:31 +00:00
|
|
|
|
redirection à ce moment-là.
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
|
2021-09-23 00:55:18 +00:00
|
|
|
|
### La bonne utilisation de l'`ENTRYPOINT`
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2021-09-24 15:12:07 +00:00
|
|
|
|
L'*entrypoint* (on le verra plus en détail dans la partie suivante) peut être
|
|
|
|
|
utilisé de deux manières différentes :
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
- Vous pouvez l'utiliser de telle sorte que la commande passée au `docker run`,
|
|
|
|
|
après le nom de l'image, corresponde aux arguments attendu par le programme
|
2022-05-12 00:46:31 +00:00
|
|
|
|
indiqué dans l'*entrypoint*. Par exemple pour `nginx` :
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2018-11-16 01:38:41 +00:00
|
|
|
|
```dockerfile
|
|
|
|
|
ENTRYPOINT ["nginx"]
|
2020-09-14 13:46:13 +00:00
|
|
|
|
CMD ["-g", "daemon", "off;"]
|
2016-09-14 20:51:14 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
- Vous pouvez aussi utiliser un script qui servira à faire les initialisations
|
|
|
|
|
ou les configurations nécessaire au bon fonctionnement du conteneur
|
2022-02-24 19:43:43 +00:00
|
|
|
|
(rappelez-vous, il doit être éphémère !). Par exemple, le `Dockerfile` pour
|
2021-09-24 15:12:07 +00:00
|
|
|
|
l'image de PostgreSQL possède cet entrypoint :
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2018-11-16 01:38:41 +00:00
|
|
|
|
```bash
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
set -e
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2018-11-16 01:38:41 +00:00
|
|
|
|
if [ "$1" = 'postgres' ]; then
|
|
|
|
|
chown -R postgres "$PGDATA"
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2018-11-16 01:38:41 +00:00
|
|
|
|
if [ -z "$(ls -A "$PGDATA")" ]; then
|
|
|
|
|
gosu postgres initdb
|
|
|
|
|
fi
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2018-11-16 01:38:41 +00:00
|
|
|
|
exec gosu postgres "$@"
|
|
|
|
|
fi
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2018-11-16 01:38:41 +00:00
|
|
|
|
exec "$@"
|
2016-09-14 20:51:14 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
|
2021-09-23 00:55:18 +00:00
|
|
|
|
### `[""]`, `'` et sans `[]`
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2018-11-16 01:38:41 +00:00
|
|
|
|
Les instructions `ENTRYPOINT`{.dockerfile} et `CMD`{.dockerfile} peuvent
|
2021-09-24 15:12:07 +00:00
|
|
|
|
prendre deux formes :
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2021-09-24 15:12:07 +00:00
|
|
|
|
- `["cmd", "arg1", "arg2"]` : ici, un simple `execve` sera effectué avec ces
|
2015-10-29 04:45:40 +00:00
|
|
|
|
arguments. Si d'éventuels variables se trouve dans les arguments, elles ne
|
|
|
|
|
seront pas remplacées.
|
2021-09-24 15:12:07 +00:00
|
|
|
|
- `cmd arg1 arg2` : ici l'exécution se fera au sein d'un `sh -c`, donc les
|
2022-05-12 00:46:31 +00:00
|
|
|
|
variables seront remplacées et étendues.
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
Les commandes sous forme de tableau étant parsées par un parser JSON, vous ne
|
2021-09-24 15:12:07 +00:00
|
|
|
|
pouvez pas utiliser les *simples quotes*.
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
|
2021-09-23 00:55:18 +00:00
|
|
|
|
### Volumes
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2018-11-16 01:38:41 +00:00
|
|
|
|
L'instruction `VOLUME`{.dockerfile} doit être utilisée pour exposer tous les
|
2021-09-24 15:12:07 +00:00
|
|
|
|
espaces de stockage de données, configuration, ...
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
|
2021-09-23 00:55:18 +00:00
|
|
|
|
### Réduisez les privilèges
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2018-11-16 01:38:41 +00:00
|
|
|
|
Utilisez l'instruction `USER`{.dockerfile} dès que vous le pouvez, lorsqu'un
|
|
|
|
|
service ne réclame pas de privilège particulier.
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
2021-09-24 15:12:07 +00:00
|
|
|
|
Il vous faudra sans doute créer l'utilisateur et son groupe dans le `Dockerfile`.
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
|
2021-09-23 00:55:18 +00:00
|
|
|
|
### Profitez du système de liaison et de résolution de nom
|
2016-09-14 20:51:14 +00:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
domaine correspondant au nom du conteneur (ou son alias) sera recherché, l'IP
|
|
|
|
|
sera bien celle du conteneur. Lorsque vous configurez un conteneur, utilisez de
|
|
|
|
|
préférence un nom plutôt qu'une IP, qui changera à coup sûr.
|
|
|
|
|
|
|
|
|
|
Au moment du `docker run`, vous pouvez préciser d'autres noms d'ĥôtes
|
|
|
|
|
particuliers en utilisant l'option `--add-host`.
|
|
|
|
|
|
|
|
|
|
|
2021-09-23 00:55:18 +00:00
|
|
|
|
### Exécutez un seul processus par conteneur
|
2015-10-29 04:45:40 +00:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
un conteneur distinct qui n'effectue que le travail pour lequel il est
|
|
|
|
|
chargé. Les options de liaison entre conteneur sont à votre disposition pour
|
|
|
|
|
vous aider à cette tâche.
|
2022-09-20 04:02:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## De l'intérêt de faire des images minimales
|
|
|
|
|
|
|
|
|
|
À l'inverse de langages comme Javascript, Python, Java et bien
|
|
|
|
|
d'autres, le langage Go compile, comme le C, vers du code directement
|
|
|
|
|
exécutable par le processeur. Tandis que les langages interprétés ont
|
|
|
|
|
besoin de leur interpréteur et de leur environnement d'exécution, les
|
|
|
|
|
langages compilés n'ont pas besoin d'être distribués avec leur
|
|
|
|
|
compilateur.
|
|
|
|
|
|
|
|
|
|
Prenons le temps de regarder les tailles des images :
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```
|
|
|
|
|
42sh$ docker image ls -f reference=golang -f reference=youp0m
|
|
|
|
|
REPOSITORY TAG IMAGE ID CREATED SIZE
|
|
|
|
|
golang 1-alpine 155ead2e66ca 3 months ago 328MB
|
|
|
|
|
nemunaire/youp0m latest 2c06880e48aa 2 days ago 25MB
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
L'image contenant le compilateur Go est bien plus lourde que l'image
|
|
|
|
|
minimale que l'on a construite avec le binaire compilé. C'est autant
|
|
|
|
|
d'espace et de performances gagnées.
|