Docker von Grund auf Bilder verstehen

Docker-Container sind auf dem Vormarsch, eine bewährte Methode für die Bereitstellung und Verwaltung von Cloud-nativen verteilten Systemen. Container sind Instanzen von Docker-Images. Es stellt sich heraus, dass es viel zu wissen und zu Bildern gibt. 

In diesem zweiteiligen Tutorial werde ich ausführlich auf Docker-Bilder eingehen. In diesem Teil beginne ich mit den Grundprinzipien, und dann werde ich weiter überlegen und die Bildeinbauten überprüfen. In Teil zwei gehe ich auf die Erstellung eigener Bilder, die Fehlerbehebung und die Arbeit mit Image-Repositorys ein. 

Wenn Sie auf der anderen Seite herauskommen, wissen Sie genau, was Docker-Images genau sind und wie Sie sie effektiv in Ihren eigenen Anwendungen und Systemen einsetzen können.

Ebenen verstehen

Docker verwaltet Bilder mit einem Back-End-Speichertreiber. Es gibt verschiedene unterstützte Treiber wie AUFS, BTRFS und Overlays. Bilder werden aus geordneten Schichten erstellt. Sie können sich einen Layer als eine Reihe von Dateisystemänderungen vorstellen. Wenn Sie alle Ebenen zusammenlegen und stapeln, erhalten Sie ein neues Bild mit allen angesammelten Änderungen. 

Der bestellte Teil ist wichtig. Wenn Sie eine Datei in einer Ebene hinzufügen und in einer anderen Ebene entfernen, sollten Sie dies in der richtigen Reihenfolge tun. Docker verfolgt jede Ebene. Ein Bild kann aus Dutzenden von Ebenen bestehen (die Strombegrenzung ist 127). Jede Schicht ist sehr leicht. Der Vorteil von Ebenen ist, dass Bilder Ebenen gemeinsam nutzen können. 

Wenn Sie über viele Bilder verfügen, die auf ähnlichen Layern basieren, z. B. auf Basis-Betriebssystemen oder gängigen Paketen, werden alle diese gemeinsamen Layer nur einmal gespeichert, und der Overhead pro Image besteht nur aus den eindeutigen Layern dieses Image.

Beim Schreiben kopieren

Wenn ein neuer Container aus einem Bild erstellt wird, sind alle Bildebenen schreibgeschützt, und es wird eine dünne Lese- / Schreibebene hinzugefügt. Alle an einem bestimmten Container vorgenommenen Änderungen werden in dieser Ebene gespeichert. 

Das bedeutet nicht, dass der Container keine Dateien von seiner Bildebene aus ändern kann. Es kann auf jeden Fall. Es wird jedoch eine Kopie in der obersten Ebene erstellt, und ab diesem Zeitpunkt erhält jeder, der versucht, auf die Datei zuzugreifen, die Kopie der obersten Ebene. Wenn Dateien oder Verzeichnisse aus den unteren Ebenen entfernt werden, werden sie ausgeblendet. Die ursprünglichen Bildebenen werden durch einen kryptographischen inhaltsbasierten Hash identifiziert. Die Lese-Schreib-Schicht des Containers wird durch eine UUID identifiziert.

Dies ermöglicht eine Copy-on-Write-Strategie für Bilder und Container. Docker verwendet dieselben Elemente so oft wie möglich. Nur wenn ein Element geändert wird, erstellt Docker eine neue Kopie.

Überlegungen zum Design für Docker-Images

Die einzigartige Layer-Organisation und die Copy-on-Write-Strategie unterstützen einige bewährte Methoden zum Erstellen und Zusammenstellen von Docker-Images.

Minimalbilder: Weniger ist mehr

Docker-Bilder haben enorme Vorteile hinsichtlich Stabilität, Sicherheit und Ladezeit, je kleiner sie sind. Sie können sehr kleine Bilder für Produktionszwecke erstellen. Wenn Sie eine Problembehandlung durchführen müssen, können Sie die Tools immer in einem Container installieren. 

Wenn Sie Ihre Daten, Protokolle und alles andere nur auf bereitgestellte Volumes schreiben, können Sie Ihr gesamtes Arsenal an Debugging- und Fehlerbehebungstools auf dem Host verwenden. Wir werden bald sehen, wie Sie sehr genau kontrollieren können, welche Dateien in Ihr Docker-Image eingefügt werden.

Schichten kombinieren

Ebenen sind großartig, aber es gibt eine Begrenzung, und Ebenen sind mit Overhead verbunden. Zu viele Ebenen könnten den Dateisystemzugriff innerhalb des Containers beeinträchtigen (da jede Ebene möglicherweise eine Datei oder ein Verzeichnis hinzugefügt oder entfernt hat), und sie stören nur Ihr eigenes Dateisystem.

Wenn Sie beispielsweise mehrere Pakete installieren, können Sie für jedes Paket eine Ebene einrichten, indem Sie jedes Paket in einem separaten RUN-Befehl in Ihrer Docker-Datei installieren:

RUN apt-get Update RUN apt-get -y Installationspaket_1 RUN apt-get -y Installationspaket_2 RUN apt-get -y Installationspaket_3

Sie können sie auch mit einem einzigen RUN-Befehl in einer Ebene kombinieren.

Führen Sie apt-get-Update && \ apt-get -y-Installationspaket_1 && \ apt-get -y-Installationspaket_2 && \ apt-get -y-Installationspaket_3 aus 

Auswahl eines Basisbildes

Ihr Grundbild (praktisch keine Bilder werden von Grund auf neu erstellt) ist oft eine wichtige Entscheidung. Es kann viele Schichten enthalten und viele Fähigkeiten hinzufügen, aber auch viel Gewicht. Die Qualität des Bildes und des Autors sind ebenfalls kritisch. Sie möchten Ihre Bilder nicht auf einem flockigen Bild basieren, bei dem Sie nicht sicher sind, was genau dort drin ist und ob Sie dem Autor vertrauen können.

Für viele Distributionen, Programmiersprachen, Datenbanken und Laufzeitumgebungen gibt es offizielle Images. Manchmal sind die Optionen überwältigend. Nehmen Sie sich Zeit und treffen Sie eine kluge Entscheidung.

Überprüfen von Bildern

Schauen wir uns einige Bilder an. Hier ist eine Liste der Bilder, die derzeit auf meinem Computer verfügbar sind:

REPOSITORY TAG IMAGE ID ERSTELLT SIZE Python neuester 775dae9b960e Vor 12 Tagen 687 MB D4W / nsenter neuester 9e4f13a0901e vor 4 Monaten 83,8 kB ubuntu-mit-ssh neuesten 87391dca396d vor 4 Monaten 221 MB ubuntu neueste bd3d4369aebc vor 5 Monaten 127 MB Hallo-Welt neuester c54a2cc56cbb 7 Monaten 1.85 kB alpine letzte 4e38e38c8ce0 7 Monate zuvor 4.8 MB nsqio / nsq letzte 2a82c70fe5e3 vor 8 Monaten 70.7 MB

Das Repository und das Tag identifizieren das Bild für Menschen. Wenn Sie nur versuchen, einen Repository-Namen auszuführen oder zu ziehen, ohne das Tag anzugeben, wird standardmäßig das "latest" -Tag verwendet. Die Bild-ID ist eine eindeutige Kennung.

Lass uns eintauchen und das Hallo-Welt-Bild betrachten:

> druehne nach harrow-world ["Id": "sha256: c54a2cc56cbb2f… e7e2720f70976c4b75237dc", "RepoTags": ["hallo-world: latest"], "RepoDigests": ["hello-world @ sha256: 025aaaa". ], "Parent": "", "Comment": "", "Created": "2016-07-01T19: 39: 27.532838486Z", "Container": "562cadb4d17bbf30b58a… bf637f1d2d7f8afbef666", "ContainerConfig": "Hostname ":" c65bc554a4b7 "," Domänenname ":" "," Benutzer ":" "," AttachStdin ": false," AttachStdout ": false," AttachStderr ": false," Tty ": false," OpenStdin ": false, "StdinOnce": false, "Env": ["PATH = / usr / bin: / usr / sbin: / usr / bin: / sbin: / bin"], "Cmd": ["/ bin / sh", " -c "," # (nop) CMD [\ "/ hello \"] "]," Image ":" sha256: 0f9bb7da10de694 ... 5ab0fe537ce1cd831e "," Volumes ": null," WorkingDir ":" Entrypoint ": null, "OnBuild": null, "Labels": , "DockerVersion": "1.10.3", "Author": "", "Config": "Hostname": "c65bc554a4b7", "Domainname": "", "Benutzer": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "Tty": false, "Open Stdin ": false," StdinOnce ": false," Env ": [" PATH = / usr / sbin: / usr / bin: / sbin: / bin "]," Cmd ": [" / hello "]," Image ":" sha256: 0f9bb7da10de694b ... b0fe537ce1cd831e "," Volumes ": null," WorkingDir ":" "," Entrypoint ": null," OnBuild ": null," Labels ": ," Architecture ":" amd64 " , "Os": "linux", "size": 1848, "VirtualSize": 1848, "GraphDriver": "Name": "aufs", "Data": null, "RootFS": "Type": "Schichten", "Schichten": ["sha256: a02596fdd012f22b03a ... 079c3e8cebceb4262d7"]

Es ist interessant zu sehen, wie viele Informationen zu jedem Bild gehören. Ich werde nicht jedes Element durchgehen. Ich erwähne gerade ein interessantes Leckerbissen, dass die Einträge "container" und "containerConfig" für einen temporären Container gelten, den Docker beim Erstellen des Images erstellt. Hier möchte ich mich auf den letzten Abschnitt von "RootFS" konzentrieren. Sie können nur diesen Teil erhalten, indem Sie den Befehl inspizieren des Befehls inspizieren verwenden:

> docker inspect -f '.RootFS' Hallo-Welt Schichten [sha256: a02596fdd012f22b03af6a… 8357b079c3e8cebceb4262d7]

Es funktioniert, aber wir haben die schöne Formatierung verloren. Ich ziehe es vor, jq zu verwenden:

> docker inspizieren hallo-welt | jq. [0] .RootFS "Typ": "Schichten", "Schichten": ["sha256: a02596fdd012f22b03af6a ... 7507558357b079c3e8cebceb4262d7"] 

Sie können sehen, dass der Typ "Layer" ist und es nur einen Layer gibt. 

Schauen wir uns die Ebenen des Python-Bildes an:

> docker inspizieren python | jq [0] .RootFS  "Typ":. "Schichten", "Schichten": [ "sha256: a2ae92ffcd29f7ede ... e681696874932db7aee2c", "sha256: 0eb22bfb707db44a8 ... 8f04be511aba313bdc090", "sha256: 30339f20ced009fc3 ... 6b2a44b0d39098e2e2c40", „sha256: f55f65539fab084d4 ... 52932c7d4924c9bfa6c9e“, "sha256: 311f330fa783aef35 ... e8283e06fc1975a47002d", "sha256: f250d46b2c81bf76c ... 365f67bdb014e98698823", "sha256: 1d3d54954c0941a8f ... 8992c3363197536aa291a"]

Beeindruckend. Sieben Schichten. Aber was sind diese Schichten? Wir können den Befehl history verwenden, um das herauszufinden:

BILD ERSTELLT NACH GRÖSSE 775dae9b960e Vor 12 Tagen / bin / sh -c # (nop) CMD ["python3"] 0 B  Vor 12 Tagen / bin / sh -c cd / usr / local / bin && … 48 B  Vor 12 Tagen / bin / sh -c set -ex && buildDeps = '… 66,9 MB  Vor 12 Tagen / bin / sh -c # (nop) ENV PYTHON_PIP_V… 0 B  Vor 12 Tagen / bin / sh -c # (nop) ENV PYTHON_VERSI… 0 B  Vor 12 Tagen / bin / sh -c # (nop) ENV GPG_KEY = 0D96… 0 B  Vor 12 Tagen / bin / sh -c apt-get update && apt-ge… 7.75 MB  Vor 12 Tagen / bin / sh -c # (nop) ENV LANG = C.UTF-8 0 B  Vor 12 Tagen / bin / sh -c # (nop) ENV PATH = / usr / lo… 0 B  Vor 13 Tagen / bin / sh -c apt-get update && apt-ge… 323 MB  Vor 13 Tagen / bin / sh -c apt-get update && apt-ge… 123 MB  Vor 13 Tagen / bin / sh -c apt-get update && apt-ge… 44.3 MB  Vor 13 Tagen / bin / sh -c # (nop) CMD ["/ bin / bash"… 0 B  Vor 13 Tagen / bin / sh -c # (nop) ADD-Datei: 89ecb642… 123 MB

OK. Sei nicht beunruhigt. Nichts fehlt. Dies ist nur eine schreckliche Benutzeroberfläche. Die Layer hatten vor Docker 1.10 eine Image-ID, jedoch nicht mehr. Die ID der obersten Ebene ist nicht wirklich die ID dieser Ebene. Es ist die ID des Python-Images. Das "CREATED BY" wird abgeschnitten, aber Sie können den vollständigen Befehl sehen, wenn Sie übergeben --no-trunc. Ich werde Sie hier vor der Ausgabe retten, da die Seitenbreitenbeschränkungen extremen Zeilenumbruch erfordern.

Wie bekommst du Bilder? Es gibt drei Möglichkeiten:

  • Ziehen / Laufen
  • Belastung
  • Bauen

Wenn Sie einen Container ausführen, geben Sie dessen Image an. Wenn das Image auf Ihrem System nicht vorhanden ist, wird es aus einer Docker-Registrierung abgerufen (standardmäßig DockerHub). Alternativ können Sie direkt ziehen, ohne den Container auszuführen.

Sie können auch ein Bild laden, das Ihnen jemand als tar-Datei gesendet hat. Docker unterstützt es nativ.

Schließlich und am interessantesten können Sie Ihre eigenen Bilder erstellen, was das Thema des zweiten Teils ist.

Fazit

Docker-Images basieren auf einem geschichteten Dateisystem, das viele Vorteile und Vorteile für die Anwendungsfälle bietet, für die Container konzipiert sind, z. B. geringes Gewicht und gemeinsame Teile, sodass viele Container auf derselben Maschine bereitgestellt und wirtschaftlich betrieben werden können. 

.