Comment créer à chaque fois la plus petite image docker qui fonctionne?


19

Objectif: créer à chaque fois les plus petites images de docker qui fonctionnent

Courant

REPOSITORY          TAG       IMAGE ID            CREATED             SIZE
a-docker-image      latest    x                   42 minutes ago       1.92 GB

Tentative

Ajout d'une étape de nettoyage à la fin du Dockerfile:

#clean
RUN apt-get purge -y wget
RUN rm -r a-build-dir
RUN apt-get purge -y a-package

réduit un peu la taille de l'image:

REPOSITORY          TAG       IMAGE ID            CREATED             SIZE
a-docker-image      latest    y                   2 minutes ago       1.86 GB

Discussion

J'ai construit différentes images de docker. Chaque fois que j'essaie de diminuer la taille de l'image créée, mais je pense toujours qu'elle est trop grande. Je cherche un script qui a déjà été créé par quelqu'un sur github qui supprime tous les paquets superflus de l'image afin que la taille de l'image créée soit aussi petite que possible.

Comme je l'ai dit, j'essaie toujours de réduire la taille de l'image, mais je veux appliquer cette cohérence afin que chaque image que je crée à partir de maintenant soit aussi petite que possible.

Question

Comment créer à chaque fois la plus petite image docker qui fonctionne?

Réponses:


1

Il existe une variété de techniques impliquées, sans solution unique. Vous souhaiterez probablement effectuer plusieurs des opérations suivantes:


Tout d'abord, optimisez vos calques d'images pour les réutiliser. Mettez les étapes fréquemment modifiées plus tard dans le Dockerfile pour augmenter les chances que les premières couches soient mises en cache à partir des versions précédentes. Une couche réutilisée apparaîtra comme plus d'espace disque dans un docker image ls, mais si vous examinez le système de fichiers sous-jacent, une seule copie de chaque couche est jamais stockée sur le disque. Cela signifie que 3 images de 2 Go chacune, mais qui n'ont que 50 Mo différents dans les dernières couches de la construction, ne prendront que 2,1 Go d'espace disque, même si la liste donne à penser qu'elles utilisent 6 Go puisque vous êtes double comptage de chacune des couches réutilisées.

La réutilisation des couches est la raison pour laquelle vous voyez des images avec des dépendances de construction qui changent rarement, installez-les d'abord avant de les copier dans le code. Voir tout exemple de python qui a un modèle comme:

FROM python
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
# note how the code is copied only after the pip install
# since code changes but requirements.txt doesn't
COPY . .
CMD ["gunicorn", "app:app"]

Choisissez une image de base minimale. Voilà pourquoi vous voyez des gens vont de ubuntula debian:slim(les variantes minces sont plus petites, avec moins d' outils d' expédition), ou même alpine. Cela réduit la taille de votre point de départ et est très utile si vous extrayez constamment de nouvelles versions de l'image de base. Cependant, si votre image de base change rarement, la réutilisation des calques supprime une grande partie de l'avantage d'une image de base minimale.

La plus petite image de base que vous pouvez choisir est scratch, qui n'est rien, pas de shell ou de bibliothèques, et n'est utile qu'avec les binaires compilés statiquement. Sinon, choisissez une image de base qui comprend les outils dont vous avez besoin sans beaucoup d'outils dont vous n'avez pas besoin.


Ensuite, toute étape qui modifie ou supprime un fichier doit être combinée avec les étapes précédentes qui créent ce fichier. Sinon, le système de fichiers en couches, qui utilise la copie sur écriture même sur des choses comme un changement d'autorisation de fichier, aura le fichier d'origine dans un calque précédent et la taille de l'image ne diminuera pas lorsque vous supprimez des fichiers. C'est pourquoi vos rmcommandes n'ont aucun effet sur l'espace disque résultant. Au lieu de cela, vous pouvez enchaîner les commandes, comme:

RUN apt-get update \
 && apt-get install -y \
      a-package \
      wget \
 && ... \
 && apt-get purge -y wget \
 && rm -r a-build-dir \
 && apt-get purge -y a-package

Notez que la surutilisation du chaînage de commandes peut ralentir vos builds car vous devez réinstaller le même ensemble d'outils à chaque fois qu'une condition préalable change (par exemple, le code extrait avec wget). Voir plusieurs étapes ci-dessous pour une meilleure alternative.


Tout fichier que vous créez dont vous n'avez pas besoin dans votre image résultante doit être supprimé, à l'étape qui le crée. Cela inclut les caches de packages, les journaux, les pages de manuel, etc. Pour découvrir quels fichiers sont créés dans chaque couche, vous pouvez utiliser un outil comme wagoodman / dive (que je n'ai pas personnellement vérifié et je ferais preuve de prudence car il s'exécute avec un accès root complet sur votre hôte), ou vous pouvez créer vos images de docker sans élaguer les conteneurs intermédiaires, puis afficher la différence avec:

# first create and leave containers from any RUN step using options on build
docker image build --rm=false --no-cache -t image_name . 
# review which layers use an unexpectedly large amount of space
docker image history image_name
# list all containers, particularly the exited ones from above
docker container ps -a 
# examine any of those containers
docker container diff ${container_id} 
# ... repeat the diff for other build steps
# then cleanup exited containers
docker container prune

Avec chacun de ces conteneurs intermédiaires, la diff montrera quels fichiers sont ajoutés, modifiés ou supprimés dans cette étape (ceux - ci sont indiqués par un A, Cou Davant chaque nom de fichier). Ce qui diffère est le système de fichiers en lecture / écriture spécifique au conteneur, qui est tout fichier modifié par le conteneur à partir de l'état de l'image à l'aide de la copie sur écriture.


La meilleure façon de réduire la taille de l'image est d'éliminer tous les composants inutiles, comme les compilateurs, de votre image expédiée. Pour cela, les générations en plusieurs étapes vous permettent de compiler en une seule étape, puis de copier uniquement les artefacts résultants de l'étape de génération vers une image d'exécution qui n'a que le minimum nécessaire pour exécuter l'application. Cela évite d'avoir à optimiser l'une des étapes de génération car elles ne sont pas fournies avec l'image résultante.

FROM debian:9 as build
# still chain update with install to prevent stale cache issues
RUN apt-get update \
 && apt-get install -y \
      a-package \
      wget \
RUN ... # perform any download/compile steps

FROM debian:9-slim as release
COPY --from=build /usr/local/bin/app /usr/local/bin/app
CMD [ "/usr/local/bin/app" ]

Multi-stage est idéal avec des binaires compilés statiquement que vous pouvez exécuter avec scratch comme image de base, ou passer d'un environnement de compilation comme JDK à un environnement d'exécution comme JRE. C'est le moyen le plus simple de réduire considérablement la taille de votre image tout en ayant des constructions rapides. Vous pouvez toujours effectuer le chaînage des étapes de votre étape de publication si vous avez des étapes qui modifient ou suppriment des fichiers créés dans les étapes précédentes, mais pour la plupart, le à COPYpartir d'une autre étape isole l'étape de publication de tout ballonnement de couche rencontré dans les étapes de génération précédentes.


Remarque, je ne recommande pas d'écraser les images car cela réduit la taille d'une image au détriment de la réutilisation des calques. Cela signifie que les futures versions de la même image nécessiteront plus de trafic disque et réseau pour envoyer les mises à jour. Pour revenir au premier exemple, l'écrasement peut réduire votre image de 2 Go à 1 Go, mais pas 3 images peuvent prendre 3 Go au lieu des 2,1 Go.


25

A Dockerfilecrée un nouveau calque pour chacune des commandes du fichier. Étant donné que les calques sont bien, superposés les uns sur les autres - vous ne pouvez pas supprimer les fichiers ajoutés par un calque précédent. C'est pourquoi lorsque vous installez des packages, téléchargez des fichiers ou créez des builds chacun dans une commande distincte - ceux-ci sont toujours là dans l'image, même si dans une future couche vous les avez supprimés.

Donc, si vous changez juste ceci:

RUN apt-get update -y
RUN apt-get install -y wget a-package
# ...
RUN apt-get purge -y wget
RUN rm -r a-build-dir
RUN apt-get purge -y a-package

Pour ça:

RUN apt-get update -y \
    && apt-get install -y wget a-package \
    && mkdir a-build-dir \
    && wget http://some-site/very-big-source-code.tar.gz \
    && tar xzvf very-big-source-code.tar.gz \
    && do-some-compilation \
    && apt-get purge -y wget \
    && cd .. \
    && rm -rf a-build-dir \
    && apt-get purge -y a-package

Vous obtiendrez une image beaucoup plus petite.


Une autre option consiste à écraser l'image après l'avoir construite. Q: Comment fonctionne le nouveau docker --squash?


Encore une autre option, est de choisir une image de base mince. Par exemple, les images qui utilisent Alpine Linux comme base au lieu de Debian, prennent seulement 10-15 Mo au lieu de 180-250 Mo. Et ceci avant d'ajouter votre propre application et vos données. De nombreuses images de base officielles sur Docker Hub ont une version alpine.


3
2.37contre1.47 GB
030

4

Probablement pas exactement une réponse, mais cela vaut la peine de donner les alternatives.

L' habitat du chef a été créé dans cet esprit, créant un package avec toutes les dépendances nécessaires sans la charge d'image distro / base que vous ne souhaitez pas.

Extraits sur ce qui compte ici, la taille du conteneur de ce billet de blog avec une simple application nodejs:

michael@ricardo-2:plans_pkg_part_2$ docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
mfdii/node-example   latest              36c6568c606b        40 minutes ago      655.9 MB
node                 latest              04c0ca2a8dad        16 hours ago        654.6 MB
mfdii/mytutorialapp  latest              534afd80d74d        2 minutes ago       182.1 MB

mdfii/node-exampleest une image docker d'un fichier docker classique tandis que mfdii/mytutorialappl'image docker est produite avec l'habitat.

Si la taille est votre principale préoccupation et que vous êtes prêt à suivre la courbe d'apprentissage des plans Habitat, cela pourrait être une solution pour vous.


0

On pourrait aussi utiliser la plongée

docker run --rm -it \
    -v /var/run/docker.sock:/var/run/docker.sock \
    wagoodman/dive:latest <dive arguments...>

pour obtenir un rapport sur les déchets qui pourraient être supprimés d'une image Docker afin de réduire la taille.


0

Si vous souhaitez disposer de couches de développement réutilisables tout en réduisant l'utilisation de votre disque pour la livraison, vous pouvez produire une "couche de livraison" fusionnée comme ceci:

  1. Assurez-vous d'avoir un conteneur qui utilise votre image (si vous n'en avez pas, utilisez peut-être quelque chose comme docker run IMAGE echo, si la commande echo est disponible)
  2. Trouver l'ID du conteneur (peut-être en utilisant docker container ls -l)
  3. Tuyau docker exportpour docker importcréer le calque fusionné (quelque chose comme docker export 20f192c6530a | docker import - project:merged)

Cela gardera vos couches de développement, mais vous donnera une image fusionnée plus petite que vous pouvez fournir.



0

simple .. docker ps vérifier les images en cours d'exécution..pour un exemple de fichier simple ci-dessous ..

DE ubuntu16

MAINTAINER sreeni (email / domaine)

RUN apt-get update

RUN apt-get install -y nginx

ENTRYPOINT ["/ usr / sbin / nginx", "- g", "daemon off;"]

EXPOSE 80 (port)

fichier docker simple ...

utiliser la commande ci-dessous docker

docker run -d -p 80:80 --name web server ubuntu16 (image name) after that check localhost or ip address: 80 (open browser and check)


1
veuillez corriger la mise en forme de votre réponse ...
Pierre.Vriens
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.