Ich nehme an, Sie sind mit Docker ein wenig vertraut und kennen Grundlagen wie das Ausführen von Docker-Containern usw.
In früheren Artikeln haben wir das Aktualisieren von Docker-Containern und das Schreiben von Docker-Dateien besprochen.
Was genau ist das Ändern eines Docker-Images?
Ein Container-Image ist in Schichten aufgebaut (oder es ist eine Sammlung von Schichten), jede Dockerfile-Anweisung erstellt eine Schicht des Bildes. Betrachten Sie beispielsweise die folgende Dockerfile:
FROM alpine:latest
RUN apk add --no-cache python3
ENTRYPOINT ["python3", "-c", "print('Hello World')"]
Da es insgesamt drei Dockerfile-Befehle gibt, enthält das aus dieser Dockerfile erstellte Image insgesamt drei Ebenen.
Sie können dies bestätigen, indem Sie das Bild erstellen:
docker image built -t dummy:0.1 .
Und dann mit dem Befehl docker image history
auf dem erstellten Image.
articles/Modify a Docker Image on modify-docker-images [?] took 12s
❯ docker image history dummy:0.1
IMAGE CREATED CREATED BY SIZE COMMENT
b997f897c2db 10 seconds ago /bin/sh -c #(nop) ENTRYPOINT ["python3" "-c… 0B
ee217b9fe4f7 10 seconds ago /bin/sh -c apk add --no-cache python3 43.6MB
28f6e2705743 35 hours ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 35 hours ago /bin/sh -c #(nop) ADD file:80bf8bd014071345b… 5.61MB
Ignorieren Sie die letzte '
Jede dieser Schichten ist schreibgeschützt. Dies ist vorteilhaft, da diese Ebenen schreibgeschützt sind und kein Prozess, der mit einer laufenden Instanz dieses Abbilds verbunden ist, in der Lage sein wird, den Inhalt dieses Abbilds zu ändern. Daher können diese Ebenen von vielen Containern gemeinsam genutzt werden, ohne dass eine Kopie für jede Instanz. Aber damit die Prozesse der Container R/W ausführen können, wird beim Erstellen der Container eine weitere Ebene zu den vorhandenen RO-Ebenen hinzugefügt, die beschreibbar ist und nicht von anderen Containern geteilt wird.
Der Nachteil dieser R/W-Ebene ist, dass Änderungen, die in dieser Ebene vorgenommen werden, nicht dauerhaft sind, obwohl Sie Volumes verwenden können, um einige Daten beizubehalten, müssen/möchten Sie manchmal eine Ebene vor einer vorhandenen Ebene hinzufügen oder eine Ebene aus einer löschen Bild oder ersetzen Sie einfach eine Ebene. Dies sind die Gründe, warum man einen bestehenden docker
ändern möchte Bild.
In diesem Artikel werde ich alle oben genannten Fälle mit verschiedenen Methoden behandeln.
Methoden zum Ändern eines Docker-Images
Es gibt zwei Möglichkeiten, wie Sie ein Docker-Image ändern können.
- Über Dockerfiles.
- Mit dem Befehl
docker container commit
.
Ich werde beide Methoden erklären und am Ende hinzufügen, welcher Anwendungsfall für die Methode im Kontext besser wäre.
Methode 1:Ändern des Docker-Image über die Dockerfile
Das Ändern eines Docker-Bildes bedeutet im Wesentlichen das Ändern der Ebenen eines Bildes. Da nun jeder Dockerfile-Befehl eine Ebene des Bildes darstellt, wird das Ändern jeder Zeile einer Dockerfile auch das entsprechende Bild ändern.
Wenn Sie also dem Bild eine Ebene hinzufügen würden, können Sie einfach eine weitere Dockerfile-Anweisung hinzufügen, um eine zu entfernen, würden Sie eine Zeile entfernen und um eine Ebene zu ändern, würden Sie die Zeile entsprechend ändern.
Es gibt zwei Möglichkeiten, wie Sie ein Dockerfile verwenden können, um ein Bild zu ändern.
- Verwenden Sie das Bild, das Sie ändern möchten, als Basisbild und erstellen Sie ein untergeordnetes Bild.
- Ändern der eigentlichen Docker-Datei des Images, das Sie ändern möchten.
Lassen Sie mich erklären, welche Methode wann und wie angewendet werden sollte.
1. Verwendung eines Bildes als Basisbild
In diesem Fall nehmen Sie das Bild, das Sie ändern möchten, und fügen Ebenen hinzu, um ein neues untergeordnetes Bild zu erstellen. Sofern ein Image nicht von Grund auf neu erstellt wird, ist jedes Image eine Modifikation desselben übergeordneten Basis-Images.
Betrachten Sie die vorherige Dockerfile. Angenommen, das Image, das aus diesem Image erstellt wird, heißt dummy:0.1
. Wenn ich jetzt denken würde, dass ich jetzt Perl anstelle von Python3 verwenden muss, um "Hello World" zu drucken, aber ich möchte Python3 auch nicht entfernen, könnte ich einfach den dummy:0.1
verwenden image als Basis-Image (da Python3 bereits vorhanden ist) und daraus wie folgt erstellen
FROM dummy:0.1
RUN apk add --no-cache perl
ENTRYPOINT ["perl", "-e", "print \"Hello World\n\""]
Hier baue ich auf dummy:0.1
auf , indem ich nach Belieben weitere Ebenen hinzufüge.
Diese Methode ist nicht sehr hilfreich, wenn Sie beabsichtigen, eine vorhandene Ebene zu ändern oder zu löschen. Dazu müssen Sie der nächsten Methode folgen.
2. Dockerfile des Bildes ändern
Da die vorhandenen Ebenen eines Images schreibgeschützt sind, können Sie sie nicht direkt über eine neue Dockerfile ändern. Mit dem FROM
Befehl in einer Docker-Datei, nehmen Sie ein Image als Basis und bauen auf auf oder fügen Sie Ebenen hinzu.
Bei einigen Aufgaben müssen wir möglicherweise eine vorhandene Ebene ändern, obwohl Sie dies mit der vorherigen Methode mit einer Reihe widersprüchlicher RUN
tun können Anweisungen (wie das Löschen von Dateien, das Entfernen/Ersetzen von Paketen, die in einer früheren Ebene hinzugefügt wurden), ist dies keine ideale Lösung oder was ich empfehlen würde. Weil es zusätzliche Ebenen hinzufügt und die Bildgröße um einiges erhöht.
Eine bessere Methode wäre, das Image nicht als Basis-Image zu verwenden, sondern die eigentliche Docker-Datei dieses Images zu ändern. Betrachten Sie noch einmal das vorherige Dockerfile. Was wäre, wenn ich Python3 nicht in diesem Image behalten und das Python3-Paket und den Befehl durch die Perl-Pakete ersetzen müsste?
Wenn ich der vorherigen Methode gefolgt wäre, hätte ich eine neue Dockerfile wie folgt erstellen müssen -
FROM dummy:0.1
RUN apk del python3 && apk add --no-cache perl
ENTRYPOINT ["perl", "-e", "print \"Hello World\n\""]
Wenn es gebaut wird, wird es in diesem Bild insgesamt fünf Ebenen geben.
articles/Modify a Docker Image on modify-docker-images [?] took 3s
❯ docker image history dummy:0.2
IMAGE CREATED CREATED BY SIZE COMMENT
2792036ddc91 10 seconds ago /bin/sh -c #(nop) ENTRYPOINT ["perl" "-e" "… 0B
b1b2ec1cf869 11 seconds ago /bin/sh -c apk del python3 && apk add --no-c… 34.6MB
ecb8694b5294 3 hours ago /bin/sh -c #(nop) ENTRYPOINT ["python3" "-c… 0B
8017025d71f9 3 hours ago /bin/sh -c apk add --no-cache python3 && … 43.6MB
28f6e2705743 38 hours ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 38 hours ago /bin/sh -c #(nop) ADD file:80bf8bd014071345b… 5.61MB
Außerdem beträgt die Größe des Bildes 83,8 MB.
articles/Modify a Docker Image on modify-docker-images [?]
❯ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
dummy 0.2 2792036ddc91 19 seconds ago 83.8MB
Anstatt das jetzt zu tun, nehmen Sie die anfängliche Docker-Datei und ändern Sie die Python3-Dateien so in Perl
FROM alpine:latest
RUN apk add --no-cache perl
ENTRYPOINT ["perl", "-e", "print \"Hello World\n\""]
Die Anzahl der Ebenen wurde auf 3 reduziert und die Größe beträgt jetzt 40,2 MB.
articles/Modify a Docker Image on modify-docker-images [?] took 3s
❯ docker image history dummy:0.3
IMAGE CREATED CREATED BY SIZE COMMENT
f35cd94c92bd 9 seconds ago /bin/sh -c #(nop) ENTRYPOINT ["perl" "-e" "… 0B
053a6a6ba221 9 seconds ago /bin/sh -c apk add --no-cache perl 34.6MB
28f6e2705743 38 hours ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 38 hours ago /bin/sh -c #(nop) ADD file:80bf8bd014071345b… 5.61MB
articles/Modify a Docker Image on modify-docker-images [?]
❯ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
dummy 0.3 f35cd94c92bd 29 seconds ago 40.2MB
Bild erfolgreich geändert.
Die vorherige Methode ist nützlicher, wenn Sie nur Ebenen über den vorhandenen hinzufügen möchten, ist jedoch nicht sehr hilfreich, wenn Sie versuchen, die vorhandenen Ebenen zu ändern, z. B. eine löschen, eine ersetzen, die vorhandenen neu anordnen und bald. Hier glänzt diese Methode.
Methode 2:Bild mit Docker-Commit ändern
Es gibt noch eine weitere Methode, mit der Sie einen Snapshot eines laufenden Containers erstellen und diesen in ein eigenes Image umwandeln können.
Lassen Sie uns einen dummy:0.1
erstellen identisches Image, aber diesmal ohne Verwendung eines Dockerfiles. Da ich alpine:latest
verwendet habe als dummy:0.1
in der Basis von , einen Container dieses Bildes hochfahren.
docker run --rm --name alpine -ti alpine ash
Fügen Sie nun im Container das Python3-Paket hinzu, apk add --no-cache python3
. Wenn Sie fertig sind, öffnen Sie ein neues Terminalfenster und führen Sie den folgenden Befehl (oder etwas Ähnliches)
docker container commit --change='ENTRYPOINT ["python3", "-c", "print(\"Hello World\")"]' alpine dummy:0.4
Mit dem --change
flag Ich füge dem neuen dummy:04
eine Dockerfile-Anweisung hinzu Bild (in diesem Fall der ENTRYPOINT
Anleitung).
Mit dem docker container commit
Befehl konvertieren Sie im Grunde die äußerste R/W-Ebene in eine R/O-Ebene, hängen diese an die Ebenen des vorhandenen Bildes an und erstellen ein neues Bild. Diese Methode ist intuitiver/interaktiver, daher möchten Sie sie möglicherweise anstelle von Dockerfiles verwenden, aber verstehen Sie, dass dies nicht sehr reproduzierbar ist. Die gleichen Regeln gelten auch für das Entfernen oder Ändern vorhandener Ebenen. Das Hinzufügen einer Ebene, nur um etwas zu entfernen oder etwas zu ändern, das in einer vorherigen Ebene gemacht wurde, ist nicht die beste Idee, zumindest in den meisten Fällen.
Damit ist dieser Artikel abgeschlossen. Ich hoffe, dieser war hilfreich für Sie, wenn Sie Fragen haben, kommentieren Sie unten.