⚠️ Traduction non officielle - Cette documentation est une traduction communautaire non officielle de Docker.

Meilleures pratiques de construction d'images

Stratification d'images

En utilisant la commande docker image history, vous pouvez voir la commande qui a été utilisée pour créer chaque couche dans une image.

  1. Utilisez la commande docker image history pour voir les couches dans l'image getting-started que vous avez créée.

    $ docker image history getting-started
    

    Vous devriez obtenir une sortie qui ressemble à quelque chose comme ce qui suit.

    IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
    a78a40cbf866        18 seconds ago      /bin/sh -c #(nop)  CMD ["node" "src/index.j…    0B                  
    f1d1808565d6        19 seconds ago      /bin/sh -c yarn install --production            85.4MB              
    a2c054d14948        36 seconds ago      /bin/sh -c #(nop) COPY dir:5dc710ad87c789593…   198kB               
    9577ae713121        37 seconds ago      /bin/sh -c #(nop) WORKDIR /app                  0B                  
    b95baba1cfdb        13 days ago         /bin/sh -c #(nop)  CMD ["node"]                 0B                  
    <missing>           13 days ago         /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B                  
    <missing>           13 days ago         /bin/sh -c #(nop) COPY file:238737301d473041…   116B                
    <missing>           13 days ago         /bin/sh -c apk add --no-cache --virtual .bui…   5.35MB              
    <missing>           13 days ago         /bin/sh -c #(nop)  ENV YARN_VERSION=1.21.1      0B                  
    <missing>           13 days ago         /bin/sh -c addgroup -g 1000 node     && addu…   74.3MB              
    <missing>           13 days ago         /bin/sh -c #(nop)  ENV NODE_VERSION=12.14.1     0B                  
    <missing>           13 days ago         /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B                  
    <missing>           13 days ago         /bin/sh -c #(nop) ADD file:e69d441d729412d24…   5.59MB   

    Chacune des lignes représente une couche dans l'image. L'affichage ici montre la base en bas avec la couche la plus récente en haut. En utilisant ceci, vous pouvez aussi rapidement voir la taille de chaque couche, aidant à diagnostiquer les grandes images.

  2. Vous remarquerez que plusieurs des lignes sont tronquées. Si vous ajoutez le flag --no-trunc, vous obtiendrez la sortie complète.

    $ docker image history --no-trunc getting-started
    

Mise en cache des couches

Maintenant que vous avez vu la stratification en action, il y a une leçon importante à apprendre pour aider à diminuer les temps de construction pour vos images de conteneur. Une fois qu'une couche change, toutes les couches en aval doivent être recréées aussi.

Regardez le Dockerfile suivant que vous avez créé pour l'application getting started.

# syntax=docker/dockerfile:1
FROM node:lts-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]

En revenant à la sortie de l'historique d'image, vous voyez que chaque commande dans le Dockerfile devient une nouvelle couche dans l'image. Vous pourriez vous rappeler que quand vous avez fait un changement à l'image, les dépendances yarn ont dû être réinstallées. Cela n'a pas beaucoup de sens d'expédier les mêmes dépendances à chaque fois que vous construisez.

Pour le corriger, vous devez restructurer votre Dockerfile pour aider à supporter la mise en cache des dépendances. Pour les applications basées sur Node, ces dépendances sont définies dans le fichier package.json. Vous pouvez copier seulement ce fichier en premier, installer les dépendances, puis copier tout le reste. Alors, vous ne recréez les dépendances yarn que s'il y a eu un changement au package.json.

  1. Mettez à jour le Dockerfile pour copier le package.json en premier, installer les dépendances, puis copier tout le reste.

    # syntax=docker/dockerfile:1
    FROM node:lts-alpine
    WORKDIR /app
    COPY package.json yarn.lock ./
    RUN yarn install --production
    COPY . .
    CMD ["node", "src/index.js"]
  2. Construisez une nouvelle image en utilisant docker build.

    $ docker build -t getting-started .
    

    Vous devriez voir une sortie comme la suivante.

    [+] Building 16.1s (10/10) FINISHED
    => [internal] load build definition from Dockerfile
    => => transferring dockerfile: 175B
    => [internal] load .dockerignore
    => => transferring context: 2B
    => [internal] load metadata for docker.io/library/node:lts-alpine
    => [internal] load build context
    => => transferring context: 53.37MB
    => [1/5] FROM docker.io/library/node:lts-alpine
    => CACHED [2/5] WORKDIR /app
    => [3/5] COPY package.json yarn.lock ./
    => [4/5] RUN yarn install --production
    => [5/5] COPY . .
    => exporting to image
    => => exporting layers
    => => writing image     sha256:d6f819013566c54c50124ed94d5e66c452325327217f4f04399b45f94e37d25
    => => naming to docker.io/library/getting-started
  3. Maintenant, faites un changement au fichier src/static/index.html. Par exemple, changez le <title> pour "The Awesome Todo App".

  4. Construisez l'image Docker maintenant en utilisant docker build -t getting-started . encore. Cette fois, votre sortie devrait avoir l'air un peu différente.

    [+] Building 1.2s (10/10) FINISHED
    => [internal] load build definition from Dockerfile
    => => transferring dockerfile: 37B
    => [internal] load .dockerignore
    => => transferring context: 2B
    => [internal] load metadata for docker.io/library/node:lts-alpine
    => [internal] load build context
    => => transferring context: 450.43kB
    => [1/5] FROM docker.io/library/node:lts-alpine
    => CACHED [2/5] WORKDIR /app
    => CACHED [3/5] COPY package.json yarn.lock ./
    => CACHED [4/5] RUN yarn install --production
    => [5/5] COPY . .
    => exporting to image
    => => exporting layers
    => => writing image     sha256:91790c87bcb096a83c2bd4eb512bc8b134c757cda0bdee4038187f98148e2eda
    => => naming to docker.io/library/getting-started

    D'abord, vous devriez remarquer que la construction était beaucoup plus rapide. Et, vous verrez que plusieurs étapes utilisent des couches précédemment mises en cache. Pousser et tirer cette image et ses mises à jour sera beaucoup plus rapide aussi.

Constructions multi-étapes

Les constructions multi-étapes sont un outil incroyablement puissant pour aider à utiliser plusieurs étapes pour créer une image. Il y a plusieurs avantages pour elles :

  • Séparer les dépendances de temps de construction des dépendances d'exécution
  • Réduire la taille globale de l'image en expédiant seulement ce dont votre application a besoin pour s'exécuter

Exemple Maven/Tomcat

Lors de la construction d'applications basées sur Java, vous avez besoin d'un JDK pour compiler le code source en bytecode Java. Cependant, ce JDK n'est pas nécessaire en production. Aussi, vous pourriez utiliser des outils comme Maven ou Gradle pour aider à construire l'application. Ceux-ci ne sont pas non plus nécessaires dans votre image finale. Les constructions multi-étapes aident.

# syntax=docker/dockerfile:1
FROM maven AS build
WORKDIR /app
COPY . .
RUN mvn package

FROM tomcat
COPY --from=build /app/target/file.war /usr/local/tomcat/webapps 

Dans cet exemple, vous utilisez une étape (appelée build) pour effectuer la construction Java réelle en utilisant Maven. Dans la deuxième étape (commençant à FROM tomcat), vous copiez les fichiers depuis l'étape build. L'image finale est seulement la dernière étape créée, qui peut être remplacée en utilisant le flag --target.

Exemple React

Lors de la construction d'applications React, vous avez besoin d'un environnement Node pour compiler le code JS (typiquement JSX), les feuilles de style SASS, et plus en HTML statique, JS, et CSS. Si vous ne faites pas de rendu côté serveur, vous n'avez même pas besoin d'un environnement Node pour votre construction de production. Vous pouvez expédier les ressources statiques dans un conteneur nginx statique.

# syntax=docker/dockerfile:1
FROM node:lts AS build
WORKDIR /app
COPY package* yarn.lock ./
RUN yarn install
COPY public ./public
COPY src ./src
RUN yarn run build

FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html

Dans l'exemple de Dockerfile précédent, il utilise l'image node:lts pour effectuer la construction (maximisant la mise en cache des couches) puis copie la sortie dans un conteneur nginx.

Résumé

Dans cette section, vous avez appris quelques meilleures pratiques de construction d'images, incluant la mise en cache des couches et les constructions multi-étapes.

Informations connexes :

Étapes suivantes

Dans la section suivante, vous apprendrez les ressources supplémentaires que vous pouvez utiliser pour continuer à apprendre sur les conteneurs.