Optimisation des images Docker: 6 Stratégies clés pour des images plus légeres et plus performantes
Tags: docker, devops, cloud, performance
Published: 2024-04-04 23:02:29

Dans l'univers de la conteneurisation, depuis de nombreuses années, Docker s'est imposé comme **_le standard_** pour la construction d'images destinées au déploiements automatisés. Cependant, à mesure que les applications développées deviennent plus complexes, leur taille augmente également, ce qui entraine 
- une durée de construction prolongée, 
- des coûts de stockage plus élevés
- des déploiements plus lents. 

Afin de remédier à ces problèmes, les développeurs ou les ingénieurs chargés du déploiement doivent _**maîtriser l'art d'optimiser les images Docker**_. Dans cet article, nous explorerons 6 stratégies clés pour créer des images Docker plus légères et plus performantes.

## 1. Choisissez une image de base minimale

Le principe fondamental de l'optimisation des images Docker réside dans le fait de <u>sélectionner une image de base légère</u>. En commençant par une base minimale, telle qu'[Alpine Linux](https://hub.docker.com/_/alpine) par exemple, vous pouvez réduire considérablement la taille de vos images Docker. Ces images de base légères ne contiennent que les composants essentiels nécessaires pour exécuter des applications, purgeant ainsi toute surcharge inutile.

![Image décrivant la légèreté d'alpine linux. Elle pèse 5 mb ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fye6os9bg81wyc81vb1w.png)
> Rendez vous compte, il s'agit d'une image de 5 mb 😲


## 2. Réduisez les couches

Les images Docker sont construites à l'aide d'un système de fichiers en couches, chaque instruction dans le Dockerfile créant une nouvelle couche. Pour optimiser la taille de l'image, vous devriez réduire le nombre de couches en combinant les commandes connexes à l'aide de l'opérateur ` && `. De plus, nettoyer les fichiers et dépendances inutiles dans la même instruction ` RUN ` aidera à rationaliser le processus de construction de l'image.

```dockerfile
RUN apt-get update \
    && apt-get install -y curl \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*
```
> Dans cet extrait de Dockerfile, nous utilisons une seule commande ` RUN ` pour mettre à jour les paquets, installer Curl, nettoyer le cache Apt, et supprimer les listes de paquets téléchargées.

### Bonus

[Dive](https://github.com/wagoodman/dive) est un outil open source qui permet d’explorer les différentes couches d’une image Docker. Il vous montre le contenu de chaque couche et vous aide à identifier les parties volumineuses ou inutiles.

## 3. Utilisez des constructions multi-étapes

Ce processus consiste à diviser la construction d'une image Docker en [plusieurs étapes distinctes](https://docs.docker.com/build/building/multi-stage/). Chaque étape crée une couche d'image, mais <u>seules les couches finales sont incluses dans l'image finale</u>. Cela permet de séparer les dépendances de construction (comme les compilateurs, les outils de génération, etc.) des dépendances d'exécution (comme les bibliothèques, les fichiers binaires, etc.). En procédant de la sorte, on peut bénéficier d'une:
   - **Réduction de la taille de l'image :** En supprimant les artefacts de construction inutiles, l'image finale est plus légère.
   - **Amélioration des performances :** Moins de couches signifient un démarrage plus rapide, une utilisation plus efficace et responsable des ressources.

**Exemple: Web app Node.js avec npm**

   ```dockerfile
   # Étape 1: Construction
   FROM node:14 AS build
   WORKDIR /app
   COPY package*.json .
   RUN npm install
   COPY . .
   RUN npm run build

   # Étape 2: Image finale
   FROM nginx:alpine
   COPY --from=build /app/dist /usr/share/nginx/html
   EXPOSE 80
   CMD ["nginx", "-g", "daemon off;"]
   ```
   > Dans cet exemple, nous construisons d'abord l'application Node.js, puis nous copions les fichiers construits dans une image Nginx plus légère.

Cette approche permet non seulement de réduire la taille de l'image, mais aussi d'améliorer drastiquement les performances de votre pipeline CI/CD.

## 4. Copiez uniquement les fichiers indispensables: dockerignore

Lors de l'ajout de fichiers à l'image Docker, il est essentiel d'<u>inclure uniquement ce qui est nécessaire pour que l'application fonctionne</u>. Cela peut sembler bête, mais il est important de le dire. Pour cela utilisez le fichier ` .dockerignore `.
Le ` .dockerignore ` permet d'exclure des fichiers et répertoires inutiles de la création d'images Docker. En définissant des règles explicites pour ce qu'il faut exclure, on peut ainsi réduire la taille du contexte et accélérer le processus de construction. Cette technique simple mais efficace permet de rationaliser la création et la gestion des images Docker. Evitez donc de copier des fichiers, répertoires ou artefacts de construction inutiles qui ne sont pas nécessaires à l'exécution de l'app. **En minimisant le contenu superflu, on économise de l'espace** et notre application est moins vulnérable car moins de code = moins de failles de sécurités.

> Par exemple, parmi les dossiers d'un projet nodeJS qui n'ont pas leur place dans une image docker, on a:
      `node_modules ` `.npm` `npm-cache` `logs` `tmp`
La liste ci-dessus n'est pas exhaustive, la seule question qu'il faut se poser durant cette étape c'est <u>**Ce fichier(ou ce dossier) est il réellement indispensable pour mon application ?**</u>

## 5. Minimisez la perturbation du cache

La perturbation du cache peut avoir un impact significatif sur les temps de construction des images Docker et leur efficacité. Pour optimiser la mise en cache, les développeurs devraient placer les instructions qui changent fréquemment vers la fin du Dockerfile, en veillant à ce que les couches mises en cache soient réutilisées autant que possible. Cette approche réduit les temps de construction et améliore la productivité globale.

## 6. Inspectez la taille de l'image

Surveiller régulièrement les tailles des images Docker est essentiel pour identifier les domaines à optimiser et suivre les améliorations au fil du temps. Les développeurs devraient utiliser des commandes Docker telles que [`docker image ls`](https://docs.docker.com/reference/cli/docker/image/ls/) et [`docker inspect`](https://docs.docker.com/reference/cli/docker/inspect/) pour inspecter les tailles des images et analyser leur composition. En restant vigilant et proactif, les développeurs peuvent continuellement optimiser les images Docker pour une efficacité maximale.


L'optimisation des images Docker est un aspect crucial du développement d'applications modernes, permettant aux développeurs de créer des conteneurs légers, performants et sécurisés. En suivant des stratégies clés telles que le choix d'images de base minimales, la réduction des couches et l'utilisation de constructions multi-étapes, les développeurs peuvent améliorer considérablement les temps de construction, réduire les coûts de stockage et rationaliser les processus de déploiement.  **_Il est important de se rappeler que l'optimisation est un processus en continu_**; il convient donc de réexaminer régulièrement vos images Docker pour identifier toute nouvelle possibilité d'optimisation à mesure que votre application se développe.