Pourquoi les images de conteneurs Docker sont-elles si grandes?

177

J'ai fait une image simple via Dockerfile de Fedora (initialement 320 Mo).

Ajout de Nano (ce petit éditeur de 1 Mo de taille) et la taille de l'image est passée à 530 Mo. J'ai ajouté Git en plus de cela (30 Mo), puis ma taille d'image fusées célestes à 830 Mo.

N'est-ce pas insensé?

J'ai essayé d'exporter et d'importer un conteneur pour supprimer l'historique / les images intermédiaires. Cet effort a permis d'économiser jusqu'à 25 Mo, maintenant ma taille d'image est de 804 Mo. J'ai également essayé d'exécuter de nombreuses commandes sur une RUN, mais j'obtiens toujours le même 830 Mo initial.

Je doute que cela vaille la peine d'utiliser Docker. Je veux dire, j'ai à peine installé quoi que ce soit et je frappe 1 Go de plus. Si je devais ajouter des choses sérieuses comme une base de données et ainsi de suite, je pourrais manquer d'espace disque.

Quelqu'un souffre de la taille ridicule des images? Comment gères-tu cela?

À moins que mon Dockerfile soit horriblement incorrect?

FROM fedora:latest
MAINTAINER Me NotYou <[email protected]>
RUN yum -y install nano
RUN yum -y install git

mais il est difficile d'imaginer ce qui pourrait mal tourner ici.

Zen
la source
Où et comment mesurez-vous la taille de votre conteneur? A-t yum clean all-il un effet sur la taille?
xeor
2
Attendez-vous à ce que les images soient de bonne taille car il s'agit d'une accumulation de son image, de ses images parentes et de l'image de base. De plus, yum installe non seulement lesdites applications, mais aussi leurs dépendances. docs.docker.com/terms/container
rexposadas
2
Eh bien, ma "mesure" est l'exécution de docker imageslaquelle dans la dernière colonne indique un 830 Mo de poids. Je ne sais peut-être pas quelle est la taille réelle de mon image car la commande docker images indique que cette taille de 830 Mo est virtuelle. Mais là encore, quelle est la taille réelle de l'image?
Zen

Réponses:

118

Comme @rexposadas l'a dit, les images incluent toutes les couches et chaque couche comprend toutes les dépendances pour ce que vous avez installé. Il est également important de noter que les images de base (comme fedora:latestont tendance à être très simples. Vous pourriez être surpris par le nombre de dépendances de votre logiciel installé.

J'ai pu réduire considérablement votre installation en ajoutant yum -y clean allà chaque ligne:

FROM fedora:latest
RUN yum -y install nano && yum -y clean all
RUN yum -y install git && yum -y clean all

Il est important de le faire pour chaque RUN, avant que la couche ne soit validée, sinon les suppressions ne suppriment pas réellement les données. Autrement dit, dans un système de fichiers union / copie sur écriture, le nettoyage à la fin ne réduit pas vraiment l'utilisation du système de fichiers car les données réelles sont déjà validées dans les couches inférieures. Pour contourner ce problème, vous devez nettoyer chaque couche.

$ docker history bf5260c6651d
IMAGE               CREATED             CREATED BY                                      SIZE
bf5260c6651d        4 days ago          /bin/sh -c yum -y install git; yum -y clean a   260.7 MB
172743bd5d60        4 days ago          /bin/sh -c yum -y install nano; yum -y clean    12.39 MB
3f2fed40e4b0        2 weeks ago         /bin/sh -c #(nop) ADD file:cee1a4fcfcd00d18da   372.7 MB
fd241224e9cf        2 weeks ago         /bin/sh -c #(nop) MAINTAINER Lokesh Mandvekar   0 B
511136ea3c5a        12 months ago                                                       0 B
Andy
la source
1
Merci pour vos efforts pour enquêter sur le cas, et oui, j'ai pu réduire la taille de ma image à environ 635 Mo (c'est la valeur présentée comme taille d'image virtuelle après l'exécution de docker images). Est-il possible de supprimer / supprimer / détruire ces anciennes couches? Pour être plus précis: je voudrais supprimer complètement (en me basant sur votre exemple) les images: 172743bd5d60, 3f2fed40e4b0, fd241224e9cf, 511136ea3c5a de l'historique, de sorte que ma taille d'image virtuelle soit plus ou moins la même que la taille d'image finale, ici ~ 260 Mo .
Zen
(Trop long pour 1 commentaire) À moins que la taille de l'image virtuelle n'ait rien à voir avec la taille réelle de l'image sur le disque dur? Si tel est le cas, comment / où vérifier la taille réelle de mes images?
Zen
Vous pourriez docker exportet docker importencore. Cela aplatirait les couches. Je ne pense pas que cela réduirait la taille, mais je peux me tromper.
Andy
10
Ouais mais exporter ne permet pas d'économiser beaucoup. Néanmoins, j'ai pu lire sur le Web que ce que je peux observer dans Docker, c'est la taille de l'image virtuelle. La taille réelle sur le disque dur semble être un mystère pour moi, car en ce qui concerne les informations officielles docker ps -s, la taille réelle du disque dur apparaît, ce qui dans mon cas l'était -1B. Cela semble raisonnable, moins 1 octet . J'ai gagné de la place sur le disque dur ... cela semble légitime.
Zen
@Zen Désolé, je ne suis pas en train de suivre. Donc, la taille virtuelle et la taille du disque sont deux choses différentes? Que mesure exactement la taille virtuelle?
Jason
63

Les images Docker ne sont pas volumineuses, vous créez simplement de grandes images.

L' scratchimage est 0B et vous pouvez l'utiliser pour empaqueter votre code si vous pouvez compiler votre code dans un binaire statique. Par exemple, vous pouvez compiler votre programme Go et l' empaqueterscratch pour créer une image entièrement utilisable de moins de 5 Mo.

La clé est de ne pas utiliser les images officielles de Docker, elles sont trop grandes. Scratch n'est pas non plus très pratique, je vous recommande donc d'utiliser Alpine Linux comme image de base. Il fait environ 5 Mo, puis n'ajoutez que ce qui est requis pour votre application. Cet article sur Microcontainers vous montre comment créer de très petites images basées sur Alpine.

MISE À JOUR: les images officielles de Docker sont basées sur l'alpin maintenant, elles sont donc bonnes à utiliser maintenant.

Travis Reeder
la source
2
Excellente solution !, Il est si important d'arrêter le gaspillage et de rester plus en sécurité ---> moins de code -> moins de souci.
Ran Davidovitz le
1
Heureusement, les images Docker Official sont également en train d'utiliser une base alpine, vous pouvez donc de plus en plus utiliser les images régulières au lieu de dépendre des versions de iron.io. Voir brianchristner.io/docker-is-moving-to-alpine-linux
Martijn
@Travis R, votre lien pour publier sur les microconteneurs semble s'être déplacé ailleurs. Est- ce le message que vous vouliez lier?
Alexander F.
@AlexanderF. Liens fixes, merci de me le faire savoir.
Travis Reeder
28

Voici d'autres choses que vous pouvez faire :

  • Évitez les RUNcommandes multiples lorsque vous le pouvez. Mettez autant que possible dans une seule RUNcommande (en utilisant &&)
  • nettoyer les outils inutiles comme wget ou git (dont vous n'avez besoin que pour télécharger ou créer des éléments, mais pas pour exécuter votre processus)

Avec ces deux ET les recommandations de @Andy et @michau, j'ai pu redimensionner mon image nodejs de 1,062 Go à 542 Mo.

Edit: Une autre chose importante: "Il m'a fallu un certain temps pour vraiment comprendre que chaque commande Dockerfile crée un nouveau conteneur avec les deltas. [...] Peu importe si vous rm -rf les fichiers dans une commande ultérieure; ils continuent d'exister dans un conteneur de couche intermédiaire. " Alors maintenant , je réussi à mettre apt-get install, wget, npm install(avec dépendances git) et apt-get removeen une seule RUNcommande, maintenant mon image a seulement 438 Mo.

Modifier 29/06/17

Avec Docker v17.06, il y a de nouvelles fonctionnalités pour Dockerfiles: vous pouvez avoir plusieurs FROMinstructions dans un Dockerfile et seuls les éléments du dernier FROMseront dans votre image Docker finale. Ceci est utile pour réduire la taille de l'image, par exemple:

FROM nodejs as builder
WORKDIR /var/my-project
RUN apt-get install ruby python git openssh gcc && \
    git clone my-project . && \
    npm install

FROM nodejs
COPY --from=builder /var/my-project /var/my-project

Cela donnera une image ayant uniquement l'image de base nodejs plus le contenu de / var / my-project des premières étapes - mais sans ruby, python, git, openssh et gcc!

Munchkin
la source
22

Oui, ces tailles sont ridicules, et je ne sais vraiment pas pourquoi si peu de gens le remarquent.

J'ai créé une image Ubuntu qui est en fait minimale (contrairement à d'autres images dites "minimales"). Il s'appelle textlab/ubuntu-essentialet dispose de 60 Mo.

FROM textlab/ubuntu-essential
RUN apt-get update && apt-get -y install nano

L'image ci-dessus fait 82 Mo après l'installation de nano.

FROM textlab/ubuntu-essential
RUN apt-get update && apt-get -y install nano git

Git a beaucoup plus de prérequis, donc l'image s'agrandit, environ 192 Mo. C'est encore moins que la taille initiale de la plupart des images.

Vous pouvez également consulter le script que j'ai écrit pour créer l'image minimale d'Ubuntu pour Docker . Vous pouvez peut-être l'adapter à Fedora, mais je ne sais pas combien vous pourrez désinstaller.

michau
la source
13

Ce qui suit m'a beaucoup aidé:

Après avoir supprimé les paquets inutilisés (par exemple redis 1200 mb libérés) à l'intérieur de mon conteneur, j'ai fait ce qui suit:

  1. exportation du menu fixe [ID conteneur] -o nom_contenu.tar
  2. docker import -m "message de validation ici" contientername.tar image: tag

Les couches s'aplatissent. La taille de la nouvelle image sera plus petite car j'ai supprimé les packages du conteneur comme indiqué ci-dessus.

Cela a pris beaucoup de temps pour comprendre cela et c'est pourquoi j'ai ajouté mon commentaire.

Jeffrey Schmitz
la source
Vous pouvez combiner les deux étapes en une seule étapedocker export <CONTAINER ID> | docker import - some-image-name:latest
Anuj Kumar
8

Pour une meilleure pratique, vous devez exécuter une seule commande RUN, car chaque instruction RUN du Dockerfile écrit une nouvelle couche dans l'image et chaque couche nécessite de l'espace supplémentaire sur le disque. Afin de réduire au minimum le nombre de couches, toute manipulation de fichier telle que l'installation, le déplacement, l'extraction, la suppression, etc., devrait idéalement être effectuée sous une seule instruction RUN.

FROM fedora:latest
RUN yum -y install nano git && yum -y clean all
tmz83
la source
4

Docker Squash est une très bonne solution à cela. vous pouvez $packagemanager cleandans la dernière étape au lieu de dans chaque ligne, puis exécutez simplement un docker squash pour vous débarrasser de toutes les couches.

https://github.com/jwilder/docker-squash

jeremyjjbrown
la source
0

Oui, le système de couches est assez surprenant. Si vous avez une image de base et que vous l'incrémentez en procédant comme suit:

# Test
#
# VERSION       1

# use the centos base image provided by dotCloud
FROM centos7/wildfly
MAINTAINER JohnDo 

# Build it with: docker build -t "centos7/test" test/

# Change user into root
USER root

# Extract weblogic
RUN rm -rf /tmp/* \
    && rm -rf /wildfly/* 

L'image a exactement la même taille. Cela signifie essentiellement que vous devez réussir à mettre dans vos étapes RUN beaucoup de magie d'extrait, d'installation et de nettoyage pour rendre les images aussi petites que le logiciel installé.

Cela rend la vie beaucoup plus difficile ...

Le dockerBuild n'a pas d'étapes RUN sans validation.

99Sono
la source