So erzwingen Sie Docker für einen sauberen Build eines Images

816

Ich habe ein Docker-Image aus einer Docker-Datei mit dem folgenden Befehl erstellt.

$ docker build -t u12_core -f u12_core .

Wenn ich versuche, es mit demselben Befehl neu zu erstellen, wird der Build-Cache wie folgt verwendet:

Step 1 : FROM ubuntu:12.04
 ---> eb965dfb09d2
Step 2 : MAINTAINER Pavan Gupta <[email protected]>
 ---> Using cache
 ---> 4354ccf9dcd8
Step 3 : RUN apt-get update
 ---> Using cache
 ---> bcbca2fcf204
Step 4 : RUN apt-get install -y openjdk-7-jdk
 ---> Using cache
 ---> 103f1a261d44
Step 5 : RUN apt-get install -y openssh-server
 ---> Using cache
 ---> dde41f8d0904
Step 6 : RUN apt-get install -y git-core
 ---> Using cache
 ---> 9be002f08b6a
Step 7 : RUN apt-get install -y build-essential
 ---> Using cache
 ---> a752fd73a698
Step 8 : RUN apt-get install -y logrotate
 ---> Using cache
 ---> 93bca09b509d
Step 9 : RUN apt-get install -y lsb-release
 ---> Using cache
 ---> fd4d10cf18bc
Step 10 : RUN mkdir /var/run/sshd
 ---> Using cache
 ---> 63b4ecc39ff0
Step 11 : RUN echo 'root:root' | chpasswd
 ---> Using cache
 ---> 9532e31518a6
Step 12 : RUN sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config
 ---> Using cache
 ---> 47d1660bd544
Step 13 : RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
 ---> Using cache
 ---> d1f97f1c52f7
Step 14 : RUN wget -O aerospike.tgz 'http://aerospike.com/download/server/latest/artifact/ubuntu12'
 ---> Using cache
 ---> bd7dde7a98b9
Step 15 : RUN tar -xvf aerospike.tgz
 ---> Using cache
 ---> 54adaa09921f
Step 16 : RUN dpkg -i aerospike-server-community-*/*.deb
 ---> Using cache
 ---> 11aba013eea5
Step 17 : EXPOSE 22 3000 3001 3002 3003
 ---> Using cache
 ---> e33aaa78a931
Step 18 : CMD /usr/sbin/sshd -D
 ---> Using cache
 ---> 25f5fe70fa84
Successfully built 25f5fe70fa84

Der Cache zeigt an, dass Aerospike installiert ist. Ich finde es jedoch nicht in Containern, die aus diesem Image hervorgehen. Daher möchte ich dieses Image neu erstellen, ohne den Cache zu verwenden. Wie kann ich Docker zwingen, ein sauberes Image ohne Cache neu zu erstellen?

Pavan Gupta
quelle
10
Nebenbei sollten Sie generell versuchen, die Anzahl der RUNAnweisungen zu minimieren .
Tripleee
4
@tripleee Kannst du erklären warum?
Ja.
9
@Ya. Früher hat Docker für jede RUNDirektive immer eine eigene Ebene erstellt , sodass eine Dockerfilemit vielen RUNDirektiven enorm viel Speicherplatz beansprucht. Dies wurde jedoch in den letzten Versionen anscheinend etwas verbessert.
Tripleee
Wenn ich es versuche docker-compose up -d, wo kann ich es verwenden --no-cache?
Oo
@Oo das ist nicht möglich. Sie müssen zuerst tun docker-compose build --no-cacheund danndocker-compose up -d
Martin Melka

Antworten:

1443

Es gibt eine --no-cacheOption:

docker build --no-cache -t u12_core -f u12_core .

In älteren Versionen von Docker mussten Sie bestehen --no-cache=true, dies ist jedoch nicht mehr der Fall.

Assaf Lavie
quelle
89
Beachten Sie auch, dass mit --no-cachefunktioniert docker-compose build.
Blackus
42
Vielleicht möchten Sie auch verwenden --pull. Dadurch wird Docker angewiesen, die neueste Version des Basisimages abzurufen. Dies ist zusätzlich erforderlich, --no-cachewenn Sie bereits über das Basis-Image (z. B. :) verfügen ubuntu/latestund das Basis-Image seit dem letzten Abrufen aktualisiert wurde. Siehe die Dokumente hier .
Collin Krawll
2
@CollinKrawll: Die --pullOption hat den Trick für mich getan. Nur --no-cachebauen noch kaputt. Setzen Sie --pullauch ein, bauen funktioniert! Vielen Dank!
Erdős-Bacon
1
Wenn jemand Docker Build aufruft, wird dann nicht angenommen, dass er ohne Cache neu erstellen möchte? In welchem ​​Anwendungsfall möchte jemand ein Image erstellen und ein zuvor erstelltes Image verwenden? <rant> Ich habe gerade einen Tag verloren, weil ein früherer Build stillschweigend fehlgeschlagen ist, aber "erfolgreich" abgeschlossen wurde und ich das fehlerhafte Image verwendet habe, ohne zu verstehen, warum Aktualisierungen des Build-Skripts nicht funktionierten. </ rant>
Jeff
3
@Jeff Wenn Sie ein Docker-Image entwickeln, werden beim Docker-Build nur geänderte Ebenen / Schritte wiederholt. Wenn ich fünf Schritte habe und einen neuen Schritt bei Index 3 hinzufüge, können die mit Schritt 1 und 2 verknüpften Ebenen wiederverwendet werden. Dies beschleunigt den Entwicklungsprozess erheblich
Flocken
130

In einigen extremen Fällen können Sie wiederkehrende Buildfehler nur ausführen, indem Sie Folgendes ausführen:

docker system prune

Der Befehl fordert Sie zur Bestätigung auf:

WARNING! This will remove:
    - all stopped containers
    - all volumes not used by at least one container
    - all networks not used by at least one container
    - all images without at least one container associated to them
Are you sure you want to continue? [y/N]

Dies ist natürlich keine direkte Antwort auf die Frage, könnte aber einige Leben retten ... Es hat meine gerettet.

Wallace Sidhrée
quelle
8
Das Hinzufügen von -a -f macht es besser
Ravi
1
@ IulianOnofrei Arbeitet für mich,Docker version 17.09.0-ce, build afdb6d4
Per Lundberg
1
@PerLundberg, ich habe dockerauf die gleiche Version aktualisiert und es funktioniert, danke.
Iulian Onofrei
1
Dies ist ein Übermaß für dieses Szenario und keine brauchbare Antwort, wenn Sie nicht alles löschen möchten.
M_dk
1
Dadurch werden sogar die Bilder angehaltener Container gelöscht, was Sie wahrscheinlich nicht möchten. Neuere Versionen von Docker verfügen über den Befehl docker builder prunezum Löschen der zwischengespeicherten Build-Layer. Bin gerade in die Falle gegangen, nachdem ich blind Befehle aus dem Stapelüberlauf kopiert habe.
Böses Azrael
59

Der Befehl hat docker build --no-cache .unser ähnliches Problem gelöst.

Unsere Docker-Datei war:

RUN apt-get update
RUN apt-get -y install php5-fpm

Sollte aber gewesen sein:

RUN apt-get update && apt-get -y install php5-fpm

Um zu verhindern, dass das Update zwischengespeichert und separat installiert wird.

Siehe: Best Practices zum Schreiben von Docker-Dateien

Youniteus
quelle
10
Das "hätte sein sollen" ist irreführend. Wenn Docker feststellt, dass eine zwischengespeicherte Kopie von RUN apt-get update && apt-get -y install php5-fpmIhnen vorhanden ist, wird diese weiterhin mit dem alten Inhalt wiederverwendet.
Tripleee
10
Tatsächlich ist es immer noch sinnvoll, sich ihnen anzuschließen, da sonst, wenn Sie die Installationszeile ändern, immer noch der alte Paket-Cache verwendet wird, der häufig Probleme hat, wenn der Cache veraltet ist (normalerweise sind die Dateien 404.)
John Chadwick
19

Verwenden Sie beim Erstellen die folgenden Optionen, um sicherzustellen, dass Ihr Build vollständig neu erstellt wird, einschließlich der Überprüfung des Basisimages auf Aktualisierungen:

--no-cache - Dadurch wird die Wiederherstellung bereits verfügbarer Ebenen erzwungen

--pull - Dadurch wird ein Pull des Basisabbilds ausgelöst, auf das mit FROM verwiesen wird, um sicherzustellen, dass Sie die neueste Version erhalten haben.

Der vollständige Befehl sieht daher folgendermaßen aus:

docker build --pull --no-cache --tag myimage:version .

Für Docker-Compose stehen dieselben Optionen zur Verfügung:

docker-compose build --no-cache --pull
M_dk
quelle
13

Ich würde nicht empfehlen, --no-cachein Ihrem Fall zu verwenden.

Sie führen einige Installationen von Schritt 3 bis 9 aus (ich würde übrigens lieber einen Einzeiler verwenden), und wenn Sie nicht möchten, dass diese Schritte bei jedem Erstellen Ihres Images erneut ausgeführt werden, können Sie dies tun Ändern Sie Ihre Dockerfilemit einem vorübergehenden Schritt vor Ihrer wgetAnweisung.

Ich mache so etwas RUN ls .und ändere es auf RUN ls ./dann RUN ls ./.und so weiter für jede Änderung, die an dem Tarball vorgenommen wird, der von abgerufen wurdewget

Sie können natürlich so etwas wie RUN echo 'test1' > test && rm testdie Anzahl 'test1für jede Iteration erhöhen .

Es sieht schmutzig aus, aber meines Wissens ist es der effizienteste Weg, um weiterhin vom Cache-System von Docker zu profitieren, das Zeit spart, wenn Sie viele Ebenen haben ...

Olivier
quelle
3
Die Möglichkeit, den Cache nach einem bestimmten Zeitpunkt nicht mehr verwenden zu können, wird von vielen gefordert ( Alternativen zur Cache-Busting finden Sie unter github.com/moby/moby/issues/1996 )
leszek.hanusz
13

Mit Docker-Compose versuchen docker-compose up -d --build --force-recreate

Yash
quelle
5

Die meisten Informationen hier sind korrekt.
Hier eine Zusammenstellung von ihnen und meine Art, sie zu benutzen.

Die Idee ist, sich an den empfohlenen Ansatz zu halten (spezifisch erstellen und keine Auswirkungen auf andere gespeicherte Docker-Objekte haben) und den radikaleren Ansatz zu versuchen (nicht spezifisch erstellen und Auswirkungen auf andere gespeicherte Docker-Objekte haben), wenn dies nicht ausreicht.

Empfohlener Ansatz:

1) Erzwingen Sie die Ausführung jedes Schritts / jeder Anweisung in der Docker-Datei:

docker build --no-cache 

oder mit docker-compose build:

docker-compose build --no-cache

Wir könnten das auch mit dem upUnterbefehl kombinieren, der alle Container neu erstellt:

docker-compose build --no-cache &&
docker-compose up -d --force-recreate 

Auf diese Weise wird kein Cache verwendet, sondern für den Docker-Builder und das Basis-Image, auf das mit der FROMAnweisung verwiesen wird .

2) Löschen Sie den Docker Builder-Cache (wenn wir Buildkit verwenden, brauchen wir das sehr wahrscheinlich):

docker builder prune -af

3) Wenn wir den Cache der übergeordneten Bilder nicht verwenden möchten, können wir versuchen, sie zu löschen, z. B.:

docker image rm -f fooParentImage

In den meisten Fällen sind diese drei Dinge perfekt genug, um einen sauberen Aufbau unseres Images zu ermöglichen.
Also sollten wir versuchen, uns daran zu halten.

Radikalerer Ansatz:

In Eckfällen, in denen es den Anschein hat, dass einige Objekte im Docker-Cache während des Builds noch verwendet werden und dies wiederholbar erscheint, sollten wir versuchen, die Ursache zu verstehen, um das fehlende Teil sehr spezifisch löschen zu können. Wenn wir wirklich keine Möglichkeit finden, von Grund auf neu zu erstellen, gibt es andere Möglichkeiten, aber es ist wichtig zu bedenken, dass diese im Allgemeinen viel mehr löschen, als erforderlich ist. Daher sollten wir sie insgesamt mit Vorsicht verwenden, wenn wir uns nicht in einer lokalen / Entwicklungsumgebung befinden.

1) Entfernen Sie alle Bilder ohne mindestens einen zugehörigen Container:

docker image prune -a

2) Entfernen Sie viele weitere Dinge:

docker system prune -a

Das sagt :

WARNUNG! Dadurch wird Folgendes entfernt:
  - alle angehaltenen Container
  - Alle Netzwerke, die nicht von mindestens einem Container verwendet werden
  - alle Bilder ohne mindestens einen zugeordneten Container
  - Alle bauen Cache

Die Verwendung dieses Super-Löschbefehls reicht möglicherweise nicht aus, da er stark vom Status der Container abhängt (ausgeführt oder nicht). Wenn dieser Befehl nicht ausreicht, versuche ich sorgfältig zu überlegen, welche Docker-Container Nebenwirkungen auf unseren Docker-Build verursachen können, und zuzulassen, dass diese Container beendet werden, damit sie mit dem Befehl entfernt werden können.

davidxxx
quelle
3

Sie können den Builder-Cache mit verwalten docker builder

So bereinigen Sie den gesamten Cache ohne Eingabeaufforderung: docker builder prune -af

Shawn
quelle