Docker-Bildverkleinerungstechniken

Haben Sie sich jemals gefragt, warum ein Docker-Container mit nur einer Anwendung etwa 400 MB groß sein kann? Oder haben Sie sich Sorgen über die Größe des Docker-Images gemacht, das eine einzelne Binärdatei mit mehreren zehn MB enthält?



Der Autor des Artikels, dessen Übersetzung wir heute veröffentlichen, möchte die Hauptfaktoren analysieren, die sich auf die Größe der Docker-Container auswirken. Darüber hinaus wird er Empfehlungen zur Verringerung der Größe von Containern aussprechen.

Docker-Bildebenen


Ein Bild eines Docker-Containers ist im Wesentlichen eine Sammlung von Dateien, die in mehreren Ebenen übereinander gestapelt sind. Aus diesen Dateien wird ein Arbeitscontainer zusammengestellt. Docker verwendet das UnionFS- Dateisystem, in dem Dateien in Ebenen gruppiert sind. Eine Ebene kann eine Datei oder mehrere Dateien enthalten, Ebenen überlappen sich. Während der Ausführung des Containers werden die Inhalte der Ebenen zusammengefasst, so dass der Endbenutzer des Containers die in Ebenen angeordneten Materialien als ein einziges Dateisystem wahrnimmt.


Vereinfachte UnionFS-Ansicht

Das resultierende Dateisystem wird dem Endbenutzer mithilfe einer UnionFS-Implementierung präsentiert (Docker unterstützt viele ähnliche Implementierungen über Plug-in-Speichertreiber). Die Gesamtgröße der vom Endbenutzer empfangenen Dateien entspricht der Summe der Dateigrößen in den Ebenen. Wenn Docker einen Container basierend auf dem Bild erstellt, werden alle schreibgeschützten Ebenen des Bildes verwendet, wobei eine dünne Ebene über diesen Ebenen hinzugefügt wird, die das Lesen und Schreiben unterstützt. Auf dieser Ebene können Sie Dateien in einem laufenden Container ändern.


Der ausgeführte Container enthält eine Lese- / Schreibebene, die sich über schreibgeschützten Ebenen befindet

Was passiert, wenn eine Datei in der Layer 4 oben schematisch dargestellten Containers gelöscht wird? Obwohl diese Datei im Dateisystem, das der Benutzer sieht, nicht verfügbar ist, ist die Größe dieser Datei immer noch eine der Komponenten der Containergröße, da diese Datei in einer der schreibgeschützten Ebenen verbleibt.

Es ist ganz einfach, das Image mit einer kleinen ausführbaren Anwendungsdatei zu erstellen und zum sehr großen Image zu gelangen. Im Folgenden werden verschiedene Methoden vorgestellt, um Container so klein wie möglich zu machen.

Achten Sie auf den Pfad zum Ordner, der auf den Materialien basiert, von denen Bilder gesammelt werden


Wie werden Docker-Images am häufigsten zusammengestellt? Anscheinend - so:

 docker build . 

Der Punkt in diesem Befehl teilt Docker mit, dass das aktuelle Arbeitsverzeichnis das Stammverzeichnis des Dateisystems ist, das für den Image-Assembly-Prozess verwendet wird.

Um besser zu verstehen, was passiert, nachdem der obige Befehl ausgeführt wurde, sollte beachtet werden, dass das Erstellen eines Docker-Images ein Client-Server-Prozess ist. Die Docker-Befehlszeilenschnittstelle (Client), an die wir den docker build , verwendet die Docker-Engine (Server), um das Container-Image zu erstellen. Um den Zugriff auf das Basisdateisystem des Clients einzuschränken, muss das Image-Assembly-System wissen, wo sich das Stammverzeichnis des virtuellen Dateisystems befindet. Dort suchen die Anweisungen aus der Dockerfile Datei nach Dockerfile , die möglicherweise im zusammengestellten Image enden.

Stellen Sie sich einen Ort vor, an dem Dockerfile normalerweise eine Dockerfile . Dies ist wahrscheinlich das Stammverzeichnis des Projekts? Befindet sich im Stammverzeichnis des Projekts eine Dockerfile , die vom docker build zum Erstellen des Abbilds verwendet wird, können alle Projektdateien in das Abbild aufgenommen werden. Dies kann dazu führen, dass Tausende von Junk-Dateien mit einer Größe von mehreren Megabyte in den Kontext der Image-Assembly gelangen. Wenn Sie die Befehle Dockerfile und Dockerfile in der Dockerfile leicht verwenden, werden alle Projektdateien möglicherweise Teil des fertigen Abbilds. In den meisten Fällen benötigen diejenigen, die Bilder sammeln, dies nicht, da das endgültige Bild normalerweise nur einige ausgewählte Dateien enthalten sollte.

Dockerfile immer sicher, dass der docker build Befehl docker build richtigen Pfad docker build und dass keine Befehle in der Dockerfile Datei vorhanden sind, die dem Image unnötige Dateien hinzufügen. Wenn Sie aus irgendeinem Grund das Stammverzeichnis des Projekts zum Erstellungskontext machen müssen, können Sie Dateien selektiv einschließen und sie mithilfe von .dockerignore davon .dockerignore .

Bildebenen optimieren


Ein Image kann maximal 127 Ebenen haben (sofern der Data Warehouse-Treiber eine solche Anzahl von Ebenen unterstützt). Diese Einschränkung kann, falls unbedingt erforderlich, gelockert werden, aber mit diesem Ansatz wird der Bereich von Systemen, auf denen solche Bilder gesammelt werden können, eingeschränkt. Der Punkt ist, dass die Docker-Engine auf einem System ausgeführt werden muss, dessen Kernel entsprechend geändert wurde.

Wie im vorherigen Abschnitt erwähnt, bleiben Dateien, die in eine bestimmte Ebene fallen, dort, da UnionFS beim Zusammenstellen von Bildern verwendet wird, selbst dann, wenn sie aus den darüber liegenden Ebenen gelöscht wurden. Lass es uns mit dem experimentellen Dockerfile herausfinden:

 FROM alpine RUN wget http://xcal1.vodafone.co.uk/10MB.zip -P /tmp RUN rm /tmp/10MB.zip 

Lassen Sie uns das Bild zusammenbauen:


Zusammenstellung eines experimentellen Bildes, in dem irrational genutzter Raum vorhanden ist

Erkunde das Bild mit einem Tauchgang :


Der Bildleistungsindikator ist 34%

Der Bildeffizienzindikator von 34% zeigt an, dass eine beträchtliche Menge an Bildraum irrational verwendet wird. Dies führt zu einer Verlängerung der Startzeit des Images, zu einer unnötigen Verschwendung von Netzwerkressourcen und zu einer langsameren Startzeit des Containers.

Wie dieses Problem loswerden? Betrachten wir mehrere Optionen.

▍ Teamarbeitsergebnisse zusammenführen


Haben Sie jemals Dockerfile gesehen, die sehr lange RUN Anweisungen enthalten, in denen viele Shell-Befehle mit && kombiniert werden? Dies ist der Zusammenschluss der Ergebnisse der Teams.

Mit dieser Methode erstellen wir basierend auf den Ergebnissen eines einzelnen langen Teams nur eine Ebene. Da das Bild keine Ebenen enthält, die in den folgenden Ebenen gelöschte Dateien enthalten, enthält das endgültige Bild keine solchen „Geisterdateien“. Betrachten Sie dies als ein Beispiel und bringen Sie die obige Dockerfile in diesen Zustand:

 FROM alpine RUN wget http://xcal1.vodafone.co.uk/10MB.zip -P /tmp && rm /tmp/10MB.zip 

Danach analysieren wir das Bild:


Durch das Zusammenführen von Teams konnten Sie ein zu 100% optimiertes Image erstellen

Die Anwendung dieser Technik zum Optimieren der Größe von Bildern in der Praxis besteht darin, dass Sie nach Abschluss der Arbeit an der Dockerfile Datei diese analysieren und herausfinden müssen, ob das Zusammenführen von Dockerfile verwendet werden kann, um den verschwendeten Speicherplatz zu verringern.

▍Anwenden der Option --squash


In Fällen, in denen Sie Dockerfile anderer Personen Dockerfile , die Sie nicht ändern möchten oder können, können Sie alternativ zum Zusammenführen von Befehlen ein Bild mit der Option --squash .

In modernen Docker-Versionen (ab 1.13) können Sie alle Ebenen in einer Ebene zusammenfassen und so "Geister-Ressourcen" entfernen. In diesem Fall können Sie die ursprüngliche, nicht Dockerfile , die viele separate Befehle enthält. Sie müssen das Image jedoch mit der Option --squash :

 docker build --squash . 

Das resultierende Bild ist zu 100% optimiert:


Durch die Verwendung der Option --squash während der Montage konnte ein zu 100% optimiertes Bild erstellt werden

Hier können Sie auf ein interessantes Detail achten. In Dockerfile eine Ebene zum Hinzufügen einer Datei und eine weitere Ebene zum Löschen dieser Datei erstellt. Die Option --squash ist intelligent genug, um zu verstehen, dass Sie in diesem Szenario überhaupt keine zusätzlichen Ebenen erstellen müssen (im endgültigen Bild gibt es nur 9ccd9… aus dem von uns verwendeten Basis-Image). Im Allgemeinen können wir dafür --squash ein zusätzliches Plus setzen. --squash , mit --squash müssen Sie berücksichtigen, dass dies die Verwendung von zwischengespeicherten Ebenen beeinträchtigen kann.

Daher wird empfohlen, die Tatsache zu berücksichtigen, dass Sie bei der Arbeit mit der Dockerfile - Dockerfile anderen Dockerfile , die Sie nicht ändern Dockerfile , den irrational --squash Bildspeicherplatz minimieren können, indem Sie Bilder mit der Option --squash . Um das fertige Bild zu analysieren, können Sie das Tauchwerkzeug verwenden.

Löschen Sie Caches und temporäre Dateien


Beim Containerisieren von Anwendungen tritt häufig eine Situation auf, in der Sie zusätzliche Tools, Bibliotheken und Dienstprogramme in das Image einfügen müssen. Dies geschieht mit Paketmanagern wie apk , yum , apt .

Paketmanager bemühen sich, dem Benutzer Zeit zu sparen und seine Netzwerkverbindung bei der Installation von Paketen nicht erneut zu laden. Daher werden heruntergeladene Daten zwischengespeichert. Damit das endgültige Docker-Image so klein wie möglich wird, müssen in diesem Image keine Paketmanager-Caches gespeichert werden. Wenn wir jemals ein anderes Image benötigen, können wir es immer mit dem aktualisierten Dockerfile neu Dockerfile .

Um die von den drei oben genannten gängigen Paketmanagern erstellten Caches zu entfernen, können Sie am Ende eines aggregierten Befehls (dh eines Befehls, der zum Erstellen einer Ebene ausgeführt wird) Folgendes hinzufügen:

 APK: ... && rm -rf /etc/apk/cache YUM: ... && rm -rf /var/cache/yum APT: ... && rm -rf /var/cache/apt 

Aus diesem Grund wird empfohlen, vor Abschluss der Arbeiten an der Dockerfile hinzuzufügen Dockerfile mit denen die Caches der zum Erstellen des Abbilds verwendeten Paketmanager entfernt werden. Gleiches gilt für temporäre Dateien, die den ordnungsgemäßen Betrieb des Containers nicht beeinträchtigen.

Wählen Sie Ihr Basisimage sorgfältig aus


Jede Dockerfile beginnt mit einer FROM Direktive. Hier legen wir das Grundbild fest, auf dessen Grundlage unser Bild erstellt wird.

In der Docker- Dokumentation heißt es dazu: „Der FROM Befehl initialisiert eine neue Erstellungsphase und richtet das Basisimage für die folgenden Anweisungen ein. Aus diesem Grund sollte eine ordnungsgemäß erstellte Dockerfile mit einer FROM Anweisung beginnen. Ein Bild kann ein beliebiges bearbeitbares Bild sein. Am einfachsten ist es, ein eigenes Image zu erstellen, das auf einem Image aus einem öffentlichen Repository basiert. "

Offensichtlich gibt es viele grundlegende Bilder, von denen jedes seine eigenen Merkmale und Fähigkeiten hat. Die richtige Auswahl eines Basisbilds, das genau das enthält, was die Anwendung benötigt, nicht mehr und nicht weniger, hat einen enormen Einfluss auf die Größe des endgültigen Bilds.

Wie zu erwarten ist, variieren die Größen der gängigen Basisbilder enorm:


Größen der populären grundlegenden Dockerbilder

Die Containerisierung der Anwendung mit dem Basis-Image von Ubuntu 19.10 führt also dazu, dass die Größe des Images zusätzlich zur Größe der Anwendung um weitere 73 MB erhöht wird. Sammeln wir das gleiche Bild auf Basis des Bildes von Alpine 3.10.3 , so erhalten wir nur einen "Zusatz" in Höhe von 6 MB. Da Docker Bildebenen zwischenspeichert, werden Netzwerkressourcen nur dann für das Laden eines Bildes aufgewendet, wenn der Container zum ersten Mal auf geeignete Weise gestartet wird (mit anderen Worten, wenn das Bild zum ersten Mal geladen wird). Die Größe des Bildes selbst wird dadurch aber nicht kleiner.

Hier können Sie zu folgendem (völlig logischen) Schluss kommen: "Also - ich werde immer Alpine verwenden!". Leider ist in der Welt der Softwareentwicklung nicht alles so einfach.

Vielleicht haben Alpine Linux-Entwickler eine geheime Zutat entdeckt, die Ubuntu oder Debian immer noch nicht finden können? Nein. Tatsache ist, dass die alpinen Entwickler, um ein Docker-Image zu erstellen, dessen Größe um eine Größenordnung kleiner ist als die Größe des Images desselben Debians, einige Entscheidungen darüber treffen mussten, was in das Image aufgenommen werden muss und was nicht. Bevor Sie das Basis-Image, das Sie immer verwenden, als Alpine bezeichnen, sollten Sie fragen, ob es alles enthält, was Sie benötigen. Obwohl Alpine über einen Paketmanager verfügt, kann es sein, dass das in Ihrer Arbeitsumgebung verwendete Paket, das beispielsweise auf Ubuntu basiert, in Alpine nicht verfügbar ist. Oder - kein Paket, sondern die gewünschte Version des Pakets. Dies sind die Kompromisse, die Sie berücksichtigen sollten, bevor Sie das für Ihr Projekt am besten geeignete Basisimage auswählen und testen.

Und schließlich können Sie mit dem Tool die Bildgröße minimieren, wenn Sie wirklich eines der größten Basisbilder benötigen. Zum Beispiel - ein kostenloses Open-Source-Tool DockerSlim . Dadurch wird das fertige Bild verkleinert.

Am Ende können wir sagen, dass die Verwendung eines sorgfältig ausgewählten Basisbildes für die Erstellung Ihrer eigenen kompakten Bilder äußerst wichtig ist. Bewerten Sie die Anforderungen Ihres Projekts, und wählen Sie ein Bild aus, das das enthält, was Sie benötigen, und das gleichzeitig für Sie akzeptable Abmessungen aufweist.

Ziehen Sie in Betracht, ein Bild zu erstellen, das kein Basisbild enthält.


Wenn Ihre Anwendung ohne eine zusätzliche, grundlegend bereitgestellte Umgebung ausgeführt werden kann, entscheiden Sie sich möglicherweise dafür, kein Basis-Image zu verwenden. Da der FROM Befehl in der Dockerfile vorhanden sein Dockerfile , können Sie Dockerfile nicht darauf verzichten. Sie muss außerdem auf eine Art Bild verweisen. Welches Bild soll man in einer solchen Situation verwenden?

Ein Kratzerblick könnte hier nützlich sein. Dockerfile seiner Beschreibung können Sie feststellen, dass es speziell für die Erstellung von Bildern leer gemacht wurde, wenn Sie die Dockerfile Sprache FROM scratch (von Grund auf FROM scratch sprechen. Dieses Image ist besonders nützlich, wenn grundlegende Images (wie Debian- und Busybox-Images) oder extrem minimale Images (solche, die eine einzelne Binärdatei enthalten und für deren Betrieb beispielsweise so etwas wie Hallo-Welt erforderlich sind) erstellt werden. Die Verwendung dieses Abbilds als Grundlage für das von Dockerfile beschriebene Dockerfile ähnelt der Verwendung eines "leeren Vorgangs" in einigen Programmen. Durch das Anwenden eines scratch wird im fertigen Bild keine zusätzliche Ebene erstellt.

Wenn es sich bei Ihrer Anwendung um eine eigenständige ausführbare Datei handelt, die eigenständig arbeiten kann, können Sie durch Auswahl des Basis- scratch Image die Größe des Containers minimieren.

Verwenden Sie mehrstufige Builds


Seit Docker 05/17 stehen mehrstufige Builds im Mittelpunkt des Interesses. Es war eine Gelegenheit, auf die man lange gewartet hatte. Es ermöglicht Image Buildern, ihre eigenen Skripte zu verlassen, um Images zu erstellen und alles Dockerfile mit dem bekannten Dockerfile Format zu Dockerfile .

Im Allgemeinen kann eine mehrstufige Assembly als Kombination mehrerer Dockerfile oder als Dockerfile mit mehreren FROM Anweisungen betrachtet werden.

Wenn Sie vor dem Entstehen von mehrstufigen Assemblys eine Assembly Ihres Projekts erstellen und mithilfe der Dockerfile in einem Container verteilen Dockerfile , müssten Sie wahrscheinlich den Assembly-Vorgang ausführen, der zum Erscheinen eines Containers wie dem folgenden führen würde:


Erstellen und verteilen Sie eine Anwendung, ohne mehrstufige Build-Technologie zu verwenden

Obwohl aus technischer Sicht alles richtig gemacht wurde, werden das endgültige Bild und der resultierende Container mit Ebenen gefüllt, die bei der Vorbereitung der Projektmaterialien erstellt wurden. Und diese Schichten werden nicht benötigt, um die Projektlaufzeitumgebung zu bilden.

Mit mehrstufigen Baugruppen können Sie die Phasen der Erstellung und Vorbereitung von Projektmaterialien von der Umgebung trennen, in der der Projektcode ausgeführt wird.


Mehrstufige Montage, Trennung des Erstellungsprozesses und der Vorbereitung des Projektmaterials von der Ausführungsumgebung

Gleichzeitig reicht eine einzige Dockerfile aus, um den gesamten Prozess der Projekterstellung zu beschreiben. Jetzt können Sie jedoch Material von einer Phase in eine andere kopieren und unnötige Daten entfernen.

Mit mehrstufigen Assemblys können Sie plattformübergreifende Assemblys erstellen, die wiederholt verwendet werden können, ohne eigene Assemblyskripts zu verwenden, die für ein bestimmtes Betriebssystem geschrieben wurden. Die endgültige Größe des Bildes kann aufgrund der Möglichkeit des selektiven Einschlusses von Materialien minimiert werden, die in den vorherigen Stufen des Bildzusammensetzungsprozesses erzeugt wurden.

Zusammenfassung


Das Erstellen von Docker-Container-Images ist ein Prozess, mit dem sich moderne Programmierer häufig befassen müssen. Es gibt viele Ressourcen zum Erstellen von Dockerfile , und im Internet finden Sie viele Beispiele für solche Dateien. Dockerfile was Sie verwenden, ist es bei der Erstellung Ihrer eigenen Dockerfile immer Dockerfile die Größe der resultierenden Bilder zu berücksichtigen.

Hier haben wir uns verschiedene Techniken zum Minimieren der Größe von Docker-Bildern angesehen. Die Aufmerksamkeit für den Inhalt der Dockerfile , einschließlich der Dockerfile , die Sie wirklich benötigen, die Auswahl des richtigen Basis-Images mithilfe der mehrstufigen Build-Technologie - all dies kann dazu beitragen, die Größe der von Ihnen erstellten Docker-Images erheblich zu verringern.

PS Wir haben den Marktplatz auf der RUVDS-Website gestartet. Auf dem Marktplatz wird das Docker- Image mit einem Klick installiert, Sie können überprüfen, wie die Container auf VPS funktionieren, 3 Testtage werden kostenlos für alle Neukunden zur Verfügung gestellt.

Sehr geehrte Leser! Wie optimieren Sie die Größe Ihrer Docker-Bilder?

Source: https://habr.com/ru/post/de485650/


All Articles