235 lines
8.3 KiB
Markdown
235 lines
8.3 KiB
Markdown
\newpage
|
|
|
|
Retour sur les bonnes pratiques
|
|
===============================
|
|
|
|
Pour chaque bonne pratique ci-dessous, vérifiez que vous la respectez
|
|
bien, faites les modifications nécessaires dans votre `Dockerfile`.
|
|
|
|
## 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
|
|
conteneur (par exemple, vous pouvez avoir un `Dockerfile` placé à la racine
|
|
d'un dépôt git : il va avoir besoin des binaires compilés, mais pas des
|
|
sources).
|
|
|
|
Afin d'améliorer les performances lors de la construction, vous pouvez exclure
|
|
les fichiers et dossiers inutiles au conteneur en ajoutant un fichier
|
|
`.dockerignore` dans le répertoire de votre `Dockerfile`.
|
|
|
|
Ce fichier fonctionne de la même manière que le `.gitignore` : vous pouvez
|
|
utiliser du globing.
|
|
|
|
Pour plus d'informations, vous pouvez consulter la documentation accessible à
|
|
<https://docs.docker.com/reference/builder/#dockerignore-file>.
|
|
|
|
|
|
## 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
|
|
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 !
|
|
|
|
|
|
## 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
|
|
créées.
|
|
|
|
|
|
## Ordonnez vos lignes de commandes complexes
|
|
|
|
### Allez à la ligne pour séparer les longues lignes de commandes complexes
|
|
|
|
Aérez vos `Dockerfile` !
|
|
|
|
N'hésitez pas à commenter et séparer les blocs logiques ensemble, comme lorsque
|
|
vous codez.
|
|
|
|
Lorsqu'une ligne devient complexe, allez à la ligne :
|
|
|
|
<div lang="en-US">
|
|
```
|
|
RUN apt-get update && apt-get install -y \
|
|
nginx \
|
|
php5-fpm
|
|
```
|
|
</div>
|
|
|
|
Notez les backslashs à la fin des lignes, indiquant qu'elle n'est pas terminée.
|
|
|
|
### Triez les arguments par ordre alphabétique
|
|
|
|
Lorsque c'est possible, ordonnez vos lignes suivant un ordre logique. Par
|
|
exemple :
|
|
|
|
<div lang="en-US">
|
|
```
|
|
RUN apt-get update && apt-get install -y \
|
|
bzr \
|
|
cvs \
|
|
git \
|
|
mercurial \
|
|
subversion
|
|
```
|
|
</div>
|
|
|
|
|
|
## 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
|
|
trouver si une image n'est pas déjà disponible dans le cache (plutôt que de
|
|
créer une nouvelle image identique).
|
|
|
|
Il y a un certain nombre de règles à connaître pour bien utiliser ce mécanisme :
|
|
|
|
- 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
|
|
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.
|
|
- Pour les instructions `ADD` et `COPY`, 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é.
|
|
- Une fois que le cache est invalidé, toutes les commandes restantes à exécuter
|
|
dans le `Dockerfile` vont être exécutées.
|
|
|
|
|
|
## 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
|
|
reconfiguration. La configuration devrait se faire au lancement du conteneur ou
|
|
lors de sa construction.
|
|
|
|
|
|
## 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`.
|
|
|
|
|
|
## Exposez les ports standards
|
|
|
|
La commande `EXPOSE` vous permet d'indiquer les ports sur lesquels votre
|
|
conteneur s'attend à recevoir des paquets venant de l'extérieur. Ces ports ne
|
|
sont pas partagés avec l'hôte ou les autres conteneur, donc vous n'avez pas de
|
|
raison de ne pas utiliser les ports standards.
|
|
|
|
Si vous faites cela, il y a de forte chance qu'il n'y ait pas besoin de
|
|
modifier la configuration des autres logiciels contenu dans d'autres conteneurs
|
|
puis qu'ils sont généralement configurés pour se connecter aux ports standards.
|
|
|
|
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`
|
|
|
|
L'entrypoint peut être utilisé de deux manières différentes :
|
|
|
|
- Vous pouvez l'utiliser de telle sorte que la commande passée au `docker run`,
|
|
après le nom de l'image, corresponde aux arguments attendu par le programme
|
|
indiqué dans l'entrypoint. Par exemple pour nginx :
|
|
|
|
<div lang="en-US">
|
|
```
|
|
ENTRYPOINT ["nginx"]
|
|
CMD ["-g daemon off;"]
|
|
```
|
|
</div>
|
|
|
|
- Vous pouvez aussi utiliser un script qui servira à faire les initialisations
|
|
ou les configurations nécessaire au bon fonctionnement du conteneur
|
|
(rappelez-vous, il doit être éphémère !). Par exemple, le `Dockerfile` pour
|
|
l'image de PostgreSQL possède cet entrypoint :
|
|
|
|
<div lang="en-US">
|
|
```shell
|
|
#!/bin/bash
|
|
set -e
|
|
|
|
if [ "$1" = 'postgres' ]; then
|
|
chown -R postgres "$PGDATA"
|
|
|
|
if [ -z "$(ls -A "$PGDATA")" ]; then
|
|
gosu postgres initdb
|
|
fi
|
|
|
|
exec gosu postgres "$@"
|
|
fi
|
|
|
|
exec "$@"
|
|
```
|
|
</div>
|
|
|
|
|
|
## `[""]`, `'` et sans `[]`
|
|
|
|
Les instructions `ENTRYPOINT` et `CMD` peuvent prendre deux formes :
|
|
|
|
- `["cmd", "arg1", "arg2"]` : ici, un simple `exexve` sera effectué avec ces
|
|
arguments. Si d'éventuels variables se trouve dans les arguments, elles ne
|
|
seront pas remplacées.
|
|
- `cmd arg1 arg2` : ici l'exécution se fera au sein d'un `sh -c`, donc les
|
|
variables seront remplacés et étendues.
|
|
|
|
Les commandes sous forme de tableau étant parsées par un parser JSON, vous ne
|
|
pouvez pas utiliser les simple quotes.
|
|
|
|
|
|
## Volumes
|
|
|
|
L'instruction `VOLUME` doit être utilisée pour exposer tous les espaces de
|
|
stockage de données, configuration, ...
|
|
|
|
|
|
## Réduisez les privilèges
|
|
|
|
Utilisez l'instruction `USER` dès que vous le pouvez, lorsqu'un service ne
|
|
réclame pas de privilège particulier.
|
|
|
|
Il vous faudra sans doute créer l'utilisateur et son groupe dans le Dockerfile.
|
|
|
|
|
|
## 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
|
|
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`.
|
|
|
|
|
|
## 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
|
|
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.
|