Warum sind Docker-Container-Bilder so groß?

177

Ich habe über Dockerfile von Fedora ein einfaches Bild erstellt (anfangs 320 MB).

Nano (dieser winzige Editor mit einer Größe von 1 MB) wurde hinzugefügt, und die Größe des Bildes ist auf 530 MB gestiegen. Ich habe darüber Git hinzugefügt (30 MB) und dann meine Bildgröße Sky-Rockets auf 830 MB.

Ist das nicht verrückt?

Ich habe versucht, Container zu exportieren und zu importieren, um Verlaufs- / Zwischenbilder zu entfernen. Dieser Aufwand sparte bis zu 25 MB, jetzt beträgt meine Bildgröße 804 MB. Ich habe auch versucht, viele Befehle auf einem auszuführen RUN, aber ich erhalte immer noch die gleichen anfänglichen 830 MB.

Ich habe meine Zweifel, ob es sich lohnt, Docker überhaupt zu verwenden. Ich meine, ich habe kaum etwas installiert und ich habe 1 GB überschritten. Wenn ich ernsthafte Dinge wie eine Datenbank usw. hinzufügen muss, geht mir möglicherweise der Speicherplatz aus.

Wer leidet unter lächerlicher Größe von Bildern? Wie gehst du damit um?

Es sei denn, meine Docker-Datei ist schrecklich falsch?

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

aber es ist schwer vorstellbar, was hier schief gehen könnte.

Zen
quelle
Wo und wie messen Sie die Größe Ihres Containers? Hat yum clean alldas einen Einfluss auf die Größe?
xeor
2
Erwarten Sie eine gute Größe der Bilder, da es sich um eine Ansammlung des Bildes, der übergeordneten Bilder und des Basisbilds handelt. Außerdem installiert yum nicht nur die genannten Apps, sondern auch deren Abhängigkeiten. docs.docker.com/terms/container
rexposadas
2
Nun, meine "Messung" ist die Ausführung, von docker imagesder in der letzten Spalte satte 830 MB angegeben sind. Ich weiß möglicherweise nicht, wie groß mein Bild tatsächlich ist, da der Befehl docker images angibt, dass diese 830 MB eine virtuelle Größe haben. Aber wie groß ist das Bild tatsächlich?
Zen

Antworten:

118

Wie @rexposadas sagte, enthalten Bilder alle Ebenen und jede Ebene enthält alle Abhängigkeiten für das, was Sie installiert haben. Es ist auch wichtig zu beachten, dass die Basis-Images (wie sie fedora:latestin der Regel sehr einfach sind). Sie werden möglicherweise von der Anzahl der Abhängigkeiten überrascht sein, die Ihre installierte Software aufweist.

Ich konnte Ihre Installation erheblich verkleinern, indem ich yum -y clean allzu jeder Zeile Folgendes hinzufügte :

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

Es ist wichtig, dass Sie dies für jeden RUN tun, bevor die Ebene festgeschrieben wird. Andernfalls werden beim Löschen keine Daten entfernt. Das heißt, in einem Union / Copy-on-Write-Dateisystem reduziert die Bereinigung am Ende die Dateisystemnutzung nicht wirklich, da die realen Daten bereits auf niedrigeren Ebenen festgeschrieben sind. Um dies zu umgehen, müssen Sie jede Schicht reinigen.

$ 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
quelle
1
Vielen Dank für Ihre Bemühungen, den Fall zu untersuchen, und ja, ich konnte meine Bildgröße auf ungefähr 635 MB reduzieren (dies ist der Wert, der nach Ausführung von als virtuelle Bildgröße dargestellt wird docker images). Ist es möglich, diese alten Ebenen zu entfernen / löschen / zerstören? Genauer gesagt: Ich möchte (basierend auf Ihrem Beispiel) Bilder vollständig entfernen: 172743bd5d60, 3f2fed40e4b0, fd241224e9cf, 511136ea3c5a aus dem Verlauf, sodass meine virtuelle Bildgröße mehr als der endgültigen Bildgröße entspricht, hier ~ 260 MB .
Zen
(Zu lang für 1 Kommentar) Es sei denn, die virtuelle Bildgröße hat nichts mit der tatsächlichen Bildgröße auf der Festplatte zu tun? Wenn dies der Fall ist, wie / wo kann ich dann die tatsächliche Größe meiner Bilder überprüfen?
Zen
Du könntest docker exportund dann docker importwieder. Das würde die Schichten abflachen. Ich denke nicht, dass es die Größe reduzieren würde, aber ich könnte mich irren.
Andy
10
Ja, aber der Export spart nicht viel. Trotzdem konnte ich im Internet lesen, dass ich im Docker die virtuelle Bildgröße beobachten kann. Die tatsächliche Größe der Festplatte scheint mir ein Rätsel zu sein, da in Bezug auf offizielle Informationen docker ps -sdie tatsächliche Größe der Festplatte angezeigt wird, die in meinem Fall der Fall war -1B. Das klingt vernünftig, minus 1 Byte . Ich habe etwas Platz auf der Festplatte gewonnen ... scheint echt zu sein.
Zen
@ Zen Sorry, ich folge nicht. Die virtuelle Größe und die Festplattengröße sind also zwei verschiedene Dinge? Was genau misst die virtuelle Größe?
Jason
63

Docker-Bilder sind nicht groß, Sie erstellen nur große Bilder.

Das scratchBild ist 0B und Sie können es verwenden, um Ihren Code zu verpacken, wenn Sie Ihren Code in eine statische Binärdatei kompilieren können. Sie können beispielsweise Ihr Go-Programm kompilieren und darauf verpackenscratch , um ein vollständig verwendbares Image mit weniger als 5 MB zu erstellen.

Der Schlüssel ist, die offiziellen Docker-Bilder nicht zu verwenden, sie sind zu groß. Scratch ist auch nicht so praktisch, daher würde ich empfehlen, Alpine Linux als Basis-Image zu verwenden. Es ist ~ 5 MB groß, dann fügen Sie nur das hinzu, was für Ihre App erforderlich ist. Dieser Beitrag über Mikrocontainer zeigt Ihnen, wie Sie sehr kleine Bilder basierend auf Alpine erstellen.

UPDATE: Die offiziellen Docker-Bilder basieren jetzt auf Alpine und können jetzt gut verwendet werden.

Travis Reeder
quelle
2
Tolle Lösung! Es ist so wichtig, den Abfall zu stoppen und sicherer zu bleiben -> weniger Code -> weniger Sorgen.
Ran Davidovitz
1
Zum Glück verwenden die offiziellen Docker-Bilder auch eine alpine Basis, sodass Sie immer mehr die regulären Bilder verwenden können, anstatt von den Versionen von iron.io abhängig zu sein. Siehe brianchristner.io/docker-is-moving-to-alpine-linux
Martijn Heemels
@Travis R, Ihr Link zum Posten über Mikrocontainer scheint sich woanders hingezogen zu haben. Ist dies der Beitrag, den Sie verlinken wollten?
Alexander F.
@ AlexanderF. Behobene Links, danke, dass du mich informiert hast.
Travis Reeder
28

Hier sind einige weitere Dinge, die Sie tun können :

  • Vermeiden Sie mehrere RUNBefehle, wo Sie können. Fügen Sie so viel wie möglich in einen RUNBefehl ein (mit &&)
  • Bereinigen Sie unnötige Tools wie wget oder git (die Sie nur zum Herunterladen oder Erstellen von Inhalten benötigen, aber nicht zum Ausführen Ihres Prozesses).

Mit diesen beiden UND den Empfehlungen von @Andy und @michau konnte ich die Größe meines NodeJS-Images von 1,062 GB auf 542 MB ändern.

Bearbeiten: Eine weitere wichtige Sache: "Es hat eine Weile gedauert, bis ich wirklich verstanden habe, dass jeder Dockerfile-Befehl einen neuen Container mit den Deltas erstellt. [...] Es spielt keine Rolle, ob Sie die Dateien in einem späteren Befehl rm -rf; Sie existieren weiterhin in einem Zwischenschichtbehälter. " So , jetzt habe ich es geschafft setzen apt-get install, wget, npm install(mit git Abhängigkeiten) und apt-get removein einem einzigen RUNBefehl, so jetzt mein Bild nur 438 MB hat.

Bearbeiten 29/06/17

Mit Docker v17.06 gibt es eine neue Funktion für Docker-Dateien: Sie können mehrere FROMAnweisungen in einer Docker-Datei haben, und nur das letzte Material FROMbefindet sich in Ihrem endgültigen Docker-Image. Dies ist nützlich, um die Bildgröße zu reduzieren, zum Beispiel:

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

Dies führt dazu, dass ein Bild nur das Basisbild des Knotens plus den Inhalt von / var / my-project aus den ersten Schritten enthält - jedoch ohne Ruby, Python, Git, OpenSh und GCC!

Munchkin
quelle
21

Ja, diese Größen sind lächerlich, und ich habe wirklich keine Ahnung, warum so wenige Leute das bemerken.

Ich habe ein Ubuntu-Bild erstellt, das eigentlich minimal ist (im Gegensatz zu anderen sogenannten "minimalen" Bildern). Es heißt textlab/ubuntu-essentialund hat 60 MB.

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

Das obige Bild ist 82 MB nach der Installation von Nano.

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

Git hat viel mehr Voraussetzungen, so dass das Bild größer wird, ungefähr 192 MB. Das ist immer noch weniger als die ursprüngliche Größe der meisten Bilder.

Sie können sich auch das Skript ansehen, das ich geschrieben habe, um das minimale Ubuntu-Image für Docker zu erstellen . Sie können es vielleicht an Fedora anpassen, aber ich bin mir nicht sicher, wie viel Sie deinstallieren können.

michau
quelle
13

Folgendes hat mir sehr geholfen:

Nachdem ich nicht verwendete Pakete (z. B. Redis 1200 MB befreit) in meinem Container entfernt habe, habe ich Folgendes getan:

  1. Docker export [containerID] -o Containername.tar
  2. Docker-Import -m "Nachricht hier festschreiben" Enthaltename.Tar Bildname: Tag

Die Schichten werden abgeflacht. Die Größe des neuen Bildes wird kleiner, da ich Pakete wie oben angegeben aus dem Container entfernt habe.

Das hat viel Zeit gekostet, um das zu verstehen, und deshalb habe ich meinen Kommentar hinzugefügt.

Jeffrey Schmitz
quelle
Sie können beide Schritte zu einem einzigen Schritt kombinierendocker export <CONTAINER ID> | docker import - some-image-name:latest
Anuj Kumar
8

Für eine bewährte Methode sollten Sie einen einzelnen RUN-Befehl ausführen, da jeder RUN-Befehl in der Docker-Datei eine neue Ebene in das Image schreibt und jede Ebene zusätzlichen Speicherplatz auf der Festplatte benötigt. Um die Anzahl der Ebenen auf ein Minimum zu beschränken, sollten alle Dateimanipulationen wie Installieren, Verschieben, Extrahieren, Entfernen usw. idealerweise unter einer einzigen RUN-Anweisung durchgeführt werden

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

Docker Squash ist eine wirklich gute Lösung dafür. Sie können $packagemanager cleanim letzten Schritt statt in jeder Zeile einen Docker-Squash ausführen, um alle Ebenen zu entfernen.

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

jeremyjjbrown
quelle
0

Ja, das Schichtsystem ist ziemlich überraschend. Wenn Sie ein Basis-Image haben und es wie folgt erhöhen:

# 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/* 

Das Bild hat genau die gleiche Größe. Das bedeutet im Wesentlichen, dass Sie es schaffen müssen, viel Magie zum Extrahieren, Installieren und Bereinigen in Ihre RUN-Schritte zu integrieren, um die Images so klein wie die installierte Software zu machen.

Das macht das Leben viel schwieriger ...

Dem dockerBuild fehlen RUN-Schritte ohne Commit.

99Sono
quelle