Verwendung von Docker-Image-Speicher-Overlays

Verwendung von Docker-Image-Speicher-Overlays

1. Übersicht

Das Image in Docker ist in Schichten aufgebaut. Jede Schicht wird als „Layer“ bezeichnet. Diese Schichten werden im Verzeichnis /var/lib/docker/<storage-driver>/ gespeichert. Es gibt viele Arten von Speichertreibern, wie z. B. AUFS, OverlayFS, VFS, Brtfs usw. Sie können den Speichertreiber über den Befehl „Docker Info“ anzeigen (das System des Autors ist Centos7.4):

Normalerweise verwenden Ubuntu-ähnliche Systeme standardmäßig AUFS, während die CentOS 7.1+-Serie OverlayFS verwendet. Dieser Artikel stellt das Bildspeicherprinzip und die Speicherstruktur unter Verwendung von OverlayFS als Speichertreiber vor.

2. OverlayFS einführen

OverlayFS ist ein gestapeltes Dateisystem, das auf anderen Dateisystemen (wie ext4fs und xfs usw.) basiert und auf diesen aufbaut. Es nimmt nicht direkt an der Aufteilung der Festplattenspeicherstruktur teil. Es „fügt“ lediglich verschiedene Verzeichnisse im ursprünglichen zugrunde liegenden Dateisystem zusammen und präsentiert sie dann dem Benutzer. Dies ist die Joint-Mount-Technologie. Im Vergleich zu AUFS ist OverlayFS schneller und einfacher zu implementieren. Der Linux-Kernel bietet zwei Arten von OverlayFS-Treibern für Docker: Overlay und Overlay2. Overlay2 ist eine Verbesserung gegenüber Overlay und hinsichtlich der Inode-Auslastung effizienter als Overlay. Overlay hat jedoch Umgebungsanforderungen: Docker-Version 17.06.02+, das Host-Dateisystem muss im ext4- oder xfs-Format vorliegen.

Kombinierte Halterung

Overlayfs wird durch drei Verzeichnisse implementiert: unteres Verzeichnis, oberes Verzeichnis und Arbeitsverzeichnis. Es kann mehrere untere Verzeichnisse geben. Das Arbeitsverzeichnis ist das grundlegende Arbeitsverzeichnis. Sein Inhalt wird nach dem Mounten gelöscht und ist während der Verwendung für Benutzer unsichtbar. Schließlich wird die einheitliche Ansicht, die Benutzern nach Abschluss des gemeinsamen Mountens angezeigt wird, als zusammengeführtes Verzeichnis bezeichnet. Die folgende Verwendung von mount demonstriert die Funktionsweise.

Verwenden Sie den Mount-Befehl, um Overlayfs mit der folgenden Syntax zu mounten:

mount -t overlay overlay -o lowerdir=unteres1:unteres2:unteres3,upperdir=oberes,workdir=Arbeitsverzeichnis

Erstellen Sie drei Verzeichnisse A, B, C und ein Arbeitsverzeichnis:

Verwenden Sie dann die Mount-Kombination, um es in /tmp/test zu mounten:

Dann überprüfen wir das Verzeichnis /tmp/test erneut. Sie werden feststellen, dass die Verzeichnisse A, B und C zusammengeführt werden und Dateien mit demselben Dateinamen „überschrieben“ werden. Das Überschreiben hier ist kein echtes Überschreiben, aber wenn zwei Dateien im Verzeichnis während der Zusammenführung denselben Namen haben, wird im zusammengeführten Layer-Verzeichnis die Datei angezeigt, die ihr am nächsten liegt:

Gleichzeitig können wir seine Einbindungsoptionen auch über den Befehl „mount“ anzeigen:

Die oben beschriebene Methode wird auch als Gelenkmontagetechnik bezeichnet.

Overlay-Treiber in Docker

Nachdem wir das Prinzip des Overlay-Treibers vorgestellt haben, werfen wir einen Blick auf den Overlay-Speichertreiber in Docker. Das Folgende ist ein Diagramm des Funktionsprinzips von Overlay von der offiziellen Docker-Website:

In der obigen Abbildung sehen wir drei Ebenenstrukturen, nämlich: lowerdir, upperdir und merged. Lowerdir ist eine schreibgeschützte Bildebene, die eigentlich rootfs ist. Im Vergleich zu den Verzeichnissen A und B, die wir oben gezeigt haben, wissen wir, dass die Bildebene in viele Ebenen unterteilt werden kann, sodass das entsprechende lowerdir mehrere Verzeichnisse haben kann. Das Upperdir ist eine Ebene über dem Lowerdir. Diese Ebene ist eine Lese-/Schreibebene. Sie wird erstellt, wenn ein Container gestartet wird. Alle Änderungen an den Containerdaten erfolgen in dieser Ebene, verglichen mit C im Beispiel. Schließlich ist das zusammengeführte Verzeichnis der Einhängepunkt des Containers, der im Vergleich zu /tmp/test im Beispiel eine einheitliche Perspektive für den Benutzer darstellt. Diese Verzeichnisebenen werden in /var/lib/docker/overlay2/ oder /var/lib/docker/overlay/ (wenn Overlay verwendet wird) gespeichert.

Demo

Starten eines Containers

Wenn Sie den Overlay-Einhängepunkt prüfen, können Sie das eingehängte zusammengeführte Verzeichnis, Lowerdir, Upperdir und Workdir finden:

Es kann mehrere Lowerdirs für Overlay2 geben und sie werden als Softlinks gemountet, was wir später erklären werden.

So funktioniert es

Wie funktioniert der OverlayFS-Speichertreiber, wenn Daten im Container geändert werden? Im Folgenden wird der Lese- und Schreibvorgang erläutert:

lesen:

  • Wenn sich die Datei in der Containerebene (upperdir) befindet, lesen Sie die Datei direkt.
  • Wenn sich die Datei nicht in der Containerebene (upperdir) befindet, wird sie aus der Imageebene (lowerdir) gelesen.

Überarbeiten:

  • Erster Schreibvorgang: Wenn die Datei nicht im oberen Verzeichnis vorhanden ist, führen Overlay und Overlay2 Copy_Up-Vorgänge aus, um die Datei von Lowdir nach Upperdir zu kopieren. Da Overlayfs auf Dateiebene ist (selbst wenn die Datei nur wenige Änderungen aufweist, wird das Copy_Up-Verhalten generiert), werden nachfolgende Schreibvorgänge für dieselbe Datei hier auf der Kopie der Datei ausgeführt, die in den Container kopiert wurde. Dies wird oft als Copy-on-Write bezeichnet.
  • Löschen von Dateien und Verzeichnissen: Wenn eine Datei im Container gelöscht wird, wird in der Containerebene (upperdir) eine Whiteout-Datei erstellt. Dateien in der Bildebene (lowerdir) werden nicht gelöscht, da sie schreibgeschützt sind, aber die Datei „ohne“ verhindert, dass sie angezeigt werden. Wenn ein Verzeichnis im Container gelöscht wird, wird in der Containerebene (upperdir) ein opakes Verzeichnis erstellt. Dies entspricht dem Whiteout-Prinzip oben und verhindert, dass Benutzer weiterhin darauf zugreifen können, selbst wenn die Bildebene noch vorhanden ist.

Vorsichtsmaßnahmen

  • Der Copy_Up-Vorgang wird nur beim ersten Schreiben der Datei ausgeführt. Danach wird nur die Kopie geändert.
  • Overlayfs gilt nur für zwei Verzeichnisebenen und bietet eine schnellere Suche als AUFS.
  • Das Löschen von Dateien auf der Containerebene ist nur ein „Ablenkungsmanöver“, das durch die Whiteout-Datei verdeckt wird. Die Imageebene wird nicht gelöscht. Deshalb wird das durch Docker Commit gespeicherte Image immer größer. Unabhängig davon, wie die Daten auf der Containerebene gelöscht werden, ändert sich die Imageebene nicht.

3. Overlay2-Bildspeicherstruktur

Ziehen Sie ein Ubuntu-Image aus dem Repository. Das Ergebnis zeigt, dass insgesamt 4 Image-Ebenen wie folgt gezogen werden:

Zu diesem Zeitpunkt sind die 4 Ebenen im Verzeichnis /var/lib/docker/overlay2/ gespeichert:

Es gibt ein zusätzliches l-Verzeichnis, das Softlinks aller Ebenen enthält. Kurzlinks verwenden kurze Namen, um zu verhindern, dass Parameter beim Mounten die Seitengrößenbeschränkung erreichen (das kurze Verzeichnis beim Anzeigen des Mount-Befehls in der Demonstration):

Das unterste Bildverzeichnis enthält eine Diff- und eine Link-Datei. Das Diff-Verzeichnis speichert den Bildinhalt der aktuellen Ebene und die Link-Datei hat den entsprechenden Kurznamen:

Das obige Bild enthält ein zusätzliches Arbeitsverzeichnis und eine untergeordnete Datei. Die untergeordnete Datei wird verwendet, um den Kurznamen der übergeordneten Ebene aufzuzeichnen, und das Arbeitsverzeichnis wird verwendet, um das angegebene Arbeitsverzeichnis gemeinsam bereitzustellen. Wie sind diese Verzeichnisse und Bilder zusammen organisiert? Die Antwort lautet: durch Metadatenzuordnung. Metadaten werden in Bildmetadaten und Layer-Metadaten unterteilt.

Bildmetadaten

Die Image-Metadaten werden im Verzeichnis /var/lib/docker/image/<storage_driver>/imagedb/content/sha256/ gespeichert. Der Name ist eine Datei, die nach der Image-ID benannt ist. Die Image-ID kann über Docker-Images angezeigt werden. Diese Dateien speichern die Root-FS-Informationen des Images, den Zeitpunkt der Image-Erstellung, Informationen zum Build-Verlauf, verwendete Container, einschließlich des Start-Entrypoints und CMD usw. im JSON-Format. Die ID des Ubuntu-Image lautet beispielsweise 47b19964fb50:

Zeigen Sie die entsprechenden Metadaten an (mit vim :%!python -m json.tool in JSON formatiert) und erfassen Sie die Zusammensetzung des Root-Dateisystems:

Die obige Diff_ID entspricht einer Bildebene, die der Reihe nach von oben nach unten angeordnet ist und die unterste bis zur obersten Ebene der Bildebene darstellt:

In welcher Beziehung steht diff_id zu den Ebenen? Insbesondere verwendet Docker jede Diff_ID und alle historischen Informationen im Root-FS, um den entsprechenden inhaltsadressierbaren Index (ChainID) zu berechnen, und die ChaiID wird der Layer-Ebene zugeordnet und dann der Image-Datei jeder Image-Ebene.

Layer-Metadaten

Die Ebene entspricht dem Konzept der Imageebene. Vor Docker Version 1.10 wurden Images über eine Graphstruktur verwaltet. Jede Imageebene verfügte über Metadaten, die die Build-Informationen der Ebene und die ID der übergeordneten Imageebene aufzeichneten. Die oberste Imageebene zeichnete weitere Informationen als Metadaten für das gesamte Image auf. Graph verwaltet eine baumartige Bildebenenstruktur basierend auf der Bild-ID (d. h. der Bildebenen-ID der obersten Ebene) und der übergeordneten Bildebenen-ID, die in jeder Bildebene aufgezeichnet ist.

Eine der größten Änderungen im Bildmetadatenmanagement nach Docker-Version 1.10 ist die Vereinfachung der Metadaten der Bildebene, die nur noch ein bestimmtes Bildebenen-Dateipaket enthält. Nachdem der Benutzer eine bestimmte Image-Ebene auf den Docker-Host heruntergeladen hat, erstellt Docker lokale Ebenen-Metadaten auf dem Host basierend auf dem Image-Layer-Dateipaket und den Image-Metadaten, einschließlich Diff, Parent, Größe usw. Wenn Docker die auf dem Hostcomputer generierte neue Image-Ebene in das Register hochlädt, werden die mit der neuen Image-Ebene verknüpften Metadaten auf dem Hostcomputer nicht zusammen mit der Image-Ebene gepackt und hochgeladen.

Docker definiert zwei Schnittstellen, Layer und RWLayer, die verwendet werden, um einige Operationen der Nur-Lese-Ebene bzw. der Lese-/Schreib-Ebene zu definieren. Es definiert auch roLayer und mountedLayer, um die beiden oben genannten Schnittstellen jeweils zu implementieren. Unter diesen wird roLayer verwendet, um die unveränderliche Bildebene zu beschreiben, und mountedLayer wird verwendet, um die lesbare und beschreibbare Containerebene zu beschreiben. Insbesondere umfassen die in roLayer gespeicherten Inhalte hauptsächlich die ChainID, die die Bildebene indiziert, den Bestätigungscode DiffID der Bildebene, die übergeordnete Bildebene, die CacheID des Speichertreibers, der die aktuelle Bildebenendatei speichert, die Größe der Bildebene und andere Inhalte. Diese Metadaten werden im Ordner /var/lib/docker/image/<storage_driver>/layerdb/sha256/<chainID>/ gespeichert. wie folgt:

In jedem ChainID-Verzeichnis gibt es drei Dateien (Cache-ID, Diff und Zize):

Cache-ID-Datei:

Die von Docker zufällig generierte UUID enthält den Verzeichnisindex der Image-Ebene, also das Verzeichnis in /var/lib/docker/overlay2/. Deshalb kann das entsprechende Ebenenverzeichnis über die ChainID gefunden werden. Das entsprechende Verzeichnis von ChainID ist d801a12f6af7beff367268f99607376584d8b2da656dcd8656973b7ad9779ab4, also 130ea10d6f0ebfafc8ca260992c8d0bef63a1b5ca3a7d51a5cd1b1031d23efd5, gespeichert in /var/lib/docker/overlay2/130ea10d6f0ebfafc8ca260992c8d0bef63a1b5ca3a7d51a5cd1b1031d23efd5

Diff-Datei:

Die diff_id in den Bildmetadaten wird gespeichert (entspricht der UUID in den diff_ids in den Metadaten)

Dateigröße:

Speichert die Größe der Bildebene

Unter allen Attributen der Ebene wird die DiffID basierend auf dem Inhalt des Bildebenendateipakets unter Verwendung des SHA256-Algorithmus berechnet. Die ChainID ist ein Index, der auf dem Inhaltsspeicher basiert. Sie wird basierend auf der DiffID der aktuellen Ebene und aller übergeordneten Bildebenen berechnet. Die spezifische Berechnung lautet wie folgt:

  • Wenn die Bildebene die unterste Ebene ist (keine übergeordnete Bildebene), ist die DiffID dieser Ebene die ChainID.
  • Die ChainID-Berechnungsformel für diese Bildebene lautet ChainID(n)=SHA256(Chain(n-1)DiffID(n)). Dabei werden zur ChainID der übergeordneten Bildebene ein Leerzeichen und die DiffID der aktuellen Ebene hinzugefügt und anschließend die SHA256-Prüfsumme berechnet.

Zu den lesbaren Informationen zu Init-Layer und Container-Einhängepunkten, die in den MountedLayer-Informationen gespeichert sind, gehören: die ID des Container-Init-Layers (Init-ID), die für das gemeinsame Einhängen verwendete ID (Mount-ID) und die ChainID (Parent) des übergeordneten Layer-Images des Container-Layers. Die relevanten Dateien befinden sich im Verzeichnis /var/lib/docker/image/<storage_driver>/layerdb/mounts/<container_id>/. Starten Sie einen Container mit der ID 3c96960b3127 wie folgt:

Sehen Sie sich die entsprechenden drei gemounteten Layer-Dateien an:

Sie können sehen, dass initID der Name des in /var/lib/docker/overlay2/ gespeicherten Verzeichnisses ist, wobei -init nach mountID hinzugefügt wurde:

Sie können die MountID des entsprechenden Mounts auch direkt über den Mount-Befehl anzeigen. Sie entspricht dem Verzeichnis /var/lib/docker/overlay2/, das auch das von overlayfs angezeigte zusammengeführte Verzeichnis ist:

Im Container wird eine Datei erstellt:

An diesem Punkt können Sie die entsprechenden Dateien im zusammengeführten Verzeichnis des Hosts sehen:

Über die Init-Schicht

Die Init-Schicht wird durch einen Namen dargestellt, der mit uuid+-init endet. Sie liegt zwischen der Nur-Lese-Schicht und der Lese-/Schreib-Schicht. Sie wird zum Speichern von Informationen wie /etc/hosts und /etc/resolv.conf verwendet. Diese Schicht wird benötigt, da beim Starten des Containers die Dateien oder Verzeichnisse, die zur Image-Schicht gehören sollten, wie z. B. der Hostname, vom Benutzer geändert werden müssen. Die Image-Schicht erlaubt jedoch keine Änderungen. Daher wird beim Start eine separate Init-Schicht bereitgestellt und die Dateien in der Init-Schicht werden geändert, um den Zweck der Änderung dieser Dateien zu erreichen. Diese Änderungen sind häufig nur im aktuellen Container wirksam, und wenn ein Docker-Commit als Image übermittelt wird, wird die Init-Ebene nicht übermittelt. Das Verzeichnis, in dem diese Dateiebene gespeichert ist, ist /var/lib/docker/overlay2/<init_id>/diff

Zusammenfassung

Durch die obige Einführung sollte eine vollständige Schicht eines Containers aus drei Teilen bestehen, wie unten gezeigt:

  • Image-Layer: auch als RootFS bekannt, stellt das Dateisystem für den Container-Start bereit
  • Init-Ebene: Wird verwendet, um einige Dateien im Container zu ändern, wie z. B. /etc/hostname, /etc/resolv.conf usw.
  • Containerebene: Verwenden Sie die gemeinsame Bereitstellung, um Benutzern ein einheitliches lesbares und beschreibbares Verzeichnis bereitzustellen.

IV. Fazit

Dieser Artikel stellt das Bildspeicherprinzip mit Overlayfs als Speichertreiber vor. Die Bilddaten jeder Ebene werden im Verzeichnis /var/lib/docker/overlay2/<uuid>/diff gespeichert, die Daten der Init-Ebene werden im Verzeichnis /var/lib/docker/overlay2/<init-id>/diff gespeichert und die Daten der einheitlichen Ansicht (Containerebene) werden im Verzeichnis /var/lib/docker/overlay2/<mount_id>/diff gespeichert. Docker verwendet Inhaltsadressierung (ChainID) über Bildmetadaten und Ebenenmetadaten, um diese Verzeichnisse zu organisieren und das auf dem Container ausgeführte Dateisystem zu bilden.

siehe:

《OverlayFS-Treiber verwenden》

《Speicherverwaltung von Docker-Images》

Dies ist das Ende dieses Artikels über die Verwendung von Overlayfs für die Docker-Image-Speicherung. Weitere Informationen zu Overlayfs für die Docker-Image-Speicherung finden Sie in den vorherigen Artikeln von 123WORDPRESS.COM oder den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen!

Das könnte Sie auch interessieren:
  • Detaillierte Erläuterung des Implementierungsprozesses des Docker-Cross-Host-Container-Kommunikations-Overlays
  • Implementierung eines Docker-Cross-Host-Netzwerks (Overlay)
  • So erstellen Sie ein Docker-Overlay-Netzwerk
  • Erstellen einer experimentellen Overlay-Netzwerkumgebung in Docker
  • Detaillierte Erklärung des Overlay-Netzwerks in Docker

<<:  So verbinden Sie Django 2.2 mit einer MySQL-Datenbank

>>:  Detaillierte Erläuterung der Idee der verteilten Sperre in MySQL mit Hilfe von DB

Artikel empfehlen

Linux-Installation, MongoDB-Start und Lösung allgemeiner Probleme

MongoDB-Installationsprozess und Problemaufzeichn...

JavaScript implementiert schnell Kalendereffekte

In diesem Artikelbeispiel wird der spezifische Ja...

Grafisches Tutorial zur Installation der komprimierten Version von MySQL 8.0.15

In diesem Artikel wird die Installationsmethode d...

Detaillierte Erklärung des JS-Speicherplatzes

Inhaltsverzeichnis Überblick 1. Stapeln und Aufhä...

Asynchroner Lebenszyklus von AsyncHooks in Node8

Async Hooks ist eine neue Funktion von Node8. Sie...

MySQL-Abfrage-Cache und Pufferpool

1. Caches - Abfrage-Cache Die folgende Abbildung ...

Zwei Möglichkeiten zur Visualisierung von ClickHouse-Daten mit Apache Superset

Apache Superset ist ein leistungsstarkes BI-Tool,...

Verwenden Sie JavaScript, um Seiteneffekte zu erstellen

11. Verwenden Sie JavaScript, um Seiteneffekte zu...