Sie machen für mich mit einem Beispiel am meisten Sinn ...
Untersuchen von Ebenen Ihres eigenen Builds mit Docker Diff
Nehmen wir ein erfundenes Beispiel Dockerfile:
FROM busybox
RUN mkdir /data
# imagine this is downloading source code
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one
RUN chmod -R 0777 /data
# imagine this is compiling the app
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/two
RUN chmod -R 0777 /data
# and now this cleans up that downloaded source code
RUN rm /data/one
CMD ls -alh /data
Jeder dieser dd
Befehle gibt eine 1M-Datei auf der Festplatte aus. Erstellen Sie das Image mit einem zusätzlichen Flag, um die temporären Container zu speichern:
docker image build --rm=false .
In der Ausgabe sehen Sie, dass jeder der ausgeführten Befehle in einem temporären Container ausgeführt wird, den wir jetzt behalten, anstatt ihn automatisch zu löschen:
...
Step 2/7 : RUN mkdir /data
---> Running in 04c5fa1360b0
---> 9b4368667b8c
Step 3/7 : RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one
---> Running in f1b72db3bfaa
1024+0 records in
1024+0 records out
1048576 bytes (1.0MB) copied, 0.006002 seconds, 166.6MB/s
---> ea2506fc6e11
Wenn Sie docker diff
für jede dieser Container-IDs eine ausführen , sehen Sie, welche Dateien in diesen Containern erstellt wurden:
$ docker diff 04c5fa1360b0 # mkdir /data
A /data
$ docker diff f1b72db3bfaa # dd if=/dev/zero bs=1024 count=1024 of=/data/one
C /data
A /data/one
$ docker diff 81c607555a7d # chmod -R 0777 /data
C /data
C /data/one
$ docker diff 1bd249e1a47b # dd if=/dev/zero bs=1024 count=1024 of=/data/two
C /data
A /data/two
$ docker diff 038bd2bc5aea # chmod -R 0777 /data
C /data/one
C /data/two
$ docker diff 504c6e9b6637 # rm /data/one
C /data
D /data/one
Jede Zeile mit dem Präfix a A
fügt die Datei hinzu, das C
zeigt eine Änderung an einer vorhandenen Datei an und das D
zeigt ein Löschen an.
Hier ist der TL; DR-Teil
Jedes der oben genannten Unterschiede in diesem Container-Dateisystem besteht aus einer "Ebene", die zusammengestellt wird, wenn Sie das Image als Container ausführen. Die gesamte Datei befindet sich in jeder Ebene, wenn hinzugefügt oder geändert wird. Daher führt jeder dieser chmod
Befehle, obwohl nur ein Berechtigungsbit geändert wird, dazu, dass die gesamte Datei in die nächste Ebene kopiert wird. Die gelöschte / data / one-Datei befindet sich noch dreimal in den vorherigen Ebenen und wird über das Netzwerk kopiert und beim Abrufen des Bildes auf der Festplatte gespeichert.
Bestehende Bilder untersuchen
Sie können die Befehle sehen, mit denen die Ebenen eines vorhandenen Bildes mit dem docker history
Befehl erstellt werden. Sie können auch docker image inspect
ein Bild ausführen und die Liste der Ebenen im Abschnitt RootFS anzeigen.
Hier ist die Geschichte für das obige Bild:
IMAGE CREATED CREATED BY SIZE COMMENT
a81cfb93008c 4 seconds ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "ls -… 0B
f36265598aef 5 seconds ago /bin/sh -c rm /data/one 0B
c79aff033b1c 7 seconds ago /bin/sh -c chmod -R 0777 /data 2.1MB
b821dfe9ea38 10 seconds ago /bin/sh -c dd if=/dev/zero bs=1024 count=102… 1.05MB
a5602b8e8c69 13 seconds ago /bin/sh -c chmod -R 0777 /data 1.05MB
08ec3c707b11 15 seconds ago /bin/sh -c dd if=/dev/zero bs=1024 count=102… 1.05MB
ed27832cb6c7 18 seconds ago /bin/sh -c mkdir /data 0B
22c2dd5ee85d 2 weeks ago /bin/sh -c #(nop) CMD ["sh"] 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ADD file:2a4c44bdcb743a52f… 1.16MB
Die neuesten Ebenen sind oben aufgeführt. Bemerkenswert ist, dass es unten zwei Schichten gibt, die ziemlich alt sind. Sie stammen aus dem Busybox-Image selbst. Wenn Sie ein Bild erstellen, erben Sie alle Ebenen des Bildes, die Sie in der FROM
Zeile angeben . Es werden auch Ebenen für Änderungen an den Bild-Metadaten hinzugefügt, z. B. die CMD
Linie. Sie nehmen kaum Platz ein und dienen eher dazu, aufzuzeichnen, welche Einstellungen für das von Ihnen ausgeführte Bild gelten.
Warum Schichten?
Die Schichten haben einige Vorteile. Erstens sind sie unveränderlich. Einmal erstellt, wird sich diese durch einen sha256-Hash identifizierte Ebene niemals ändern. Diese Unveränderlichkeit ermöglicht es Bildern, sich sicher aufzubauen und voneinander zu trennen. Wenn zwei Docker-Dateien denselben Anfangssatz von Zeilen haben und auf demselben Server erstellt werden, teilen sie denselben Satz von Anfangsebenen, wodurch Speicherplatz gespart wird. Das bedeutet auch, dass beim erneuten Erstellen eines Images, bei dem nur die letzten Zeilen der Docker-Datei Änderungen erfahren, nur diese Ebenen neu erstellt werden müssen und der Rest aus dem Ebenen-Cache wiederverwendet werden kann. Dadurch können Docker-Images sehr schnell neu erstellt werden.
In einem Container sehen Sie das Image-Dateisystem, aber dieses Dateisystem wird nicht kopiert. Über diesen Bildebenen stellt der Container seine eigene Lese- / Schreib-Dateisystemebene bereit. Jeder Lesevorgang einer Datei durchläuft die Ebenen, bis sie auf eine Ebene trifft, die die Datei zum Löschen markiert hat, eine Kopie der Datei in dieser Ebene hat oder dem Lesevorgang die Ebenen zum Durchsuchen ausgehen. Bei jedem Schreibvorgang wird eine Änderung in der container-spezifischen Lese- / Schreibschicht vorgenommen.
Reduzierung des Aufblähens der Schicht
Ein Nachteil der Ebenen ist das Erstellen von Bildern, die Dateien duplizieren oder Dateien versenden, die in einer späteren Ebene gelöscht werden. Die Lösung besteht häufig darin, mehrere Befehle zu einem einzigen RUN
Befehl zusammenzuführen. Insbesondere wenn Sie vorhandene Dateien ändern oder Dateien löschen, möchten Sie, dass diese Schritte in demselben Befehl ausgeführt werden, in dem sie zuerst erstellt wurden. Eine Neufassung der obigen Docker-Datei würde folgendermaßen aussehen:
FROM busybox
RUN mkdir /data \
&& dd if=/dev/zero bs=1024 count=1024 of=/data/one \
&& chmod -R 0777 /data \
&& dd if=/dev/zero bs=1024 count=1024 of=/data/two \
&& chmod -R 0777 /data \
&& rm /data/one
CMD ls -alh /data
Und wenn Sie die resultierenden Bilder vergleichen:
- Busybox: ~ 1 MB
- erstes Bild: ~ 6MB
- zweites Bild: ~ 2 MB
Durch einfaches Zusammenführen einiger Zeilen im erfundenen Beispiel haben wir den gleichen resultierenden Inhalt in unserem Bild erhalten und unser Bild von 5 MB auf nur die 1 MB-Datei verkleinert, die Sie im endgültigen Bild sehen.