Übersicht



Beim Erstellen von Docker-Images wird oft unabsichtlich der Speicherplatz größer. Die meisten Ursachen sind unnötig erzeugte Schichten. In diesem Artikel teile ich meine Erfahrungen zur Optimierung, indem ich den docker history-Befehl verwende, um die 'Genealogie' eines Images zu überprüfen und dieses tatsächlich zu optimieren.

Mit diesem Befehl können Sie genau herausfinden, was Ihr Image schwer macht und effizientere Images erstellen.


docker history: Überprüfung der Genealogie von Images

docker history ist ein Befehl, der zeigt, wie ein bestimmtes Image erstellt wurde und welche Komponenten es hat. Sie können sehen, welche Schichten von den einzelnen Befehlen des Dockerfiles gebildet wurden und wann jede Schicht erstellt wurde und wie groß sie ist.

Die Grundnutzung ist sehr einfach.

docker history [Optionen] <Image-Name:Tag>

Zum Beispiel lautet der Befehl zur Überprüfung der Historie des lokalen my-app:latest Images:

docker history my-app:latest

Die Ausgabe zeigt die oberste Schicht (neueste) bis hin zum Basisimage (das älteste) in der Reihenfolge an.

IMAGE          CREATED         CREATED BY                                      SIZE
a6215f271958   vor 5 Minuten   /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
<missing>      vor 7 Wochen     /bin/sh -c #(nop) ADD datei:f28242cf608f6...   7.81MB
  • CREATED BY: Der Dockerfile-Befehl, der diese Schicht erstellt hat

  • SIZE: Der Speicherplatz, den diese Schicht einnimmt

Nützlicher Tipp: Vollständige Befehlsanzeige mit --no-trunc

Die Standardausgabe von docker history kann abgeschnitten werden, wenn der Befehl in der CREATED BY Spalte zu lang ist. In diesem Fall ist es unerlässlich, die --no-trunc-Option zu verwenden, um den vollständigen Befehl ohne Abschneidung zu sehen.

docker history --no-trunc my-app:latest

Warum die Schichtenanalyse wichtig ist: Echte Optimierungserfahrungen



Docker-Images erstellen eine Schicht pro Zeile im Dockerfile, das ist das Grundprinzip. Jede Schicht stellt eine 'Änderung' dar, die auf der vorherigen Schicht aufbaut.

Das Problem ist, dass unnötige Schichtteilungen die Image-Größe schnell erhöhen können.

Fallstudie: Die Fallen von COPY und RUN chown

Beim Schreiben eines Dockerfiles kommt es häufig vor, dass Projektdateien in den Container kopiert (COPY) und anschließend die Besitzrechte dieser Dateien auf einen bestimmten Benutzer (z. B. appuser) geändert werden (RUN chown).

Unwirtschaftliche Methode: 2 Schichten

Zu Beginn wurde das Dockerfile wie folgt geschrieben.

# 1. Dateien zunächst kopieren (als root kopiert)
COPY . .

# 2. Besitzer ändern (in einem separaten Befehl)
RUN chown -R appuser:appgroup /app

Der Befehl docker history zeigt, dass zwei Schichten entstanden sind.

IMAGE          CREATED BY                                        SIZE
<layer_id_2>   /bin/sh -c chown -R appuser:appgroup /app        150MB  <-- (Problem!)
<layer_id_1>   /bin/sh -c #(nop) COPY dir:abc in /app           150MB

Hier ergibt sich ein ernsthaftes Problem.

  1. Durch den Befehl COPY . . wurden Dateien mit einer Größe von 150 MB zur Schicht 1 hinzugefügt.

  2. Der Befehl RUN chown hat diese 150 MB Dateien der Schicht 1 lediglich kopiert und nur die Besitzerinformationen geändert, damit sie in Schicht 2 neu gespeichert werden.

Der Inhalt der Dateien ist gleich, aber sie sind jeweils in verschiedenen Schichten gespeichert – eine als root und die andere als appuser. Infolgedessen beträgt die Gesamtkapazität des Images 300MB (150MB + 150MB).

Effiziente Methode: 1 Schicht

Dieses Problem kann einfach durch die Verwendung des --chown-Flags des COPY-Befehls gelöst werden.

# 1. Kopieren und gleichzeitig Besitzrechte festlegen
COPY --chown=appuser:appgroup . .

Nach dieser Änderung des Dockerfiles habe ich erneut docker history überprüft.

IMAGE          CREATED BY                                             SIZE
<layer_id_1>   /bin/sh -c #(nop) COPY --chown=appuser... dir:abc     150MB

Es wurde nur eine einzige Schicht erstellt, und die Gesamtgröße des Images reduzierte sich auf 150MB. Nur zwei Zeilen wurden in eine einzige Zeile zusammengefasst, und die Image-Größe wurde um fast die Hälfte reduziert.


Fazit

docker history ist mehr als nur ein Werkzeug zur Anzeige der Erstellungshistorie von Images; es ist ein beispielhaftes Analysewerkzeug für die Image-Optimierung.

Nach der Änderung des Dockerfiles ist es ratsam, regelmäßig docker history --no-trunc auszuführen, um zu überprüfen, ob die Schichten wie beabsichtigt erstellt wurden und keine unnötigen Schichten vorhanden sind, die Speicherplatz beanspruchen. Diese kleine Gewohnheit trägt dazu bei, leichte und effiziente Images zu erstellen.