Anpassen von Bildern mit Dockerfile Unter Bildanpassung versteht man eigentlich die Anpassung der Konfiguration und der Dateien, die jeder Ebene hinzugefügt werden. Wenn wir die Befehle für jede Änderungs-, Installations-, Konstruktions- und Betriebsebene in ein Skript schreiben und dieses Skript zum Erstellen und Anpassen des Images verwenden können, sind alle Probleme der Nichtwiederholbarkeit, der Transparenz beim Imageerstellen und des Volumens gelöst. Dieses Skript ist die Docker-Datei. Dockerfile ist eine Textdatei, die Anweisungen enthält. Jede Anweisung erstellt eine Ebene, sodass der Inhalt jeder Anweisung beschreibt, wie die Ebene erstellt werden soll. Hier nehmen wir die Anpassung des Nginx-Images als Beispiel und verwenden Dockerfile, um es anzupassen. Erstellen Sie in einem leeren Verzeichnis eine Textdatei und nennen Sie sie Dockerfile: $ mkdir mynginx $ cd mynginx $ berühren Sie die Docker-Datei Sein Inhalt ist: VON nginx RUN echo '<h1>Hallo, Docker!</h1>' > /usr/share/nginx/html/index.html Dieses Dockerfile ist sehr einfach, nur zwei Zeilen. Es sind zwei Anweisungen beteiligt: FROM und RUN. Dockerfile-Anweisungen erklärt FROM gibt das Basisbild an Das sogenannte angepasste Image muss auf einem Bild basieren und darauf angepasst sein. FROM gibt das Basis-Image an, daher ist FROM eine erforderliche Anweisung in einer Docker-Datei und muss die erste Anweisung sein. Im Docker Store gibt es viele hochwertige offizielle Images, darunter Service-Images, die direkt verwendet werden können, wie z. B. Nginx, Redis, Mongo, MySQL usw.; es gibt auch einige Images, die sich zum Entwickeln, Erstellen und Ausführen von Anwendungen in verschiedenen Sprachen eignen, wie z. B. Node, OpenJDK, Python usw. Sie können ein Bild finden, das Ihrem endgültigen Ziel am besten entspricht, und es als Basisbild anpassen. Wenn Sie das Image des entsprechenden Dienstes nicht finden können, bietet das offizielle Image auch einige grundlegendere Betriebssystem-Images wie Ubuntu, Debian, CentOS usw. Die Softwarebibliotheken dieser Betriebssysteme bieten uns einen größeren Erweiterungsspielraum. Zusätzlich zur Auswahl eines vorhandenen Images als Basisimage verfügt Docker auch über ein spezielles Image namens Scratch. Dieses Bild ist ein virtuelles Konzept und existiert nicht wirklich. Es stellt ein leeres Bild dar. VON Grund auf ... Wenn Sie Scratch als Basisbild verwenden, bedeutet dies, dass Sie auf keinem Bild basieren und die als Nächstes geschriebenen Anweisungen als erste Ebene des Bildes vorhanden sind. Es ist nicht ungewöhnlich, ausführbare Dateien direkt in das Image zu kopieren, ohne dass diese auf einem System basieren, wie etwa Swarm und CoreOS/etcd. Für statisch kompilierte Programme unter Linux muss das Betriebssystem keine Laufzeitunterstützung bereitstellen. Alle erforderlichen Bibliotheken befinden sich bereits in der ausführbaren Datei, sodass die Imagegröße direkt VON Grund auf kleiner wird. Viele mit der Sprache Go entwickelte Anwendungen verwenden diese Methode zum Erstellen von Bildern. Dies ist einer der Gründe, warum manche Leute glauben, dass Go eine Sprache ist, die sich besonders für die Container-Mikroservice-Architektur eignet. RUN Befehl ausführen Der RUN-Befehl wird zum Ausführen von Befehlszeilen-Anweisungen verwendet. Aufgrund der leistungsstarken Funktionen der Befehlszeile ist der RUN-Befehl einer der am häufigsten verwendeten Befehle beim Anpassen von Bildern. Es gibt zwei Formate: Shell-Format: RUN <Befehl>, genau wie der Befehl, der direkt in der Befehlszeile eingegeben wird. Die RUN-Anweisung in der gerade geschriebenen Docker-Datei hat dieses Format. RUN echo '<h1>Hallo, Docker!</h1>' > /usr/share/nginx/html/index.html Exec-Format: RUN ["ausführbare Datei", "Parameter 1", "Parameter 2"], was eher dem Format eines Funktionsaufrufs entspricht. VON debian:jessie Führen Sie apt-get update aus. Führen Sie apt-get install -y gcc libc6-dev make aus. Führen Sie wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" aus. RUN mkdir -p /usr/src/redis Führen Sie den Befehl tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 aus. RUN make -C /usr/src/redis RUN make -C /usr/src/redis install Wie bereits erwähnt, erstellt jede Anweisung im Dockerfile eine Ebene, und RUN ist keine Ausnahme. Das Verhalten jedes RUN ist dasselbe wie beim manuellen Erstellen eines Images: Eine neue Ebene wird erstellt, diese Befehle werden darauf ausgeführt und nach Abschluss der Ausführung werden die Änderungen an dieser Ebene übernommen, um ein neues Image zu erstellen. Durch die obige Schreibmethode wird ein 7-Schichten-Bild erstellt. Dies ist völlig bedeutungslos, und im Image werden viele Dinge installiert, die zur Laufzeit nicht benötigt werden, wie etwa die Kompilierungsumgebung, aktualisierte Softwarepakete und so weiter. Das Ergebnis ist ein sehr aufgeblähtes, vielschichtiges Image, das nicht nur die Zeit für Erstellung und Bereitstellung erhöht, sondern auch fehleranfällig ist. Dies ist ein häufiger Fehler, den viele Docker-Anfänger machen (ich kann mir das leider auch nicht verzeihen ε=(´ο`*))). Union FS hat eine maximale Anzahl von Schichten. Beispielsweise hatte AUFS früher maximal 42 Schichten, jetzt sind es maximal 127 Schichten. Die korrekte Schreibweise des obigen Dockerfiles sollte folgendermaßen aussehen: VON debian:jessie RUN buildDeps='gcc libc6-dev make' \ && apt-get update \ && apt-get install -y $buildDeps \ && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \ && mkdir -p /usr/src/redis \ && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \ && make -C /usr/src/redis \ && make -C /usr/src/redis installieren \ && rm -rf /var/lib/apt/lists/* \ && rm redis.tar.gz \ && rm -r /usr/src/redis \ && apt-get purge -y --auto-remove $buildDeps Zunächst einmal haben alle vorherigen Befehle nur einen Zweck, nämlich das Kompilieren und Installieren der ausführbaren Redis-Datei. Es müssen also nicht viele Schichten aufgetragen werden, es genügt eine einzige Schicht. Anstatt viele RUN-Befehle zu verwenden, die nacheinander verschiedenen Befehlen entsprechen, wird daher nur eine RUN-Anweisung verwendet und && wird verwendet, um die erforderlichen Befehle aneinanderzureihen. Die vorherigen 7 Schichten wurden auf 1 Schicht vereinfacht. Denken Sie beim Schreiben einer Docker-Datei immer daran, dass Sie kein Shell-Skript schreiben, sondern definieren, wie die einzelnen Ebenen aufgebaut werden sollen. Außerdem werden hier Zeilenumbrüche zu Formatierungszwecken vorgenommen. Dockerfile unterstützt die Shell-ähnliche Befehlszeilenumbruchmethode durch Hinzufügen von \ am Ende der Zeile und das Kommentarformat # am Anfang der Zeile. Eine gute Formatierung, wie etwa Zeilenumbrüche, Einzüge, Kommentare usw., erleichtert die Wartung und Fehlerbehebung und ist eine gute Angewohnheit. Darüber hinaus können Sie sehen, dass am Ende dieses Befehlssatzes ein Bereinigungsbefehl hinzugefügt wird, der die zum Kompilieren und Erstellen erforderliche Software löscht, alle heruntergeladenen und entpackten Dateien bereinigt und auch die Apt-Cache-Dateien bereinigt. Dies ist ein sehr wichtiger Schritt. Wie bereits erwähnt, werden Bilder in mehreren Ebenen gespeichert. Der Inhalt jeder Ebene wird in der nächsten Ebene nicht gelöscht und bleibt immer dem Bild folgen. Daher müssen Sie beim Erstellen eines Images darauf achten, dass in jeder Ebene nur das hinzugefügt wird, was wirklich benötigt wird, und dass alles Irrelevante bereinigt wird. Einer der Gründe, warum viele Docker-Neulinge sehr aufgeblähte Images erstellen, besteht darin, dass sie vergessen, am Ende jeder Build-Ebene irrelevante Dateien zu bereinigen. Erstellen des Images OK, gehen wir zurück zum Dockerfile des angepassten Nginx-Image. Nachdem wir nun den Inhalt dieser Docker-Datei verstehen, erstellen wir dieses Image. Führen Sie es im Verzeichnis aus, in dem sich die Dockerfile-Datei befindet: $ docker build -t nginx:v3 . Senden des Build-Kontexts an den Docker-Daemon 2.048 kB Schritt 1: VON nginx ---> e43d811ce2f4 Schritt 2: RUN echo '<h1>Hallo, Docker!</h1>' > /usr/share/nginx/html/index.html ---> Wird ausgeführt in 9cdc27646c7b ---> 44aa4490ce2c Zwischenbehälter entfernen 9cdc27646c7b 44aa4490ce2c erfolgreich erstellt Anhand der Ausgabe des Befehls können wir den Bildaufbauvorgang deutlich erkennen. In Schritt 2 startet der RUN-Befehl, wie bereits erwähnt, einen Container 9cdc27646c7b, führt den erforderlichen Befehl aus, übermittelt schließlich diese Ebene 44aa4490ce2c und löscht dann den verwendeten Container 9cdc27646c7b. Hier verwenden wir den Befehl Docker Build, um das Image zu erstellen. Das Format ist: Docker Build [Optionen] <Kontextpfad/URL/-> Hier geben wir den Namen des endgültigen Images an -t nginx:v3. Nachdem der Build erfolgreich ist, können wir dieses Image direkt ausführen und das Ergebnis ist, dass unsere Homepage in „Hello, Docker!“ geändert wird. Image-Build-Kontext Wenn Sie genau hinschauen, werden Sie feststellen, dass am Ende des Docker-Build-Befehls ein . steht. . gibt das aktuelle Verzeichnis an, und Dockerfile befindet sich im aktuellen Verzeichnis. Daher denken viele Anfänger, dass dieser Pfad den Pfad angibt, in dem sich Dockerfile befindet, was tatsächlich nicht stimmt. Wenn das obige Befehlsformat auf Sie zutrifft, stellen Sie möglicherweise fest, dass hier der Kontextpfad angegeben wird. Was ist also Kontext? Zuerst müssen wir verstehen, wie Docker Build funktioniert. Docker gliedert sich zur Laufzeit in eine Docker-Engine (also einen Server-Daemon) und Client-Tools. Die Docker-Engine bietet eine Reihe von REST-APIs, die als DockerRemote-APIs bezeichnet werden, und Client-Tools wie Docker-Befehle interagieren über diese APIs mit der Docker-Engine, um verschiedene Funktionen auszuführen. Obwohl es oberflächlich betrachtet so aussieht, als würden wir verschiedene Docker-Funktionen auf dem lokalen Computer ausführen, wird tatsächlich alles auf der Serverseite (Docker-Engine) mithilfe von Remote-Aufrufen erledigt. Aufgrund dieses C/S-Designs können wir die Docker-Engine des Remote-Servers problemlos betreiben. Wenn wir ein Image erstellen, werden nicht alle Anpassungen über den RUN-Befehl vorgenommen. Wir müssen oft einige lokale Dateien in das Image kopieren, z. B. über den COPY-Befehl, den ADD-Befehl usw. Der Befehl „Docker Build“ erstellt das Image, die Erstellung erfolgt jedoch nicht lokal, sondern serverseitig, also in der Docker-Engine. Wie kann der Server also in dieser Client/Server-Architektur auf lokale Dateien zugreifen? Dies führt das Konzept des Kontextes ein. Beim Erstellen gibt der Benutzer den Pfad zum Erstellen des Bildkontexts an. Sobald der Docker-Build-Befehl diesen Pfad kennt, verpackt er den gesamten Inhalt unter diesem Pfad und lädt ihn in die Docker-Engine hoch. Auf diese Weise erweitert die Docker-Engine dieses Kontextpaket, nachdem sie es erhalten hat, um alle zum Erstellen des Images erforderlichen Dateien zu erhalten. Wenn Sie dies in Ihr Dockerfile schreiben: KOPIEREN ./package.json /app/ Dies bedeutet nicht, dass die Datei package.json in das Verzeichnis kopiert werden soll, in dem der Docker-Build-Befehl ausgeführt wird, und auch nicht, dass die Datei package.json in das Verzeichnis kopiert werden soll, in dem sich die Docker-Datei befindet, sondern dass die Datei package.json in das Kontextverzeichnis kopiert werden soll. Daher sind die Quelldateipfade in Anweisungen wie COPY allesamt relative Pfade. Aus diesem Grund fragen Anfänger auch oft, warum COPY ../package.json /app oder COPY /opt/xxxx /app nicht funktioniert, da diese Pfade außerhalb des Kontextbereichs liegen und die Docker-Engine die Dateien an diesen Speicherorten nicht abrufen kann. Wenn Sie diese Dateien wirklich benötigen, sollten Sie sie in das Kontextverzeichnis kopieren. Jetzt können Sie den . im Befehl docker build -t nginx:v3 . verstehen. Er gibt tatsächlich das Kontextverzeichnis an. Der Befehl docker build packt den Inhalt des Verzeichnisses und übergibt ihn an die Docker-Engine, um beim Erstellen des Images zu helfen. Wenn wir die Ausgabe des Docker-Builds beobachten, können wir tatsächlich diesen Prozess des Sendens von Kontext sehen: $ docker build -t nginx:v3 . Senden des Build-Kontexts an den Docker-Daemon 2.048 kB ... Um Fehler zu vermeiden, ist es beim Erstellen von Images wichtig, den Erstellungskontext zu verstehen. Einige Anfänger stellten beispielsweise fest, dass COPY /opt/xxxx /app nicht funktionierte, und legten die Docker-Datei einfach im Stammverzeichnis der Festplatte ab, um sie zu erstellen. Als Ergebnis stellten sie fest, dass nach der Ausführung des Docker-Builds ein Ding mit Dutzenden von GB gesendet wurde, das extrem langsam war und dessen Erstellung leicht fehlschlug. Das liegt daran, dass dieser Ansatz Docker Build auffordert, die gesamte Festplatte zu packen, was offensichtlich ein Nutzungsfehler ist. Generell sollten Sie das Dockerfile in einem leeren Verzeichnis oder im Stammverzeichnis des Projekts platzieren. Falls die benötigte Datei in diesem Verzeichnis nicht vorhanden ist, sollten Sie diese kopieren. Wenn sich im Verzeichnis Dinge befinden, die Sie während des Builds wirklich nicht an die Docker-Engine übergeben möchten, können Sie eine .dockerignore-Datei mit derselben Syntax wie .gitignore schreiben. Diese Datei wird verwendet, um Dinge zu entfernen, die nicht als Kontext an die Docker-Engine übergeben werden müssen. Warum also glauben manche Leute fälschlicherweise, dass . das Verzeichnis angibt, in dem sich die Docker-Datei befindet? Dies liegt daran, dass standardmäßig, wenn Sie kein Dockerfile angeben, die Datei mit dem Namen „Dockerfile“ im Kontextverzeichnis als Dockerfile verwendet wird. Dies ist lediglich das Standardverhalten. Tatsächlich muss der Dockerfile-Dateiname nicht Dockerfile sein und muss sich nicht im Kontextverzeichnis befinden. Sie können beispielsweise den Parameter -f ../Dockerfile.php verwenden, um eine Datei als Dockerfile anzugeben. Natürlich wird normalerweise der Standarddateiname „Dockerfile“ verwendet und die Datei im Kontextverzeichnis der Image-Erstellung abgelegt. Andere Docker-Build-Verwendung Direkt aus dem Git-Repository erstellen Wie Sie vielleicht bemerkt haben, unterstützt Docker Build auch das Erstellen von einer URL. Sie können beispielsweise direkt aus einem Git-Repository erstellen: $ Docker-Build https://github.com/twang2218/gitlab-ce-zh.git#:8.14 Docker-Build https://github.com/twang2218/gitlab-ce-zh.git\#:8.14 Senden des Build-Kontexts an den Docker-Daemon 2.048 kB Schritt 1: VON gitlab/gitlab-ce:8.14.0-ce.0 8.14.0-ce.0: Abrufen von gitlab/gitlab-ce aed15891ba52: Existiert bereits 773ae8583d14: Existiert bereits ... Diese Befehlszeile gibt das für den Build erforderliche Git-Repository an und gibt den Standard-Master-Zweig und das Build-Verzeichnis als /8.14/ an. Docker führt dann ein Git-Klon des Projekts durch, wechselt zum angegebenen Zweig und gibt das angegebene Verzeichnis ein, um den Build zu starten. Mit dem angegebenen Tarball erstellen $ Docker-Build http://server/context.tar.gz Wenn die angegebene URL kein Git-Repository, sondern ein Tarball ist, lädt die Docker-Engine den Tarball herunter, dekomprimiert ihn automatisch und verwendet ihn als Kontext zum Starten des Builds. Dockerfile zum Erstellen von der Standardeingabe lesen Docker-Build - < Docker-Datei oder cat Docker-Datei | Docker-Build - Wenn eine Textdatei als Standardeingabe übergeben wird, wird sie als Docker-Datei behandelt und ein Build wird gestartet. Da diese Form den Inhalt der Docker-Datei direkt von der Standardeingabe liest, verfügt sie über keinen Kontext und kann daher nicht wie bei anderen Methoden lokale Dateien in das Image kopieren. Lesen Sie den Kontext-Tarball aus der Standardeingabe zum Erstellen $ Docker-Build -< Kontext.tar.gz Wenn das Standardeingabedateiformat gzip, bzip2 oder xz ist, wird es als kontextkomprimiertes Paket behandelt, das direkt erweitert und als Kontext zum Erstellen behandelt wird. KOPIEREN Datei kopieren <br /> Format:
Wie beim RUN-Befehl gibt es zwei Formate, eines ähnlich einer Befehlszeile und eines ähnlich einem Funktionsaufruf. Der COPY-Befehl kopiert die Dateien/Verzeichnisse unter <Quellpfad> aus dem Build-Kontextverzeichnis an den Speicherort <Zielpfad> in der neuen Ebene des Images. Zum Beispiel: KOPIEREN Sie package.json /usr/src/app/ <source path> kann mehrere oder sogar Platzhalter sein. Die Platzhalterregeln müssen den filepath.Match-Regeln von Go entsprechen, wie zum Beispiel: KOPIEREN hom* /mydir/ KOPIEREN Sie hom?.txt /mydir/ <Zielpfad> kann ein absoluter Pfad innerhalb des Containers oder ein relativer Pfad zum Arbeitsverzeichnis sein (das Arbeitsverzeichnis kann mit der Anweisung WORKDIR angegeben werden). Der Zielpfad muss nicht vorab angelegt werden. Sollte das Verzeichnis noch nicht vorhanden sein, wird es vor dem Kopieren der Dateien angelegt. Darüber hinaus ist es auch wichtig zu beachten, dass bei der Verwendung des COPY-Befehls verschiedene Metadaten der Quelldatei erhalten bleiben. Beispielsweise Lese-, Schreib-, Ausführungsberechtigungen, Dateiänderungszeit usw. Diese Funktion ist für die Bildanpassung nützlich. Dies gilt insbesondere, wenn Build-bezogene Dateien mit Git verwaltet werden. ADD Erweitertes Kopieren von Dateien Das Format und die Eigenschaften der ADD-Anweisungen und von COPY sind grundsätzlich identisch. Es werden jedoch einige Funktionen basierend auf COPY hinzugefügt. Beispielsweise kann <Quellpfad> eine URL sein. In diesem Fall versucht die Docker-Engine, die Datei dieses Links herunterzuladen und in <Zielpfad> abzulegen. Die Dateiberechtigungen werden nach dem Herunterladen automatisch auf 600 gesetzt. Wenn dies nicht die gewünschte Berechtigung ist, müssen Sie eine zusätzliche Ebene von RUN hinzufügen, um die Berechtigungen anzupassen. Wenn die heruntergeladene Datei ein komprimiertes Paket ist und dekomprimiert werden muss, ist außerdem eine zusätzliche Ebene von RUN-Anweisungen erforderlich, um sie zu dekomprimieren. Daher ist es sinnvoller, den RUN-Befehl direkt zu verwenden und dann die Tools wget oder curl zum Herunterladen, Verwalten der Berechtigungen, Dekomprimieren und anschließenden Bereinigen nicht benötigter Dateien zu nutzen. Daher ist diese Funktion nicht praktikabel und wird nicht empfohlen. Wenn <Quellpfad> eine mit TAR komprimierte Datei ist und das Komprimierungsformat gzip, bzip2 oder xz ist, dekomprimiert der Befehl ADD die komprimierte Datei automatisch in <Zielpfad>. In einigen Fällen ist diese automatische Dekomprimierungsfunktion sehr nützlich, beispielsweise im offiziellen Ubuntu-Image: VON Grund auf HINZUFÜGEN ubuntu-xenial-core-cloudimg-amd64-root.tar.gz / ... Wenn wir in manchen Fällen jedoch wirklich eine komprimierte Datei dorthin kopieren möchten, ohne sie zu dekomprimieren, können wir den Befehl ADD nicht verwenden. Das offizielle Best-Practice-Dokument zu Dockerfile von Docker erfordert, dass wann immer möglich COPY verwendet wird, da die Semantik von COPY sehr klar ist und lediglich das Kopieren von Dateien beinhaltet, während ADD komplexere Funktionen umfasst und sein Verhalten möglicherweise nicht ganz klar ist. Der beste Anlass zum Einsatz von ADD sind die genannten Gelegenheiten, bei denen eine automatische Dekomprimierung erforderlich ist. Beachten Sie auch, dass der ADD-Befehl den Image-Build-Cache ungültig macht, was den Image-Build verlangsamen kann. Daher können Sie bei der Wahl zwischen den Anweisungen COPY und ADD diesem Prinzip folgen: Verwenden Sie die Anweisung COPY für alle Dateikopien und verwenden Sie ADD nur, wenn eine automatische Dekomprimierung erforderlich ist. CMD-Container-Startbefehl Das Format des CMD-Befehls ähnelt dem von RUN und verfügt ebenfalls über zwei Formate:
Bei der Einführung von Containern habe ich zuvor gesagt, dass Docker keine virtuelle Maschine ist, sondern ein Container ein Prozess. Da es sich um einen Prozess handelt, müssen Sie beim Starten des Containers das auszuführende Programm und die Parameter angeben. Mit der CMD-Anweisung wird der Startbefehl des Standard-Containerhauptprozesses angegeben. Zur Laufzeit können Sie einen neuen Befehl angeben, um den Standardbefehl in den Image-Einstellungen zu ersetzen. Beispielsweise lautet die Standard-CMD des Ubuntu-Images /bin/bash. Wenn wir docker run -it ubuntu direkt ausführen, geben wir direkt bash ein. Wir können auch andere Befehle angeben, die zur Laufzeit ausgeführt werden sollen, wie z. B. „docker run -it ubuntu cat /etc/os-release“. Dadurch wird der Standardbefehl /bin/bash durch den Befehl cat /etc/os-release ersetzt, der die Systemversionsinformationen ausgibt. In Bezug auf das Befehlsformat wird im Allgemeinen empfohlen, das Exec-Format zu verwenden. Dieses Format wird beim Parsen als JSON-Array analysiert. Verwenden Sie daher unbedingt doppelte Anführungszeichen " anstelle von einfachen Anführungszeichen. Wenn das Shell-Format verwendet wird, wird der eigentliche Befehl als Parameter von sh -c gepackt und ausgeführt. Zum Beispiel: CMD echo $HOME Bei der tatsächlichen Implementierung wird es wie folgt geändert: CMD [ "sh", "-c", "echo $HOME" ] Aus diesem Grund können wir Umgebungsvariablen verwenden, da diese Umgebungsvariablen von der Shell analysiert werden. Wenn wir über CMD sprechen, müssen wir das Problem der Vordergrund- und Hintergrundausführung von Anwendungen in Containern erwähnen. Anfänger verwechseln dies häufig. Docker ist keine virtuelle Maschine. Anwendungen im Container sollten im Vordergrund ausgeführt werden, anstatt Upstart/Systemd zu verwenden, um Hintergrunddienste zu starten, wie in virtuellen und physischen Maschinen. Im Container gibt es kein Konzept für Hintergrunddienste. Anfänger schreiben CMD normalerweise so: CMD-Dienst nginx starten Dann wurde festgestellt, dass der Container unmittelbar nach der Ausführung beendet wurde. Auch bei Verwendung des systemctl-Befehls im Container stellt sich heraus, dass dieser gar nicht ausgeführt werden kann. Dies liegt daran, dass sie die Konzepte von Vordergrund und Hintergrund nicht verstehen, die Unterschiede zwischen Containern und virtuellen Maschinen nicht erkennen und Container immer noch aus der Perspektive herkömmlicher virtueller Maschinen verstehen. Bei einem Container ist sein Startprogramm der Containeranwendungsprozess. Der Container existiert für den Hauptprozess. Wenn der Hauptprozess beendet wird, verliert der Container seine Existenzberechtigung und wird somit beendet. Andere Hilfsprozesse sind nichts, um das er sich kümmern muss. Wenn Sie den Befehl „service nginx start“ verwenden, möchten Sie, dass systemd den nginx-Dienst als Daemon-Prozess im Hintergrund startet. Wie bereits erwähnt, wird CMD service nginx start als CMD ["sh", "-c", "service nginxstart"] verstanden, der Hauptprozess ist also tatsächlich sh. Wenn der Befehl service nginx start endet, endet auch sh. Wenn sh als Hauptprozess beendet wird, wird der Container natürlich beendet. Der richtige Ansatz besteht darin, die ausführbare Nginx-Datei direkt auszuführen und zu verlangen, dass sie im Vordergrund läuft. Zum Beispiel: CMD ["nginx", "-g", "Daemon aus;"] EINSTIEGSPUNKT Das Format von ENTRYPOINT ist dasselbe wie das des RUN-Befehls, der in ein Exec-Format und ein Shell-Format unterteilt ist. Der Zweck von ENTRYPOINT ist derselbe wie bei CMD, nämlich die Angabe des Container-Startprogramms und der Parameter. ENTRYPOINT kann auch zur Laufzeit ersetzt werden, ist aber etwas komplizierter als CMD und muss über den Docker-Run-Parameter –entrypoint angegeben werden. Wenn ENTRYPOINT angegeben wird, ändert sich die Bedeutung von CMD. Es führt den Befehl nicht mehr direkt aus, sondern übergibt den Inhalt von CMD als Parameter an die ENTRYPOINT-Anweisung. Mit anderen Worten, wenn es tatsächlich ausgeführt wird, wird es zu: <EINSTIEGSPUNKT> "<CMD>" Warum brauchen wir also ENTRYPOINT, wenn wir CMD haben? Hat dieser <ENTRYPOINT> "<CMD>" irgendeinen Vorteil? Schauen wir uns ein paar Szenarien an. Szenario 1: Verwenden Sie das Bild wie einen Befehl Angenommen, wir benötigen einen Spiegel, um unsere aktuelle öffentliche IP zu kennen, können wir dies zunächst mit CMD erreichen: VON Ubuntu:16.04 Führen Sie apt-get update \ aus. && apt-get install -y curl \ && rm -rf /var/lib/apt/lists/* CMD [ "curl", "-s", "http://ip.cn" ] Wenn wir docker build -t myip . zum Erstellen des Images verwenden und die aktuelle öffentliche IP abfragen müssen, müssen wir nur Folgendes ausführen: $ docker run myip Aktuelle IP: 61.148.226.66 Von: Beijing Unicom Nun, es scheint, dass wir das Bild direkt als Befehl verwenden können, aber Befehle haben immer Parameter. Was ist, wenn wir Parameter hinzufügen möchten? Beispielsweise können wir aus dem obigen CMD ersehen, dass der eigentliche Befehl curl ist. Wenn wir HTTP-Header-Informationen anzeigen möchten, müssen wir den Parameter -i hinzufügen. Können wir also einfach den Parameter -i zu Docker Run Myip hinzufügen? $ docker run myip -i Docker: Fehlerantwort vom Daemon: ungültiger Header-Feldwert „oci runtime error: con tainer_linux.go:247: Starten des Containerprozesses verursachte \"exec: \\\"-i\\\": ausführbare Datei Datei nicht in $PATH\"\n" gefunden. Wir sehen eine Fehlermeldung, dass die ausführbare Datei nicht gefunden werden kann, „Ausführbare Datei nicht gefunden“. Wie bereits erwähnt, folgt der Befehl dem Bildnamen, der beim Ausführen den Standardwert von CMD ersetzt. Daher ersetzt das -i hier die ursprüngliche CMD, anstatt nach dem ursprünglichen curl -s http://ip.cn hinzugefügt zu werden. Und -i ist überhaupt kein Befehl und kann daher nicht gefunden werden. Wenn wir den Parameter -i hinzufügen möchten, müssen wir den gesamten Befehl erneut eingeben: $ docker run myip curl -s http://ip.cn -i Dies ist offensichtlich keine gute Lösung und die Verwendung von ENTRYPOINT kann dieses Problem lösen. Jetzt verwenden wir erneut ENTRYPOINT, um dieses Bild zu implementieren: VON Ubuntu:16.04 Führen Sie apt-get update \ aus. && apt-get install -y curl \ && rm -rf /var/lib/apt/lists/* EINSTIEGSPUNKT [ "curl", "-s", "http://ip.cn" ] Dieses Mal versuchen wir, docker run myip -i direkt zu verwenden: $ docker run myip Aktuelle IP: 61.148.226.66 Von: Beijing Unicom $ docker run myip -i HTTP/1.1 200 OK Server: nginx/1.8.0 Datum: Dienstag, 22. November 2016, 05:12:40 GMT Inhaltstyp: text/html; Zeichensatz=UTF-8 Variieren: Accept-Encoding X-Powered-By: PHP/5.6.24-1~dotdeb+7.1 X-Cache: MISS aus Cache-2 X-Cache-Lookup: MISS aus Cache-2:80 X-Cache: MISS von Proxy-2_6 Übertragungskodierung: chunked Über: 1.1 Cache-2:80, 1.1 Proxy-2_6:8006 Verbindung: Keep-Alive Aktuelle IP: 61.148.226.66 Von: Beijing Unicom Wie Sie sehen, war es dieses Mal erfolgreich. Dies liegt daran, dass, wenn ENTRYPOINT vorhanden ist, der Inhalt von CMD als Parameter an ENTRYPOINT übergeben wird und hier -i das neue CMD ist, sodass es als Parameter an curl übergeben wird, wodurch der gewünschte Effekt erzielt wird. Szenario 2: Vorbereitung vor dem Ausführen der Anwendung Das Starten eines Containers bedeutet, den Hauptprozess zu starten. Manchmal sind jedoch vor dem Starten des Hauptprozesses einige Vorbereitungen erforderlich. Beispielsweise kann für eine Datenbank wie MySQL einige Konfigurations- und Initialisierungsarbeiten erforderlich sein, die abgeschlossen werden müssen, bevor der endgültige MySQL-Server ausgeführt wird. Darüber hinaus möchten Sie möglicherweise aus Sicherheitsgründen den Dienst nicht als Root-Benutzer starten. Bevor Sie den Dienst starten, müssen Sie einige notwendige Vorbereitungen als Root-Benutzer treffen und schließlich zum Dienstbenutzer wechseln, um den Dienst zu starten. Alternativ können neben den Diensten auch noch andere Befehle unter Verwendung der Root-Identität ausgeführt werden, um beispielsweise das Debuggen zu erleichtern. Diese Vorbereitungen haben nichts mit dem Container-CMD zu tun. Unabhängig davon, was das CMD ist, muss im Voraus eine Vorverarbeitungsaufgabe ausgeführt werden. In diesem Fall können Sie ein Skript schreiben und es zur Ausführung in ENTRYPOINT einfügen. Das Skript erhält die Parameter (d. h. ) als Befehle und führt sie am Ende des Skripts aus. Dies wird beispielsweise im offiziellen Redis-Image durchgeführt: VON alpin:3.4 ... FÜHREN Sie addgroup -S redis && adduser -S -G redis redis aus ... EINSTIEGSPUNKT ["docker-entrypoint.sh"] EXPOSE 6379 CMD [ "Redis-Server"] Sie können sehen, dass ein Redis-Benutzer für den Redis-Dienst erstellt wird und der ENTRYPOINT am Ende als Skript dockerentrypoint.sh angegeben wird. #!/bin/sh ... # Erlaube den Start des Containers mit `--user` wenn [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; dann chown -R redis. exec su-exec redis "$0" "$@" fi Ausführung "$@" Der Inhalt des Skripts wird basierend auf dem Inhalt von CMD bestimmt. Wenn es sich um einen Redis-Server handelt, wechselt es zur Redis-Benutzeridentität, um den Server zu starten. Andernfalls wird zur Ausführung weiterhin die Root-Identität verwendet. Zum Beispiel: $ docker run -it Redis-ID uid=0(Wurzel) gid=0(Wurzel) Gruppen=0(Wurzel) ENV legt Umgebungsvariablen fest Es gibt zwei Formate:
Dieser Befehl ist sehr einfach, er legt nur die Umgebungsvariablen fest. Unabhängig davon, ob es sich um andere nachfolgende Befehle wie RUN oder Anwendungen zur Laufzeit handelt, können Sie die hier definierten Umgebungsvariablen direkt verwenden. ENV VERSION=1.0 DEBUG=ein \ NAME="Glückliche Füße" Dieses Beispiel demonstriert, wie Zeilen umbrochen und Werte, die Leerzeichen enthalten, in Anführungszeichen gesetzt werden, was mit dem Verhalten unter der Shell übereinstimmt. Sobald die Umgebungsvariable definiert ist, kann sie in nachfolgenden Anweisungen verwendet werden. Beispielsweise gibt es im offiziellen Dockerfile des Node-Images einen Code ähnlich diesem: ENV NODE_VERSION 7.2.0 FÜHREN SIE curl -SLO aus "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.ta r.xz" \ && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \ && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ && grep " node-v$NODE_VERSION-linux-x64.tar.xz\$" SHASUMS256.txt | sha256sum -c - \ && tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=1 \ && rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \ && ln -s /usr/local/bin/node /usr/local/bin/nodejs Hier wird zuerst die Umgebungsvariable NODE_VERSION definiert und dann in der RUN-Ebene wird $NODE_VERSION mehrmals verwendet, um Vorgänge anzupassen. Wie Sie sehen, müssen Sie bei zukünftigen Upgrades der Image-Build-Version nur 7.2.0 aktualisieren, was die Wartung des Dockerfile-Builds vereinfacht. Die folgenden Anweisungen unterstützen die Erweiterung von Umgebungsvariablen: Anhand dieser Befehlsliste können Sie erkennen, dass Umgebungsvariablen an vielen Stellen verwendet werden können und sehr leistungsstark sind. Durch Umgebungsvariablen können wir eine Docker-Datei verwenden, um durch Verwendung verschiedener Umgebungsvariablen mehrere Images zu erstellen. ARG-Build-Parameter Format: ARG <Parametername>[=<Standardwert>] Build-Parameter haben dieselbe Wirkung wie ENV, beide legen Umgebungsvariablen fest. Der Unterschied besteht darin, dass die Umgebungsvariablen der von ARG festgelegten Build-Umgebung bei künftiger Ausführung des Containers nicht mehr vorhanden sind. Verwenden Sie ARG jedoch nicht zum Speichern von Informationen wie Passwörtern, da im Docker-Verlauf weiterhin alle Werte angezeigt werden. Die ARG-Anweisung in einer Docker-Datei definiert den Parameternamen und seinen Standardwert. Dieser Standardwert kann im Build-Befehl „Docker Build“ mit –build-arg <Parametername>=<Wert> überschrieben werden. In Versionen vor 1.13 muss der Parametername in --build-arg im Dockerfile mit ARG definiert worden sein. Mit anderen Worten muss der durch --build-arg angegebene Parameter im Dockerfile verwendet werden. Wenn der entsprechende Parameter nicht verwendet wird, wird ein Fehler gemeldet und der Build wird beendet. Ab 1.13 wurde diese strikte Einschränkung gelockert. Anstatt mit einem Fehler zu beenden, wird eine Warnmeldung angezeigt und der Build wird fortgesetzt. Dies ist hilfreich, wenn Sie ein CI-System verwenden, um verschiedene Dockerfiles mit demselben Build-Prozess zu erstellen, da so die Notwendigkeit vermieden wird, den Build-Befehl basierend auf dem Inhalt der einzelnen Dockerfiles zu ändern. VOLUME definiert anonyme Datenträger Das Format ist:
Wie bereits erwähnt, sollte die Speicherschicht des Containers bei laufendem Container so weit wie möglich frei von Schreibvorgängen gehalten werden. Bei Datenbankanwendungen, die dynamische Daten speichern müssen, sollten die Datenbankdateien in Volumes gespeichert werden. Um zu verhindern, dass Benutzer vergessen, das Verzeichnis, in dem dynamische Dateien gespeichert sind, zur Laufzeit als Volume bereitzustellen, können wir im Dockerfile vorab bestimmte Verzeichnisse angeben, die als anonyme Volumes bereitgestellt werden sollen. Auf diese Weise kann die Anwendung auch dann normal ausgeführt werden, wenn der Benutzer die Bereitstellung zur Laufzeit nicht angibt, ohne eine große Datenmenge in die Containerspeicherschicht zu schreiben. VOLUME /Daten Das Verzeichnis /data wird hier zur Laufzeit automatisch als anonymes Volume gemountet, und alle in /data geschriebenen Informationen werden nicht in der Containerspeicherschicht aufgezeichnet, wodurch die Zustandslosigkeit der Containerspeicherschicht sichergestellt wird. Natürlich kann diese Mount-Einstellung zur Laufzeit überschrieben werden. Zum Beispiel: docker run -d -v meineDaten:/Daten xxxx In dieser Befehlszeile wird das benannte Volume mydata am Speicherort /data bereitgestellt und ersetzt die im Dockerfile definierte anonyme Volume-Einbindungskonfiguration. EXPOSE deklariert einen Port Das Format ist EXPOSE <Port1> [<Port2>...]. Die EXPOSE-Anweisung deklariert den vom Laufzeitcontainer bereitgestellten Service-Port. Dies ist nur eine Deklaration. Aufgrund dieser Deklaration öffnet die Anwendung den Service dieses Ports zur Laufzeit nicht. Das Schreiben einer solchen Anweisung in die Docker-Datei hat zwei Vorteile. Einer davon ist, dass es Image-Benutzern hilft, den Daemon-Port des Image-Dienstes zu verstehen, um die Konfigurationszuordnung zu erleichtern. Der andere Vorteil besteht darin, dass bei Verwendung der zufälligen Portzuordnung zur Laufzeit, d. h. wenn docker run -P verwendet wird, der EXPOSE-Port automatisch zufällig zugeordnet wird. Darüber hinaus gibt es eine spezielle Verwendung in frühen Docker-Versionen. Zuvor liefen alle Container im Standard-Bridge-Netzwerk, sodass alle Container direkt aufeinander zugreifen konnten, was bestimmte Sicherheitsprobleme mit sich brachte. Daher gibt es einen Docker-Engine-Parameter --icc=false. Wenn dieser Parameter angegeben ist, können Container standardmäßig nicht aufeinander zugreifen, es sei denn, die Container verwenden den Parameter --links, um miteinander zu kommunizieren, und es kann nur auf die von EXPOSE im Image deklarierten Ports zugegriffen werden. Die Verwendung von --icc=false wird nach der Einführung des Docker-Netzwerks grundsätzlich nicht mehr verwendet. Durch benutzerdefinierte Netzwerke ist es einfach, eine Verbindung und Isolierung zwischen Containern zu erreichen. Unterscheidung von Expose von der Verwendung von -p <Host -Port>: <Containerport> zur Laufzeit. -P enthält den Host -Port und den Containerport. WorkDir Gibt das Arbeitsverzeichnis an Das Format ist WorkDir <Working Directory Path>. Verwenden Sie den Befehl workDir, um das Arbeitsverzeichnis (oder das aktuelle Verzeichnis) anzugeben. Wie bereits erwähnt, besteht ein häufiger Fehler einiger Anfänger, Dockerfile zu schreiben, als wäre es ein Shell -Skript. Führen Sie den Befehl cd /app aus. Rennen Sie Echo "Hallo"> World.txt Wenn Sie das Bild mit dieser Dockerfile erstellen und es ausführen, werden Sie feststellen, dass die Datei /app/world.txt nicht gefunden werden kann oder der Inhalt nicht Hallo ist. Der Grund ist tatsächlich sehr einfach. Dies ist ein Fehler, der durch das Nichtverständnis des Konzepts des geschichteten Speichers in Dockerfile verursacht wird. Wie bereits erwähnt, startet jeder Lauf einen Container, führt Befehle aus und begeht dann die Änderungen der Speicherschichtdatei. Die Ausführung der ersten Stufe RunCD /App ändert nur das Arbeitsverzeichnis des aktuellen Prozesses, nur eine Speicheränderung und führt nicht zu Änderungen der Datei. Wenn es um die zweite Ebene geht, wird ein brandneuer Container gestartet, der nichts mit dem Container der ersten Schicht zu tun hat. Wenn Sie den Standort des Arbeitsverzeichnisses auf jeder nachfolgenden Ebene ändern müssen, sollten Sie den WorkDir -Anweisungen verwenden. Der Benutzer gibt den aktuellen Benutzer an Format: User <Bustername> Die Benutzerrichtlinie ähnelt WorkDir, da sie den Umgebungszustand ändert und nachfolgende Ebenen betrifft. WorkDir ändert das Arbeitsverzeichnis und der Benutzer ändert die Identität der nachfolgenden Ebenen, die Befehle wie Ausführen, CMD und Einstiegspunkt ausführen. Wie bei WorkDir hilft Sie natürlich nur, zu einem bestimmten Benutzer zu wechseln. FÜHREN Sie groupadd -r redis && useradd -r -g redis redis aus. Benutzer Redis Rennen ["Redis-Server"] Wenn Sie die Identität eines Skripts ändern möchten, das während der Ausführung als Root ausgeführt wird, beispielsweise, wenn Sie einen Serviceprozess als etablierter Benutzer ausführen möchten, verwenden Sie keine SU oder sudo, die eine kompliziertere Konfiguration erfordern und in einer Umgebung häufig ohne TTY versagen. Es wird empfohlen, Gosu zu verwenden. # Erstellen Sie einen Redis -Benutzer und verwenden Sie GOSU, um zu einem anderen Benutzer zu wechseln, um den Befehl auszuführen. # Gosu herunterladen Führen Sie WGet -o/usr/local/bin/gosu "https://github.com/tianon/gosu/releass/download/1.7/ aus gosu-amd64 "\ && chmod +x/usr/local/bin/gosu \ \ && gosu niemand wahr # Setzen Sie CMD und führen Sie CMD als einen anderen Benutzer aus ["exec", "gosu", "redis", "redis-server"] GESUNDHEITSCHECK Format:
Die HealthCheck -Anweisung sagt Docker, wie der Status des Containers normal ist. Vor der HealthCheck -Anweisung konnte der Docker -Motor nur feststellen, ob sich der Behälter in einem abnormalen Zustand befand, indem der Hauptprozess im Behälter beendet war. Dies ist in vielen Fällen in Ordnung, aber wenn das Programm in eine Sackgasse oder eine unendliche Schleife eingeht, wird der Antragsverfahren nicht beendet, der Container kann jedoch keine Dienste mehr anbieten. Vor 1.12 erkannte Docker diesen Status des Containers nicht und plante ihn nicht, was dazu führte, dass einige Container nicht in der Lage sind, Dienste anzubieten, aber weiterhin Benutzeranfragen anzunehmen. Seit 1.12 hat Docker die HealthCheck -Anweisung zur Verfügung gestellt, die eine Befehlszeile festlegt, um festzustellen, ob der Servicestatus des Hauptprozesses des Containers immer noch normal ist, und damit realistischer den tatsächlichen Status des Containers widerspiegelt. Wenn der HealthCheck -Anweisungen in einem Bild angegeben ist, wird der Container mit dem anfänglichen Status begonnen. HealthCheck unterstützt die folgenden Optionen:
Wie CMD und Einstiegspunkt können HealthCheck nur einmal erscheinen. Der Befehl nach HealthCheck [Option] CMD hat das gleiche Format wie ein Eintragspunkt, das in das Shell -Format und das Exec -Format unterteilt werden kann. Der Rückgabewert des Befehls bestimmt, ob die Gesundheitsprüfung erfolgreich ist oder nicht: 0: Erfolg; Nehmen wir an, wir haben ein einfaches Webdienst, und wir möchten eine Gesundheitsprüfung hinzufügen, um festzustellen, ob der Webdienst ordnungsgemäß funktioniert. VON nginx Führen Sie APT -Get -Update aus && apt -Get Install -y Curl && rm -rf/var/lib/apt/lists/* HealthCheck --Interval = 5S -Timeout = 3S \ CMD CURL -FS http: // localhost/|| Exit 1 Hier setzen wir alle 5 Sekunden einen Scheck (das Intervall ist zum Zwecke des Experimentierens sehr kurz, sollte jedoch in der Realität relativ lang sein). Verwenden Sie Docker Build, um dieses Bild zu erstellen: $ Docker Build -t MyWeb: v1. Nach dem Gebäude beginnen wir einen Container: $ docker run -d -name web -p 80:80 MyWeb: v1 Nach dem Ausführen des Bildes sehen Sie den anfänglichen Status (Gesundheit: Start) über Docker Container LS: $ Docker-Container ls CONTAINER ID BILD BEFEHL ERSTELLT STATUS PORTS NAMEN 03E28EB00BD0 MyWeb: V1 "Nginx -g 'Daemon off" vor 3 Sekunden vor 2 Sekunden (Gesundheit: Start) 80/TCP, 443/TCP Web Nachdem Sie einige Sekunden lang gewartet haben, führen Sie den Docker -Container LS erneut aus und Sie werden den Gesundheitszustand ändern (gesund): $ Docker-Container ls CONTAINER ID BILD BEFEHL ERSTELLT STATUS PORTS NAMEN 03E28EB00BD0 MyWeb: V1 "Nginx -g 'Daemon off" vor 18 Sekunden Vorsprung vor 16 Sekunden (Gesundheit: gesund) 80/TCP, 443/TCP Web Wenn die Gesundheitsprüfung für mehr als die Anzahl der Wiederholungen kontinuierlich fehlschlägt, ändert sich der Status (ungesund). Um bei der Fehlerbehebung zu helfen, wird die Ausgabe der Gesundheitsprüfbefehle (sowohl stdout als auch stderr) im Gesundheitszustand gespeichert und kann mit Docker Inspect angesehen werden. $ docer inspect -format '{{json .state.Health}' upbeat_allen | { "FailingStreak": 0,, "Protokoll": [ { "Ende": "2018-06-14T04: 55: 37.477730277-04: 00", "Exitcode": 0,, "Ausgabe": "<! DocType html> \ n <html> \ n <kopf> \ n <title> Willkommen bei nginx! \ n <body> \ n <h1> Willkommen bei nginx! Br/> \ nCommercial -Unterstützung ist unter \ n <a href = \ "http: //nginx.com/ \"> nginx.com </a>. "Start": "2018-06-14t04: 55: 37.408045977-04: 00" }, { "Ende": "2018-06-14T04: 55: 42,553816257-04: 00", "Exitcode": 0,, "Ausgabe": "<! DocType html> \ n <html> \ n <kopf> \ n <title> Willkommen bei nginx! \ n <body> \ n <h1> Willkommen bei nginx! Br/> \ nCommercial -Unterstützung ist unter \ n <a href = \ "http: //nginx.com/ \"> nginx.com </a>. "Start": "2018-06-14t04: 55: 42.480940888-04: 00" }, { "Ende": "2018-06-14T04: 55: 47.631694051-04: 00", "Exitcode": 0,, "Ausgabe": "<! DocType html> \ n <html> \ n <kopf> \ n <title> Willkommen bei nginx! \ n <body> \ n <h1> Willkommen bei nginx! Br/> \ nCommercial -Unterstützung ist unter \ n <a href = \ "http: //nginx.com/ \"> nginx.com </a>. "Start": "2018-06-14t04: 55: 47.557214953-04: 00" }, { "Ende": "2018-06-14T04: 55: 52.708195002-04: 00", "Exitcode": 0,, "Ausgabe": "<! DocType html> \ n <html> \ n <kopf> \ n <title> Willkommen bei nginx! \ n <body> \ n <h1> Willkommen bei nginx! Br/> \ nCommercial -Unterstützung ist unter \ n <a href = \ "http: //nginx.com/ \"> nginx.com </a>. "Start": "2018-06-14t04: 55: 52.63499573-04: 00" }, { "Ende": "2018-06-14t04: 55: 57.795117794-04: 00", "Exitcode": 0,, "Ausgabe": "<! DocType html> \ n <html> \ n <kopf> \ n <title> Willkommen bei nginx! \ n <body> \ n <h1> Willkommen bei nginx! Br/> \ nCommercial -Unterstützung ist unter \ n <a href = \ "http: //nginx.com/ \"> nginx.com </a>. "Start": "2018-06-14t04: 55: 57.714289056-04: 00" } ], "Status": "gesund" } Onbuild ist ein Hochzeitskleid für andere Format: Onbuild <Andere Anweisungen>. Onbuild ist eine spezielle Anweisung, die andere Anweisungen wie Run, Kopie usw. folgen, die nicht ausgeführt werden, wenn das aktuelle Bild erstellt wird. Es wird nur ausgeführt, wenn das Bild der nächsten Ebene basierend auf dem aktuellen Bild erstellt wird. Die anderen Anweisungen in Dockerfile sind bereit, das aktuelle Bild anzupassen. Nur Onbuild ist bereit, anderen zu helfen, sich selbst anzupassen. Angenommen, wir möchten ein Bild einer in Node.js. Wir alle wissen, dass Node.js NPM für die Paketverwaltung verwendet, und alle Abhängigkeiten, Konfigurationen, Startinformationen usw. werden in die Datei package.json platziert. Nachdem Sie den Programmcode erhalten haben, müssen Sie zuerst die NPM -Installation durchführen, um alle erforderlichen Abhängigkeiten zu erhalten. Dann können Sie die Anwendung über NPM -Start starten. Daher wird eine Dockerfile normalerweise so geschrieben: Vom Knoten: Slim Mkdir /App ausführen ARBEITSVERZEICHNIS /app Kopieren ./package.json /App Rennen ["npm", "install"] KOPIEREN ./app/ CMD [ "npm", "start" ] Setzen Sie diese Dockerfile in das Stammverzeichnis des Node.js -Projekts. Aber was ist, wenn wir ein zweites Node.js -Projekt haben, das etwas Ähnliches tut? OK, dann kopieren Sie diese Dockerfile in das zweite Projekt. Was ist, wenn es ein drittes Projekt gibt? Kopieren Sie es noch einmal? Je mehr Kopien einer Datei es gibt, desto schwieriger ist es, ihre Versionen zu kontrollieren. Wenn während der Entwicklung des ersten Node.js -Projekts ein Problem in der Dockerfile gefunden wird, z. B. ein Tippfehler oder die Notwendigkeit, zusätzliche Pakete zu installieren, kann der Entwickler die Dockerfile beheben und erneut erstellen, und das Problem wird gelöst. Das erste Projekt ist in Ordnung, aber was ist mit dem zweiten? Obwohl die ursprüngliche Dockerfile aus dem ersten Projekt kopiert und eingefügt wurde, wird das Dockerfile des zweiten Projekts nicht automatisch behoben. Können wir also ein Basisbild erstellen und dann verwendet jedes Projekt dieses Basisbild? Wenn das Basisbild aktualisiert wird, muss jedes Projekt die Änderungen in Dockerfile nicht synchronisieren und die Aktualisierungen des Basisbildes nach dem Wiederaufbau erben? Okay, okay, lass uns die Ergebnisse wie diese sehen. Dann wird die obige Dockerfile: Vom Knoten: Slim Mkdir /App ausführen ARBEITSVERZEICHNIS /app CMD [ "npm", "start" ] Hier nehmen wir die Projektanweisungen im Zusammenhang mit dem Projekt aus und setzen sie in das Unterprojekt ein. Unter der Annahme, dass der Name dieses Basisbildes Mynode ist, wird die Dockerfile in jedem Projekt: Vom My-Node Kopieren ./package.json /App Rennen ["npm", "install"] KOPIEREN ./app/ Wenn sich das Basisbild ändert, verwendet jedes Projekt diese Dockerfile, um das Bild wieder aufzubauen und die Aktualisierungen des Basisbildes zu erben. Ist das Problem gelöst? NEIN. Um genau zu sein, wurde nur die Hälfte des Problems gelöst. Was ist, wenn etwas in dieser Dockerfile angepasst werden muss? Zum Beispiel erfordert die NPM -Installation einige Parameter. Was soll ich tun? Es ist unmöglich, diese Linie des Basisbildes zu rennen, da es die ./Package.json des aktuellen Projekts beinhaltet. Daher löst das Erstellen eines Grundbildes auf diese Weise nur das Problem der Änderungen in den ersten vier Anweisungen der ursprünglichen Dockerfile, während Änderungen in den letzten drei Anweisungen überhaupt nicht behandelt werden können. Onbuild kann dieses Problem lösen. Schreiben wir die Dockerfile des Basisbildes mit Onbuild neu: Vom Knoten: Slim Mkdir /App ausführen ARBEITSVERZEICHNIS /app Onbuild Copy ./Package.json /App Onbuild run ["npm", "install"] Onbuild Copy ./App/ CMD [ "npm", "start" ] Diesmal kehren wir zum ursprünglichen Dockerfile zurück, fügen Sie diesmal jedoch die Anweisungen im Zusammenhang mit den Projekten hinzu, damit diese drei Zeilen beim Erstellen des Basisbildes nicht ausgeführt werden. Dann wird die Dockerfile für jedes Projekt einfach: Vom My-Node Ja, das ist die einzige Zeile. Wenn Sie dieses One-Line-Dockerfile verwenden, um in jedem Projektverzeichnis ein Bild zu erstellen, werden die drei Onbuild-Zeilen des vorherigen Basisbildes ausgeführt, den Code des aktuellen Projekts erfolgreich in das Bild kopieren und die NPM-Installation für dieses Projekt ausführen, um ein Anwendungsbild zu generieren. Referenz: https://github.com/yeasy/docker_practice Das Obige ist der vollständige Inhalt dieses Artikels. Ich hoffe, er wird für jedermanns Studium hilfreich sein. Ich hoffe auch, dass jeder 123WORDPRESS.COM unterstützen wird. Das könnte Sie auch interessieren:
|
<<: So verarbeiten Sie lokal dynamisch geladene Bilder in Vue
>>: SSM implementiert die Chiffretext-Anmeldefunktion für das Kennwort des MySQL-Datenbankkontos
Der gesamte Inhalt dieses Blogs ist unter Creativ...
Dieser Artikel darf gerne geteilt und zusammengef...
Inhaltsverzeichnis 1. So funktioniert das Bootstr...
Inhaltsverzeichnis Vorwort Einführung Live Einfac...
——Anmerkungen aus „MySQL in einfachen Worten (zwe...
Was ist der Zweck der Erstellung einer eigenen Web...
Der Interviewer wird Sie manchmal fragen: „Sagen ...
Inhaltsverzeichnis Vorwort 1. So schreiben Sie Fu...
Im Allgemeinen verwenden wir nach dem Start des C...
Inhaltsverzeichnis 1. Vorbereitung 2. Einführung ...
Dieser Artikel stellt hauptsächlich die Wirkung d...
Wenn Sie nach Inspiration für spaltenbasiertes Web...
Inhaltsverzeichnis 1. Wirkungsdiagramm (mehrere S...
glibc ist die von GNU veröffentlichte libc-Biblio...
Inhaltsverzeichnis 1. Gebrauchsanweisung 2. Vorbe...