Moby: Anforderung neuer Funktionen: Deaktivieren Sie selektiv das Caching für bestimmte RUN-Befehle in Dockerfile

Erstellt am 24. Sept. 2013  ·  245Kommentare  ·  Quelle: moby/moby

Abzweigung der Diskussion von #1384 :

Ich verstehe, dass -no-cache das Caching für das gesamte Dockerfile deaktiviert. Aber wäre es nützlich, wenn ich den Cache für einen bestimmten RUN-Befehl deaktivieren kann? Zum Beispiel das Aktualisieren von Repos oder das Herunterladen einer Remote-Datei .. usw. Nach meinem Verständnis würde RUN apt-get update, wenn es zwischengespeichert wird, das Repository nicht wirklich aktualisieren? Dadurch unterscheiden sich die Ergebnisse von denen einer VM?

Wenn das Deaktivieren des Cachings für bestimmte Befehle in der Dockerfile ermöglicht wird, würden die nachfolgenden Befehle in der Datei dann den Cache nicht verwenden? Oder würden sie etwas Intelligenteres tun - zB Cache verwenden, wenn der vorherige Befehl im Vergleich zu einem vorherigen Lauf die gleichen Ergebnisse (fs-Schicht) lieferte?

arebuilder kinfeature

Hilfreichster Kommentar

Was ist mit CACHE ON und CACHE OFF im Dockerfile? Jeder Befehl würde nachfolgende Befehle beeinflussen.

Alle 245 Kommentare

Ich denke, der Weg, dies zu bekämpfen, besteht darin, den Punkt in dem Dockerfile zu nehmen, in dem Sie zwischengespeichert werden möchten, und diesen als Image zu markieren, das in Ihrem zukünftigen Dockerfile FROM werden kann, das dann mit -no-cache ohne Konsequenz, da das Basis-Image nicht neu erstellt würde.

Aber würde dies nicht die Verschachtelung zwischengespeicherter und nicht zwischengespeicherter Befehle mit Leichtigkeit einschränken?

Nehmen wir zum Beispiel an, ich möchte meine Repository- und Wget-Dateien von einem Server aktualisieren und dazwischen eine Reihe von Schritten ausführen - z. B. Software aus dem Repository installieren (die aktualisiert werden könnte) - Operationen an der heruntergeladenen Datei ausführen (die sich in der Server) usw.

Ideal wäre eine Möglichkeit, Docker im Dockerfile anzugeben, um jedes Mal bestimmte Befehle ohne Cache auszuführen und das vorherige Image nur wiederzuverwenden, wenn keine Änderung erfolgt (zB kein Update im Repo).

Wäre das nicht sinnvoll?

Was ist mit CACHE ON und CACHE OFF im Dockerfile? Jeder Befehl würde nachfolgende Befehle beeinflussen.

Ja, ich verwende git clone Befehle in meinem Dockerfile, und wenn ich möchte, dass es mit Updates neu geklont wird, muss ich zum Beispiel einen Kommentar am Ende der Zeile hinzufügen, um einen Neuaufbau davon auszulösen Linie. Ich sollte für diesen Schritt keinen ganz neuen Basiscontainer erstellen müssen.

Kann eine Container-ID an 'docker build' als Anweisung "Nicht nach dieser ID zwischenspeichern" übergeben werden? Ähnlich wie 'docker build' alle Schritte bis zu einer geänderten Zeile in einem Dockerfile zwischenspeichert?

Ich stimme zu, dass wir eine leistungsfähigere und detailliertere Kontrolle über den Build-Cache benötigen. Derzeit bin ich mir nicht sicher, wie ich dies dem Benutzer zur Verfügung stellen soll.

Ich denke, dies wird mit den kommenden API-Erweiterungen einfacher, insbesondere bei der Benennung und Introspektion.

Wäre eine tolle Funktion. Momentan benutze ich dumme Dinge wie RUN a=a some-command , dann RUN a=b some-command um den Cache zu knacken

Eine bessere Kontrolle über den Cache würde die Verwendung von Docker von CI viel glücklicher machen.

@shykes

Wie wäre es, wenn Sie --no-cache von einem Bool in einen String ändern und eine Regex für die Stelle im Docker benötigen, an der wir den Cache sprengen möchten?

docker build --no-cache "apt-get install" .

Ich stimme zu und habe genau dieses Feature im IRC vorgeschlagen.

Abgesehen davon, dass ich denke, um die Rückwärtskompatibilität zu wahren, sollten wir ein neues Flag erstellen (sagen Sie "--uncache"), damit wir --cached als (veraltetes) bool-Flag behalten können, das in "--uncache .*" aufgelöst wird.

Am Freitag, 7. Februar 2014 um 9:17 Uhr, Michael Crosby [email protected]
schrieb:

@shykes
Wie wäre es, wenn Sie --no-cache von einem Bool in einen String ändern und eine Regex für die Stelle im Docker benötigen, an der wir den Cache sprengen möchten?

docker build --no-cache "apt-get install" .

Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an:
https://github.com/dotcloud/docker/issues/1996#issuecomment -34474686

Was denken alle anderen darüber? Hat jemand Lust, das Feature zu implementieren?

Ich bin bereit, dies heute zu implementieren, wenn noch niemand damit begonnen hat?

Ich habe angefangen, daran zu arbeiten - wollte überprüfen, ob der Ansatz gut aussieht.

  • Das Feld noCache von buildfile wird zu *regexp.Regexp .

    • Ein nil Wert dort bedeutet, was utilizeCache = true früher gemacht hat.

  • Die Übergabe eines Strings an docker build --no-cache sendet nun einen validierten Regex-String an den Server.
  • Ein Anruf von --no-cache führt zu einer Standardeinstellung von .*
  • Die Regex wird dann in einer neuen Methode buildfile.utilizeCache(cmd []string) bool , um Befehle zu überprüfen, die den Cache ignorieren

Eine Sache: Soweit ich sehen kann, unterstützt das Flag/mflag-Paket keine Zeichenfolgen-Flags ohne einen Wert, daher muss ich etwas extra herumfummeln, um sowohl --no-cache als auch --no-cache some-regex

Ich denke wirklich, dass dies eine separate neue Flagge sein sollte. Das Verhalten und die Syntax von --no-cache ist bereits gut definiert und wird an vielen, vielen Stellen von vielen verschiedenen Leuten verwendet. Ich würde für --break-cache oder etwas Ähnliches stimmen und --no-cache genau das tun lassen, was es heute tut (da dies ein sehr nützliches Verhalten ist, auf das sich viele Leute verlassen und immer noch wollen).

Wie auch immer, IANTM (ich bin nicht der Betreuer), also sind dies nur meine persönlichen Gedanken. :)

@tianon --no-cache ist derzeit bool, also erweitert dies einfach das bestehende Verhalten.

  • docker build --no-cache - gleiches Verhalten wie zuvor: ignoriert Cache
  • docker build --no-cache someRegex - ignoriert alle RUN oder ADD Befehle, die mit someRegex übereinstimmen

Stimmt, das ist alles in Ordnung. Das Problem ist, dass --no-cache ein Bool ist, also ist das vorhandene Verhalten tatsächlich:

  • --no-cache=true - Cache explizit deaktivieren
  • --no-cache=false - Cache explizit aktivieren
  • --no-cache - Abkürzung für --no-cache=true

Ich denke auch, dass wir uns selbst keinen Gefallen tun würden, wenn wir Regex-Strings mit Sonderfällen für "wahr" und "falsch" erstellen, um dieses Problem zu lösen, da dies in Zukunft für unsere Benutzer möglicherweise überraschendes Verhalten erzeugen wird. ("Wenn ich --no-cache mit einer Regex von entweder 'true' oder 'false' verwende, funktioniert es nicht wie es soll!")

@tianon ja du hast recht. Hatte einen kurzen Blick darauf und die Leute verwenden =true/false.

Ich freue PR zu ändern, um ein neues Flag hinzuzufügen, wie Sie es vorschlagen. Was denken die Betreuer ( @crosbymichael , @shykes)? Dies würde auch bedeuten, dass ich den zu mflag hinzugefügten Code entfernen könnte, um String-/Bool-Flags zuzulassen.

+1 für @wagerlabs- Ansatz

@crosbymichael , @timruffles Wäre es nicht besser, wenn der Autor des Dockerfiles entscheidet, welcher Build-Schritt zwischengespeichert werden soll und welcher nicht? Die Person, die das Dockerfile erstellt, ist nicht unbedingt dieselbe Person, die das Image erstellt. Das Verschieben der Entscheidung auf den Docker-Build-Befehl erfordert detaillierte Kenntnisse von der Person, die nur eine bestimmte Dockerdatei verwenden möchte.

Stellen Sie sich eine Unternehmensumgebung vor, in der jemand nur eine vorhandene Bildhierarchie neu aufbauen möchte, um einige Abhängigkeiten zu aktualisieren. Der vorhandene Dockerfile-Baum wurde möglicherweise vor Jahren von jemand anderem erstellt.

+1 für @wagerlabs- Ansatz

+1 für @wagerlabs- Ansatz, obwohl es noch schöner wäre, wenn es auch eine Möglichkeit gäbe, Büste auch in einem Zeitintervall zwischenzuspeichern, z

CACHE [interval | OFF]
RUN apt-get update
CACHE ON

Ich weiß, dass dies der Vorstellung widersprechen könnte, dass Container nicht deterministisch sind, aber es ist genau das, was Sie in einem kontinuierlichen Bereitstellungsszenario tun möchten, in dem Ihre Pipeline über gute automatisierte Tests verfügt.

Als Workaround erzeuge ich derzeit Cache-Buster in dem Skript, das ich zum Ausführen von Docker-Build verwende, und füge sie in der Docker-Datei hinzu, um einen Cache-Bust zu erzwingen

FROM ubuntu:13.10
ADD ./files/cachebusters/per-day /root/cachebuster
...
ADD ./files/cachebusters/per-build /root/cachebuster
RUN git clone [email protected]:cressie176/my-project.git /root/my-project

Ich möchte Container für die kontinuierliche Integration verwenden und die Möglichkeit, Timeouts für bestimmte Elemente im Cache festzulegen, wäre wirklich wertvoll. Ohne diese kann ich nicht bereitstellen. Jedes Mal einen vollständigen Neuaufbau zu erzwingen ist viel zu langsam.

Mein derzeitiger Plan, dies zu umgehen, besteht darin, Befehle wie RUN echo 2014-04-17-00:15:00 dynamisch einzufügen, wobei die generierte Zeile auf die letzten 15 Minuten abgerundet wird, um Cache-Elemente ungültig zu machen, wenn die gerundete Zahl springt. alle 15 Minuten. Das funktioniert für mich, weil ich jedes Mal ein Skript habe, das die Dockerdatei generiert, aber ohne dieses Skript funktioniert es nicht.

+1 für die Funktion.

Ich möchte auch für diese Funktion stimmen. Der Cache ist nervig, wenn Teile eines Containers aus Git-Repositories erstellt werden, die nur auf dem Master-Zweig aktualisiert werden.
:+1:

@hiroprotagonist Ein git pull in Ihrem ENTRYPOINT könnte helfen?

@amarnus Ich habe es ähnlich der Idee von @tfoote gelöst. Ich führe den Build von einem Jenkins-Job aus und anstatt den docker build-Befehl direkt auszuführen, startet der Job ein Build-Skript, das das Dockerfile aus einer Vorlage generiert und die Zeile 'RUN echo currentsMillies' über den git-Befehlen hinzufügt. Dank Sed und Pipes war dies eine Sache von Minuten. Wie auch immer, ich bevorzuge diese Funktion immer noch als Teil des Dockerfiles selbst.

Hinzufügen meines +1 für @wagerlabs- Ansatz. Habe auch dieses Problem mit CI. Ich verwende vorerst einfach eine dynamische echo RUN-Anweisung, aber ich würde diese Funktion lieben.

+1 für CACHE EIN/AUS. Mein Anwendungsfall ist auch die CI-Automatisierung.

+1, insbesondere die Möglichkeit, ein Cache-Intervall für Ausführungsbefehle festzulegen , wie im Beispiel von

"Zum Beispiel Repos aktualisieren oder eine Remote-Datei herunterladen"

+1

Wenn es jemandem hilft, hier ist der Code, den ich in meinem Jenkins-Build verwende:

echo "Using build $BUILD_NUMBER for docker cachebusting"
sed -i s/cachebust_[0-9]*/cachebust_"$BUILD_NUMBER"/g Dockerfile

+1 für CACHE EIN/AUS

Als mögliche Alternative zum CACHE ON/OFF-Ansatz, wie wäre es mit einem zusätzlichen Schlüsselwort wie "ALWAYS". Das Schlüsselwort würde in Kombination mit einem bestehenden Befehl verwendet (zB "ALWAYS RUN" oder "ALWAYS ADD"). Das Schlüsselwort "ALWAYS" wird von Entwurf nicht in den Cache verschoben, um den angrenzenden Befehl abzuschließen. Es vergleicht jedoch das Ergebnis mit dem CACHE (implizit der Cache für andere Zeiten, in denen dieselbe Zeile ausgeführt wurde) und verknüpft mit dem zwischengespeicherten Bild, wenn das Ergebnis des ALWAYS-Befehls unverändert ist.

Ich glaube, die zugrunde liegende Notwendigkeit besteht darin, "nicht-idempotente Anweisungen" zu identifizieren. Der Befehl ALWAYS tut dies sehr explizit. Mein Eindruck ist, dass der CACHE-ON/OFF-Ansatz genauso gut funktionieren könnte, aber auch viele Codeblöcke erfordern könnte (was Benutzer dazu ermutigen kann, mehr Zeilen zu blockieren als wirklich erforderlich).

Ich bin auch eher für ein Präfix zu Befehlen, wie ALWAYS oder CACHE 1 WEEK ADD ...

Ich hatte also eine Weile mit diesem Problem zu kämpfen und wollte nur meine Arbeit teilen, falls sie hilfreich ist, während dies geklärt wird. Ich wollte dem Build-Aufruf wirklich nichts außerhalb der Docker-Datei hinzufügen oder die Datei jedes Mal ändern. Wie auch immer, dies ist ein dummes Beispiel, aber es verwendet den Add-Mechanismus, um den Cache zu sprengen, und erfordert keine Dateimanipulationen.

From ubuntu:14.04

RUN apt-get -yqq update
RUN apt-get -yqq install git
RUN git clone https://github.com/coreos/fleet
ADD http://www.random.org/strings/?num=10&len=8&digits=on&upperalpha=on&loweralpha=on&unique=on&format=plain&rnd=new uuid
RUN cd fleet && git pull

Natürlich können Sie Ihren eigenen Anwendungsfall und Netzwerk-Zufallsgenerierung auswählen. Wie auch immer, vielleicht wird es einigen Leuten helfen, idk.

Noch ein +1 für @wagerlabs- Ansatz

Noch ein +1 für die Funktion. Verwenden Sie in der Zwischenzeit den Workaround von

noch ein +1 für die Funktionsanfrage. Und danke an @cruisibesarescondev für die

Noch ein +1 für die Funktion.

Cheers @cruisibesarescondev für die

Ich denke, das Schlüsselwort ALWAYS ist ein guter Ansatz, zumal es eine einfache, klare Semantik hat. Ein etwas komplizierterer Ansatz wäre, eine Mindestzeit hinzuzufügen (nützlich in Dingen wie einer Buildfarm oder einer kontinuierlichen Integration). Dafür würde ich eine Syntax "EVERY XXX" vorschlagen, wobei XXX ein Timeout ist. Und wenn der Cache dieses Befehls länger als XXX erstellt wurde, muss er den Befehl erneut ausführen. Und prüfen Sie, ob sich die Ausgabe geändert hat. Wenn keine Änderung erfolgt, verwenden Sie das zwischengespeicherte Ergebnis erneut und notieren Sie sich den Zeitpunkt der letzten Aktualisierung. Dies würde bedeuten, dass JEDE 0 gleich wäre wie IMMER.

Als Workaround generiere ich momentan meine Dockerfiles mit empy Templates in Python und bette die folgenden Snippets ein, die wie oben funktionieren, außer dass sie in zwei aufeinanderfolgenden Läufen nicht das gleiche Ergebnis erkennen, sondern alle XXX Sekunden einen Retrigger erzwingen. Oben:

@{
import time
def cache_buster(seconds):
    ts = time.time()
    return ts - ts % seconds
}@

Wo ich eine Wiederholung erzwingen möchte:

RUN echo @(cache_buster(60))

Was im Dockerfile so aussieht

RUN echo 1407705360.0

Wie Sie sehen, wird auf die nächsten 60 gerundet, so dass jedes Mal, wenn 60 Sekunden vergehen, der nächste Lauf alle folgenden Befehle wiederholt.

+1 für IMMER-Syntax. +.5 für CACHE EIN/CACHE AUS.

+1 für IMMER-Syntax.

Ja, die Syntax von ALWAYS sieht sehr intuitiv aus.

Ich mag CACHE ON/OFF nicht, weil ich denke, dass Zeilen "in sich geschlossen" sein sollten und das Hinzufügen von Blöcken zu Dockerfiles eine Menge "Probleme" mit sich bringen würde (z. .).

@kuon Ich denke, es gibt bereits eine Reihe von Befehlen, die sich auf nachfolgende Anweisungen auswirken, z. B. USER und WORKDIR

Ja, das stimmt, aber ich benutze sie nicht aus dem gleichen Grund. Ich mache immer RUN cd ... && oder RUN su -c ...&& .

Ich würde eine Blocknotation bevorzugen:

CACHE OFF {
    RUN ...
}

Dies ist expliziter und verhindert, dass versehentlich eine CACHE OFF Zeile eingefügt wird (dies würde einen Syntaxfehler auslösen).

Ich denke vielleicht zu viel darüber nach, Dockerfiles werden nicht wirklich in der Produktion ausgeführt (nur beim Erstellen des Images), sodass das Deaktivieren des Caches beim Erstellen nicht viel Schaden anrichtet. Aber ich glaube auch, dass Dockerfiles wirklich einschränkend sind (alle Befehle mit einem && in einem einzigen RUN verketten zu müssen, um zu vermeiden, dass eine Unmenge von Bildern erstellt wird und keine Variablen verwendet werden können ...).

Vielleicht ist dieses Problem die Gelegenheit für ein neues Dockerfile-Format.

Ich möchte auf das zurückkommen, was ich gerade gesagt habe. Ich habe gelesen, was @shykes in einer anderen Ausgabe https://github.com/docker/docker/pull/2266 gesagt hat, und ich stimme ihm auch zu (Dockerfile muss eine wirklich einfache Assembler-ähnliche Sprache bleiben).

Ich sagte, ich hätte gerne Variable oder ähnliches, aber das kann von einer anderen Sprache abgedeckt werden, aber in diesem Fall sollte jede Zeile in einer Dockerfile in sich geschlossen sein, zB:

NOIMAGE ALWAYS RUN USER:jon  apt-get update

Das würde immer den Befehl ausführen (kein Cache), aber auch kein Image erstellen und den Benutzer jon verwenden.

Diese Art von in sich abgeschlossenen Zeilen sind viel einfacher aus jeder anderen Sprache zu generieren. Wenn Sie sich um den Kontext (Benutzer, Cache, Arbeitsverzeichnis) kümmern müssen, ist dies fehleranfälliger.

Kann es der Einfachheit halber RUN! ?

Gibt es hierzu ein Statusupdate?

Das selektive Deaktivieren des Caches wäre sehr nützlich. Ich hole Dateien aus einem entfernten Amazon s3-Repository über den awscli-Befehl (aus dem Amazon AWS-Toolkit), und ich habe keine einfache Möglichkeit, den Cache über einen ADD-Befehl zu sprengen (zumindest fällt mir keine Möglichkeit ein, das Dockerfile zu bearbeiten auslösen). Ich glaube, es gibt gute Gründe dafür, dem Benutzer die Kontrolle zurückzugeben, um den Cache selektiv zu sprengen, wenn RUN verwendet wird. Falls jemand einen Vorschlag für mich hat, würde ich mich über eine Nachricht freuen.

Wollte dieses Thema etwas anheben, da wir einen großen Bedarf daran haben.

Immer noch überzeugt, dass die ALWAYS Syntax die ideale ist.

Wie wäre es mit einer einfachen BREAK Anweisung.

@ cpuguy83 das würde auch für meinen speziellen Anwendungsfall funktionieren.

Ich bin mir nicht sicher, ob es technisch möglich ist, nur einen Befehl nicht zwischenzuspeichern, sondern den Rest zwischenzuspeichern. Wahrscheinlich nicht, da Docker auf inkrementellen Diffs basiert.

Die Unterstützung für BREAK würde mir jedoch eine Funktionsparität mit meiner aktuellen Problemumgehung geben, basierend auf dem Vorschlag von @CheRuisiBesares.

Was meinen vorherigen Post angeht, würde es in der Tat ausreichen, den Cache ab diesem Punkt im Skript zu sprengen, der Rest wäre nur auf intelligentes Skriptdesign zurückzuführen (und ich glaube, dies würde den Anforderungen der meisten Leute gerecht werden). Ist dies machbar, anstatt den Cache-Bust selektiv zu deaktivieren?

@orrery Du ausreißen ", COPY hinzufügst. Wenn die kopierte(n) Datei(en) unterschiedlich sind, sollten alle nachfolgenden Schritte den Cache nicht mehr verwenden (siehe diesen Abschnitt ). Schmutziger Trick, kann aber Ihren Fall lösen.

Ein Schlüssel zu ALWAYS (oder ähnlichen Konzepten wie EVERY # DAYS ) ist der Cache-Vergleich nach dem angehängten Befehl. Für mich (und ich nehme an, viele andere) ist das Ziel nicht, den Cache per se zu sprengen.

  • Das Ziel ist sicherzustellen, dass wir den Cache nicht mehr verwenden, wenn sich das Ergebnis des Befehls (dh "Upgrade auf die neueste Version") ändert.
  • Wenn das Ergebnis hingegen mit einer zwischengespeicherten Version übereinstimmt, möchten wir den Cache nutzen.

Diese Adressen der Kommentar von @hellais da Sie die Vorteile der Cache für nachfolgende Befehle nehmen können ... , wenn und nur wenn die Ausgabe von ALWAYS eine im Cache gespeicherte Version entspricht (dies leicht die Mehrheit der Zeit sein könnte).

Natürlich _könnte_ dieselbe Logik in einem CACHE-ON/OFF-Modell enthalten sein. Der Vergleich mit Cache ist wahrscheinlich billiger als das erneute Ausführen aller nachfolgenden Befehle, könnte aber immer noch teuer sein. Wenn ein CACHE-ON/OFF-Block einen Benutzer dazu ermutigt, zusätzliche Befehle in einen OFF-Block einzufügen (was mit ALWAYS nicht passieren kann), könnte dies zu erheblichen Leistungsunterschieden beitragen.

Ich befinde mich in genau der gleichen Situation wie

+1 für EVERY Syntax. Die Syntax ALWAYS würde auch die Arbeit erledigen.

@claytondaley das ist ein toller Punkt. Es ist jedoch immer noch wichtig, die Zwischenspeicherung für einen Befehl vollständig deaktivieren zu können. Es wird immer einen versteckten Zustand geben, der für Docker von Natur aus unsichtbar ist. ZB kann die Ausführung eines Befehls den Zustand auf einem entfernten Server ändern.

@mkoval , Sie bringen einen guten Punkt zum _Erstellen von _ versteckten Zuständen als wichtigen Zeitpunkt für die Verwendung von ALWAYS , aber ich glaube nicht, dass dies meine Logik zum Fortsetzen des Caches beeinflusst. Um das Beispiel konkret zu machen (wenn auch etwas trivial), ein Befehl, der ein Drittanbietersystem aktualisiert:

  • Erstellt einen versteckten Zustand (muss ausgeführt werden ALWAYS ) und
  • Ändert nicht den aktuellen Container

Wenn der nächste Befehl keinen versteckten Zustand beinhaltet (trivialerweise ein mv-Befehl auf dem Container), ist der Cache 100% zuverlässig. Gleicher Container, gleicher Befehl, keine Abhängigkeit von versteckten Informationen.

Wenn der nächste Befehl (oder jeder nachfolgende Befehl) versteckte Informationen enthält, sollte er das Schlüsselwort ALWAYS und den Cache nur dann fortsetzen, wenn der resultierende Container mit dem Cache übereinstimmt.

@claytondaley deine Lösung erscheint mir sehr elegant und effizient. Ich wäre Ihnen sehr dankbar, wenn dies umgesetzt würde. :+1: :Oktopus:

+1 für diese Funktion unter Verwendung der vorgeschlagenen Syntax ALWAYS und EVERY X. CACHE ON/OFF kommt mir etwas ungeschickt vor, aber ich würde es benutzen. Ich mag auch den Vorschlag von fortzusetzen .

+1 für IMMER-Syntax. insbesondere für Pull-Codes aus Git Repo.

+1 Für jede dieser Lösungen.

Ich bin ein bisschen verwirrt. Wie kann Caching wieder aktiviert werden, wenn es deaktiviert wurde? Wenn Sie es deaktivieren und Änderungen am Container vornehmen, würden dann nicht alle Änderungen, die von den Dockerfile-Befehlen vorgenommen wurden, die bei ausgeschaltetem Caching ausgeführt wurden, durch das erneute Aktivieren des Cachings verworfen? Ich dachte, der einzige Grund, warum wir Caching durchführen könnten, war, dass wir die vollständige Liste der vorherigen ausgeführten Befehle genau kannten und garantieren konnten, dass der Container genau gleich war. Wenn Sie das Caching deaktivieren (und ich spreche von der Nachschlageseite davon), bläst das nicht diese Garantie weg? Oder wird der Cache einfach nicht gefüllt?

Mein Verständnis der Vorschläge ist, dass Sie "ALWAYS" als Teil eines Dockerfile-Befehls angeben können, um den Schritt immer erneut auszuführen. Zum Beispiel "RUN ALWAYS git clone https://example.com/myrepo.git " wird immer ausgeführt (dadurch wird immer das Repo geklont). Dann schlägt @claytondaley vor, dass Docker die Änderungen mit dem Cache

@curtiszimmerman... genau

@duglin ... Die Idee könnte offensichtlicher sein, wenn wir einen mathematischen Proxy verwenden. Cache (in diesem Kontext) ist nur eine Erinnerung an das Ergebnis von action B wenn es auf state A angewendet wird, sodass Sie es nicht erneut verarbeiten müssen. Angenommen, ich führe eine Folge von Befehlen aus:

  • beginne mit 6
  • IMMER * x ausführen, wobei der Wert von x von einem Git-Repository heruntergeladen wird (und sich daher ändern könnte)
  • + 12 run ausführen

Wenn ich den Befehl zum ersten Mal ausführe, ist x 8, sodass ich die folgende Sequenz erhalte (und zwischenspeichere):

  • 6
  • 48 (als Ergebnis von * x angewendet auf 6 )
  • 60 (als Ergebnis der Anwendung von + 12 auf 48 )

Wenn meine Maschine jemals wieder den Zustand 48 (in beliebiger Reihenfolge)... und den Befehl + 12 erhält, muss ich die Verarbeitung nicht erneut durchführen. Mein Cache weiß, dass das Ergebnis dieses Befehls 60 .

Der schwierige Teil ist, herauszufinden, wann Sie sich wieder im gleichen Zustand ( 48 ) befinden.

  • Theoretisch könnten wir die Maschine nach jedem Befehl mit jedem anderen zwischengespeicherten Bild vergleichen, aber dies ist ressourcenintensiv und hat eine sehr geringe Wahrscheinlichkeit, eine Übereinstimmung zu finden.
  • Mein Vorschlag ist es einfach zu halten. Jedes Mal, wenn wir uns in einem Zustand befinden (zB 6 ) und einen Befehl drücken (zB * x ), vergleichen wir das Ergebnis mit dem Cache von dem letzten Mal (oder den Zeiten), als wir uns im selben Zustand befanden den gleichen Befehl ausführen. Wenn der Zustand der Maschine nach diesem Vorgang derselbe ist (zB immer noch 48 ), setzen wir den Cache fort. Wenn der nächste Befehl immer noch + 12 lautet, ziehen wir das Ergebnis aus dem Cache, anstatt es zu verarbeiten.

@claytondaley, aber ich verstehe nicht, wie Sie den aktuellen Zustand bestimmen. Wie Sie sagten, vergleichen wir nicht alle Dateien im Container. Die Art und Weise, wie der Cache jetzt funktioniert, besteht darin, im Grunde nur den nächsten Befehl zu strcmp, den wir für alle bekannten untergeordneten Container des aktuellen Containers ausführen möchten. In dem Moment, in dem Sie einen Container im Fluss überspringen, kann ich nicht erkennen, wie Sie jemals davon ausgehen können, dass Ihr aktueller Container wie jeder andere zwischengespeicherte Container ist, ohne alle Dateien im Dateisystem zu überprüfen. Aber vielleicht groke ich nicht, was du tust.

Lassen Sie mich es umformulieren.... Wie können Sie bei einem zufälligen Container (der im Grunde genommen das ist, was Sie haben, wenn Sie den Cache nicht verwenden) einen Container im Cache finden, der zu ihm passt, ohne dass alle Dateien im Container?

@claytondaley @duglin Die Bestimmung, ob eine Operation "kein Cache" ohne Änderung zwischengespeichert werden kann, ist, wie Sie beschrieben haben, ein schwieriges Problem. Es ist auch eher ein Nice-to-have als unbedingt notwendig.

Persönlich wäre ich mehr als glücklich, wenn ich nur die Möglichkeit hätte, sicherzustellen, dass ein Befehl immer ausgeführt wird. Nehmen Sie ein Dockerfile wie:

RUN install_stuff_take_forever
RUN always_do_it   #will not run every time
RUN more_stuff

Derzeit wird die Zeile always_do_it nur das erste Mal ausgeführt, es sei denn, ich bearbeite den Text, um einen Cache-Bust zu erzwingen. Ich denke, die meisten von uns würden gerne akzeptieren, dass more_stuff manchmal unnötig ausgeführt wird (wenn sich always_do_it nicht geändert hat, wenn wir im Gegenzug den Cache für install_stuff_take_forever behalten können.

RUN install_stuff_take_forever
NOCACHE
RUN always_do_it
RUN more_stuff

@pikeas Ich bekomme total einen NOCACHE-Befehl und das ist einfach. Was ich nicht bekomme, ist ein Befehl, der es ohne Diffing/Hashing/was auch immer das gesamte Dateisystem wieder einschaltet.

Ich habe die "Layer"-Erklärung von Docker so gelesen, dass sie

  • Docker erstellt für jeden Befehl eine "Ebene".
  • Diese Ebene enthält nur die Dateien, die durch diesen Befehl geändert (oder möglicherweise "gespeichert" wurden, ob geändert oder unverändert).
  • Der aktuelle Zustand des Dateisystems wird logisch (wenn nicht betriebsbereit) ermittelt, indem jede Schicht der Reihe nach überprüft wird, bis eine (die zuletzt aktualisierte) Version dieser bestimmten Datei gefunden wird.

In diesem Fall ist ein Vergleich zweier Instanzen desselben Befehls relativ günstig. Sie müssen nur die oberste Ebene vergleichen (da jede darunterliegende Ebene geteilt wird). Es gibt eine bestimmte Liste von Dateien, die durch den Befehl geändert wurden. Nur diese Dateien sind in der Ebene enthalten. Zugegeben... Sie müssten alle Dateien in dieser Ebene vergleichen... aber nicht das gesamte Dateisystem.

Es ist auch möglich (obwohl nicht garantiert vollständig ist), nur die neue Ebene mit der letzten Ausführung des Befehls zu vergleichen:

  • In den meisten Fällen (git pull oder Software-Upgrade) ist die aktuelle Version entweder (1) dieselbe wie die letzten Versionen oder (2) eine neue Version ... aber nie – zumindest selten – ein Rollback auf eine vorherige Ausführung.
  • In seltenen Fällen (wie ein Upgrade auf dev-master und anschließendes Zurücksetzen auf eine stabile Version) ist es möglich, auf eine ältere Version zurückzuwechseln. Diese sind jedoch ziemlich selten, so dass die meisten Leute wahrscheinlich besser dran wären (häufig) nur die neueste Version zu überprüfen und Befehle in dem seltenen Fall, in dem sie ein Rollback durchführen, erneut auszuführen.

Natürlich können Sie auch einen Hash-Check für alle vorherigen Versionen durchführen ... gefolgt von einem vollständigen Datei-Check ... um volle Unterstützung ohne Overhead zu bieten.

Wenn Sie sich den unteren Rand von https://github.com/docker/docker/pull/9934 ansehen, sehen Sie eine Diskussion über die unterstützenden Optionen für Dockerfile-Befehle. Was wäre, wenn für alle (oder nur RUN) eine Option --no-cache verfügbar wäre, die "den Cache nicht verwenden" für diesen Befehl bedeutete? z.B:
RUN --no-cache apt-get install -y my-favorite-tool
Dies würde dann automatisch auch den Cache für die restlichen Befehle deaktivieren (glaube ich).
Würde dies das Problem lösen?

Zwischen "RUN ALWAYS" und "RUN --no-cache", die semantisch identisch sind, würde ich persönlich die natürlicher aussehende "RUN ALWAYS"-Syntax bevorzugen. Ich stimme dem letzten Kommentar zu dieser PR zu: Ich denke, --option beeinträchtigt die Lesbarkeit und macht Dockerfiles hässlich. Darüber hinaus müssen sich Dockerfile-Befehle meiner Meinung nach sehr von den tatsächlichen Befehlen unterscheiden, die ihnen folgen. Stellen Sie sich etwas wie "RUN --no-cache myapp --enable-cache" als Beispiel für eine verworrene Syntax vor, die sich mit dieser Art von Option schnell ausdrücken würde.

@curtiszimmerman dein Beispiel ist mir sehr klar. --no-cache ist für RUN, während --enable-cache für myapp ist. Die Platzierung ist wichtig. Schauen Sie sich zum Beispiel an:
docker run -ti ubuntu ls -la
Die Leute verstehen, dass -ti für 'run' steht, während '-la' für 'ls' steht. Dies ist eine Syntax, mit der die Leute wohl zu sein scheinen.
Eines der Probleme bei so etwas wie RUN ALWAYS ist die Erweiterbarkeit. Wir brauchen eine Syntax, die für alle Dockerfile-Befehle funktioniert und die Übergabe von Werten unterstützt. Zum Beispiel haben Leute ihr Interesse bekundet, den USER für bestimmte Befehle anzugeben.
RUN USER=foo myapp
setzt technisch gesehen einen env var USER auf 'foo' in der Shell von myapp. Wir sind hier also zweideutig.
Während: RUN --user=foo myapp hat dieses Problem nicht.
Ist: RUN var=foo myapp
Versuchen, eine var genannte 'var'-Datei zu setzen und zu env oder ein Tippfehler, der versucht, eine RUN-Option zu erhalten?
IOW, die Wahrscheinlichkeit, sich mit einem bestehenden gültigen Befehl, IMO, zu überschneiden, ist viel geringer, wenn wir damit beginnen – als nur ein Wort dort zuzulassen

Ich befürworte eigentlich die umgekehrte Reihenfolge, EVERY <options> COMMAND . Mehrere Gründe:

  • Im Fall von "user" und "cache" (zumindest) handelt es sich in Wirklichkeit um Umgebungsmerkmale, die jeden BEFEHL einschließen könnten (obwohl sie andere möglicherweise nicht wesentlich beeinflussen).
  • Die Syntax RUN ALWAYS bedeutet, den Befehlsinterpreter RUN ändern, was unnötig klingt.
  • Dieses Problem ist bei RUN EVERY 5 days noch schlimmer, da die an EVERY angehängten Optionen noch mehr Mehrdeutigkeit erzeugen. EVERY 5 days RUN ist sich klar über den Befehl, den die Optionen betreffen. Wir haben das gleiche Problem mit RUN USER usr vs. USER usr RUN . Solange entweder (1) Befehlsschlüsselwörter niemals Optionen sind oder (2) es eine einfache Möglichkeit gibt, sie zu umgehen, ist dies eindeutig.

Ich könnte einsteigen, indem ich den Befehlen ihre Optionen voranstelle ( ALWAYS AS user RUN ... ). Ich bin nur wirklich besorgt über die Verwendung von Longopts im GNU-Stil für Optionen, da sie sich nicht sehr von alten oder verglasten Augen unterscheiden. Ich kann mir vorstellen, wie ich auf einen komplexen Dockerfile-Befehl starre, nachdem ich mich 20 Stunden lang gewundert habe, dass wtf im Gange ist. Aber ich sage voraus, dass Optionen trotzdem passieren werden.

Aber ich sage voraus, dass Optionen trotzdem passieren werden.

Noch ist nichts entschieden, im Gegenteil; die Syntax, die @duglin vorschlägt, ist ein _Gegenvorschlag_ zu einer Syntax, die früher vorgeschlagen/beschlossen wurde. Bitte lesen Sie #9934 für weitere Informationen dazu.

Außerdem ist @duglin _nicht_ die Person, die diese Entscheidung trifft (zumindest nicht allein). Einige der Punkte, die Sie ansprechen, wurden in dem anderen Thread erwähnt.

Ich teile Ihre Bedenken hinsichtlich der Lesbarkeit, denke aber auch, dass die anderen vorgeschlagenen Syntaxen das gleiche Problem haben könnten, wenn mehrere Optionen angegeben werden müssen.

Dieses Problem kann möglicherweise behoben werden, indem das Dockerfile für die Lesbarkeit formatiert wird. Ich denke, es wäre gut, einige weitere Beispiele zu schreiben, um zu testen / zu überprüfen, ob die Lesbarkeit bei richtiger Formatierung ein Problem darstellt.

Und ja, Ihr Beitrag dazu ist willkommen.

Ich bin immer noch sehr -1 darin, das Dockerfile selbst definieren zu lassen, wo der Cache ist
sollte und darf nicht angewendet werden. Ich habe noch kein gutes Beispiel für a see gesehen
Dockerfile, das nicht richtig in Cache-Bust umgeschrieben werden konnte und
natürlich, wenn die zugrunde liegende Ressource aktualisiert werden musste.

Ein Flag auf "Docker Build" haben, um den Cache an einem bestimmten Ort zu stoppen
wäre viel flexibler, IMO (und die Kontrolle über den Cache zurückgeben
in die Hände des Systembetreibers, der diesen Cache sowieso verwalten darf).

+1 auf @tianon -1 (das ist also ein -1!), und das Hinzufügen eines Flags zum Break bei Schritt N scheint vernünftig. Wenn man bedenkt, dass der Cache, sobald er kaputt ist, sowieso für den Rest des Dockerfiles kaputt ist, halte ich dies für sinnvoll.

Dies liegt vor allem daran, dass der Caching-Mechanismus von Docker direkt mit der Speicherung und dem Transport des Images verbunden ist, was ein effizientes Caching ermöglicht, jedoch auf Kosten erheblich größerer Images geht. Also lass uns das beheben!

Ohne zu sagen, was ich von dieser Funktion halte - bin mir noch nicht sicher, um ehrlich zu sein - wie stellen Sie sich vor, dass jemand sagt (von "Docker-Build"), bei Schritt N aufzuhören? Scheint irgendwie brüchig, wenn heute Schritt N morgen Schritt N+1 wäre.
Es sieht so aus, als ob wir eine Möglichkeit brauchen, um eine Art "Label" innerhalb der Dockerfile hinzuzufügen, damit die Leute auf dieses Label aus der build-cmd-Zeile verweisen können.
Wenn wir das hätten, bin ich mir nicht sicher, ob ich einen großen Unterschied zwischen dem Hinzufügen eines "STOP-CACHING" -Befehls sehe, der in der Dockerfile angezeigt wird.
Was ist ein gutes Beispiel für ein Dockerfile-cmd, das den Cache jedes Mal kaputt macht?

Nun, das ist eigentlich der Grund, warum es ursprünglich diskutiert wurde, es zu einem
zeileninhaltsbasierter Regexp, mit dem ich auch gut zurechtkommen würde (vor allem, da
das ist viel einfacher zu schreiben, als genau zu wissen, welche Schrittnummer Sie haben
Ich möchte nicht zwischengespeichert werden - auf keinen Fall schreibe ich eine vollständige Kopie des aktuellen
Dockerfile-Parser in Bash, danke :D).

Tianon Gravi [email protected] schrieb:

Nun, das ist eigentlich der Grund, warum es ursprünglich diskutiert wurde, es zu einem
zeileninhaltsbasierter Regexp, mit dem ich auch gut zurechtkommen würde (besonders
seit
das ist viel einfacher zu skripten, als genau zu wissen, welche Schrittnummer
Sie
Ich möchte nicht zwischengespeichert werden - auf keinen Fall schreibe ich eine vollständige Kopie des aktuellen
Dockerfile-Parser in Bash, danke :D).

Ich möchte meinen früheren Vorschlag wiederholen, dass IMMER/Cache-Breaking
"RUN" sollte einfach "RUN" sein! um die 1-Wort-Befehlsstruktur (?) beizubehalten.

Es scheint ungeschickt, ein Dockerfile bearbeiten zu müssen (indem Sie etwas hinzufügen, das im Grunde zufällig ist, weil es ein Platzhalter ist), um den Cache in einem bestimmten Schritt zu unterbrechen. Ich würde eine docker build CLI-Option verwenden, die immer einen bestimmten Schritt ausführt , aber git clone zufällige Zeichen (!) hinzuzufügen, nur um Docker dazu zu bringen, das Repository tatsächlich zu klonen, anstatt aus dem Cache zu arbeiten.

@curtiszimmerman Ich habe vorgeschlagen (!), weil es auf Englisch so etwas wie Dringlichkeit anzeigt. ("Du solltest das tun!")

Ich denke, das Dockerfile ist mindestens ein geeigneter Ort, um zu definieren, welche Befehle un/cache-fähig sein sollen. Mit "--no-cache=git" bauen zu müssen (mir ist klar, dass dies nicht etwas ist, was Sie vorgeschlagen haben, aber Sie haben mir nichts zum Zitieren/Vergleichen vorgeschlagen) scheint klobiger zu sein.

Warum der Fokus auf RUN? Warum nicht zulassen, dass der Cache für jeden Befehl gebustet wird?
Scheint wie das Hinzufügen eines:
BÜSTE-CACHE
Art des Dockerfile-Befehls wäre viel flexibler. Und um die Flexibilität wirklich zu erhöhen, könnte es optional ein Flag zulassen:
BUST-CACHE $doit
wo es nur gilt, wenn $doit definiert ist - dann, wenn wir Unterstützung für eine -e-Option beim Build hinzufügen (https://github.com/docker/docker/pull/9176), dann könnten die Leute Folgendes tun:
docker build -e doit=true ...

@zamabe Oh, ich würde total RUN! , sorry. Hier benutzte ich (!) um zu sagen "Das ist ungewöhnlich!" zum Bearbeiten eines Dockerfiles jedes Mal, wenn ich den Cache für einen bestimmten Schritt unterbrechen möchte. Jede Möglichkeit, den Cache in einer Dockerfile-Datei vor einem bestimmten Schritt zu sprengen, wäre nützlich (und für zusätzlichen Gewinn, wenn der Schritt nach diesem Cache-Busting-Befehl das gleiche Ergebnis ist wie das, was sich im Cache befindet, seien Sie schlau genug, um vom Cache fortzufahren ). BUST-CACHE oder ALWAYS RUN (oder RUN ALWAYS ) oder RUN! ... Wirklich jeder Mechanismus, der diese Funktion unterstützt, würde ich verwenden.

@duglin Entschuldigung? Der Bug-Titel sagt RUN, was als Beispiel einfacher zu geben ist.

@curtiszimmerman ah.

Nebenbei; Ich denke, die Cache-Neuvalidierung (?) geht etwas über die Cache-Entwertung hinaus, nach der dieser Fehler sucht. Obwohl mir gefällt, was Sie vorschlagen, würde ich meine Dockerfile einfach neu anordnen, um Cache-Busting-Befehle so nah wie möglich am Ende zu platzieren. Dies macht die Vorteile eines _möglichen_ Cache-Treffers zunichte, da Sie _immer_ die notwendigen Berechnungen/Vergleiche durchführen, was wahrscheinlich eine schwerere Strafe darstellt, als den Dockerfile-Build normal abzuschließen, da Leute, die Cache-Busting verwenden, wahrscheinlich auf einen Cache-Miss hoffen/erwarten.

@zamabe Einverstanden. Ich schlage vor, dass, wenn die Implementierung ziemlich trivial ist, dies möglicherweise ein spezieller Befehl zum Fortfahren aus dem Cache ist, der von der Cache-Busting-Kennung getrennt ist. Etwas wie DISABLE-CACHE an einem bestimmten Punkt, um den Cache jedes Mal zu deaktivieren, und wenn Sie einen Anwendungsfall haben, in dem der Rest des Dockerfiles teuer wäre, anstatt aus dem Cache fortzufahren, würde etwas wie DISABLE-CACHE? wenn möglich vom Cache aus fortfahren. Das ist kein Vorschlag, sondern nur eine Demonstration, um zu vermitteln, wovon ich rede.

+1 für Pull-Codes aus Git Repo

+1

Das wäre riesig! Im Moment habe ich einen Teil meiner Continuous Integration, der den Git-Commit-Hash in das Dockerfile schreibt (einen Platzhalter überschreibt), nur um den Cache für Git-Klone zu unterbrechen.

Ich habe diese PR eingereicht: https://github.com/docker/docker/pull/10682 , um dieses Problem zu beheben.
Obwohl es das Wiedereinschalten des Cachings nicht unterstützt, glaube ich nicht, dass dies heute möglich ist.

+1

Ich erzeuge eine Zufallszahl im Dockerfile und sie wird zwischengespeichert...
+1 für eine NOCACHERUN-Anweisung

+1
Sollte für einige RUN wirklich nützlich sein, die wir jedes Mal machen müssen, ohne alles neu aufzubauen

Mir ist aufgefallen, dass git clone den Cache trifft, go get -d jedoch nicht. irgendwelche ideen warum?

_Gemeinsame Rezension mit @LK4D4 @calavera @jfrazelle @crosbymichael @tiborvass_

Wir schließen dies, da wir nicht so viele Anwendungsfälle aus der realen Welt sehen (weitere Informationen finden Sie in der zugehörigen Nummer #10682).

+1 für RUN. Wäre nett.

+1

docker 1.9 führt Build-Time-Variablen ein; es ist möglich, diese (missbräuchlich) zu verwenden, um das Brechen des Caches zu erzwingen; Weitere Informationen finden Sie unter https://github.com/docker/docker/issues/15182

Wieso ist das noch kein Feature?

+1

+1

+1 wie ist das noch nicht mal ein ding!!!???!

+1 Wir benötigen diese Funktion, um eine genauere Steuerung des Bauens zu ermöglichen.

+1

+1

+1

+1

+1 sehr nützlich
(mit @timruffles Workaround

+1

+1

+1

Es könnte nützlich sein, wenn die Leute ihre Anwendungsfälle anstelle von nur +1 gepostet haben, damit die Leute sehen können, warum dies nur eine benötigte Funktion ist.

+1, kam hier über Google an und suchte nach einer Lösung für einen zwischengespeicherten Git-Klon.

Mein Anwendungsfall:
Ich habe eine Docker-Konfiguration, die während ihres Builds über Gradle eine groovige Microservice-App im Probelaufmodus aufruft. Dies führt dazu, dass alle abhängigen Java-Bibliotheken (von einem entfernten mvn-Repository) in das lokale Docker-mvn-Repository heruntergeladen werden. Der Probelauf führt nur die App aus und kehrt sofort zurück, stellt jedoch sicher, dass alle Abhängigkeiten der Java-Bibliothek geladen werden.
Während der Docker-Run-Phase wird dieselbe App über den gradle --offline-Modus ausgeführt. Dh die Microservice-App wird nur aus dem lokalen mvn-Repository-Verzeichnis geladen. kein teurer, zeitaufwändiger Remote-Bibliotheksabruf findet statt. Wenn ich jetzt eine neue Snapshot-Version einer solchen Bibliothek freigebe, löst Docker während eines Builds keinen Remote-Fetch aus (dh er ruft mein Gradle-Trockenlauf-cmd nicht auf), es sei denn, ich ändere das Docker-Verzeichnis.

Mein Anwendungsfall: Abrufen der neuesten Drittanbieterversion einer Bibliothek zur Verwendung für ein Bild. Ich verwende dafür Docker Hub und AFAIK, es wird nichts zwischenspeichern. Aber wer weiß, wann sich das ändern kann.
Wenn es im Docker ein solches Befehls-Flag wie NOCACHE gäbe, würde dies garantiert, egal wo das Image erstellt wird.

Es ist schlimmer, sich auf ein "Feature" des Build-Systems zu verlassen, als auf eine neueste Version, IMHO.

Wie wäre es mit einer neuen Syntax: FORCE RUN git clone .... ?

Im Moment verwende ich RUN _=$(date) git clone ... um den Cache zu ungültig zu machen.

@c9s funktioniert das tatsächlich? Ich glaube nicht.

Die Umgebungsvariable

@c9s Ich sehe nicht, wie das Festlegen der env var funktionieren könnte, da dies von der Shell des Containers und nicht von der Dockerfile-Verarbeitung erfolgt. Wenn ich RUN _=$(date) echo hi versuche, wird der Cache des 2. Builds verwendet.

@duglin du hast recht :| es macht den Cache nicht ungültig

@c9s versuche es stattdessen

FROM foo
ARG CACHE_DATE=2016-01-01
RUN git clone ...
docker build --build-arg CACHE_DATE=$(date) ....

@thaJeztah Danke! Es klappt!

+1 Klonen von Git-Repos (Anwendungsfall)

So viele +1, wenn Sie das Git-Repo in Ihre Docker-Datei ziehen, verhindert der Cache, dass Ihre Bilder erstellt werden. Erschwert es, Builds durch CI zu pushen.

+1 Git-Repos klonen (es ist sehr ärgerlich, dass das Image jedes Mal von Grund auf neu erstellt werden muss, wenn eine kleine Änderung in einem Git-Repo vorgenommen wurde)

@Vingtoft Wenn Sie die Dateien im

@itsprdp Das wusste ich nicht, danke für die Klarstellung.

@itsprdp habe ich gerade getestet. Wenn ich das Repository aktualisiere und das Image erstelle, verwendet Docker immer noch den Cache.
Vielleicht verstehe ich da was falsch?

@itsprdp Das ist meiner Erfahrung nach nicht richtig. Ich habe zum Testen einen neuen Commit in ein Repository ausgeführt, und beim erneuten Erstellen wird derselbe Cache verwendet.

Wenn ich die Docker-Datei vor dem Repository ändere, wird sie natürlich Cache-Bused, aber das einfache Aktualisieren eines Repositorys scheint dieses Problem nicht zu beheben.

@RyanHartje Entschuldigung für die Verwirrung. Es soll den Cache ungültig machen, wenn das Repository aktualisiert wird, und das sollten Mitwirkende berücksichtigen.
Der Anwendungsfall, den @Vingtoft erwartet, besteht darin, das Repository zwischenzuspeichern und nur die geänderten Dateien im Repository zu aktualisieren. Dies kann kompliziert zu implementieren sein.

@itsprdp Nur das Aktualisieren der geänderten Dateien in einem Repository wäre großartig, aber weniger (oder sollte ich mehr sagen?)
In meinem Anwendungsfall (und vielen anderen) dauert der eigentliche Git-Pull nicht lange: Es ist das Erstellen von allem anderen, das den Entwicklungsfluss zerstört.

+1, Cache verwendet während git clone :(

Eine integrierte Lösung wäre schön, aber in der Zwischenzeit können Sie mit ARG den Cache bei einer bestimmten Dockerfile-Anweisung sprengen.

Im Dockerfile:

ARG CACHEBUST=1
RUN git clone https://github.com/octocat/Hello-World.git

Auf der Kommandozeile:

docker build -t your-image --build-arg CACHEBUST=$(date +%s) .

Das Setzen von CACHEBUST auf die aktuelle Zeit bedeutet, dass diese immer eindeutig ist und Anweisungen nach der ARG-Deklaration in der Dockerfile nicht zwischengespeichert werden. Beachten Sie, dass Sie auch erstellen können, ohne das CACHEBUST build-arg anzugeben, wodurch der Standardwert 1 verwendet und der Cache beibehalten wird. Dies kann verwendet werden, um immer neue Kopien von Git-Repos auszuchecken, die neuesten SNAPSHOT-Abhängigkeiten abzurufen usw.

Edit: Was @thaJeztah gerade gesagt hat. Ich lasse dies als zusätzliche Beschreibung seiner Lösung.

@shane-axiom Wie wäre es, wenn Sie den Git-Commit-Hash als Wert für CACHEBUST ?

export CACHEBUST=`git ls-remote https://[email protected]/username/myRepo.git | grep refs/heads/develop | cut -f 1` && \
echo $CACHEBUST && \
docker build -t myDockerUser/myDockerImage \
   --build-arg blah=blue \
   --build-arg CACHEBUST=$CACHEBUST \
   .

Basierend auf Hinweisen von http://stackoverflow.com/questions/15677439/how-to-get-latest-git-commit-hash-command#answer -15679887

@pulkitsinghal Das sieht wunderbar aus, um den Cache für Git-Repos zu sprengen. Für andere Anwendungen (wie das Einbinden von SNAPSHOT-Abhängigkeiten usw.) funktioniert der Ansatz mit dem Always-Busting-Zeitstempel gut.

+1 für CACHE EIN | AUS

+1

+1

Denken Sie an den Ansatz von @CheRuisiBesares, Sie können immer ADD https://www.random.org/strings/?num=16&len=16&digits=on&upperalpha=on&loweralpha=on&unique=on&format=plain&rnd=new uuid als Problemumgehung für Cache-Probleme verwenden.

Um einen zusätzlichen Anwendungsfall zu posten....

COPY package.json /usr/src/
RUN npm install

In unserem package.json wir für einige unserer privaten Github-Abhängigkeiten normalerweise auf ein master Tag verweisen. Dies bedeutet, dass wir nie wirklich die neuesten master sei denn, wir ändern die package.json Datei (normalerweise fügen Sie der Beschreibung einfach ein - und entfernen Sie es dann während des Tests).

Ein RUN NO CACHE von RUN scheint eine gute Lösung zu sein.

+1

Ich habe ein ähnliches Problem für die npm-Installation, die den Cache verwendet und meine neue veröffentlichte Bibliothek in npm nicht verwendet.

Es wäre toll, wenn ich den Cache per RUN-Befehl in der Docker-Datei deaktivieren könnte.

@brycereynolds @mmobini siehe https://github.com/docker/docker/issues/1996#issuecomment -172606763 zum manuellen Busen des Caches. _keine_ Angabe einer bestimmten Version von Paketen, die installiert werden müssen, ist jedoch möglicherweise nicht die beste Vorgehensweise, da das Endergebnis Ihres Dockerfiles (und des Quellcodes) nicht mehr garantiert reproduzierbar ist (dh es wird heute erfolgreich erstellt, aber nicht 'nicht morgen, weil eines der Pakete aktualisiert wurde). Ich kann sehen, dass dies während der Entwicklung "ok" ist, aber für die Produktion (und automatisierte Builds auf Docker Hub) besteht der beste Ansatz darin, explizit eine Version anzugeben. Dadurch können Benutzer auch die genauen Pakete überprüfen, die zum Erstellen des Images verwendet wurden.

Ich habe einen Anwendungsfall, bei dem es Probleme gibt, den Cache nicht ungültig zu machen. Ich führe Dropwizard-Anwendungen (Java REST Services, erstellt mit Maven) von Docker aus und ein automatisiertes System erledigt alle Container-Builds und Bereitstellungen für mich. Ich füge ein Dockerfile in mein Repo ein und es erledigt den Rest. Das System führt eine Produktionsversion und eine oder mehrere Entwicklungsversionen meiner Anwendung aus. Bei Entwicklungs-Builds habe ich Probleme.

Während der Entwicklung haben einige Abhängigkeiten des Projekts SNAPSHOT in ihren Versionsnummern. Dies weist Maven an, dass sich die Version in der Entwicklung befindet und mit jedem Build eine neue Version herunterfahren sollte. Als Ergebnis kann eine identische Dateistruktur zu zwei unterschiedlichen Builds führen. Dies ist das gewünschte Verhalten, da möglicherweise Fehler in einer SNAPSHOT-Abhängigkeit behoben wurden. Um dies zu unterstützen, wäre es hilfreich, Docker zu zwingen, einen bestimmten Befehl auszuführen, da es keine Möglichkeit gibt, die Wirkung des Befehls anhand des aktuellen Zustands des Dateisystems zu bestimmen. Die meisten Java-Projekte werden darauf stoßen, da SNAPSHOT-Abhängigkeiten im Maven-Stil von mehreren verschiedenen Build-Systemen verwendet werden.

@ctrimble Sie können --no-cache oder --build-arg , um den Cache ungültig zu machen.
Sie können den Effekt von --no-cache minimieren, indem Sie ein Basis-Image mit allen zwischenspeicherbaren Befehlen haben.

@cpuguy83 danke für die Antwort. Ich habe den Thread gelesen und verstehe die aktuellen Optionen. Ich habe ein Ticket mit dem Build-System geöffnet, das ich verwende, um ein Cache-Busting-Argument bereitzustellen. Das Erstellen zweier unterschiedlicher Bilder für eine einzige Anwendung scheint eine Menge Arbeit zu erfordern, um die Builds zu beschleunigen. Es wäre viel einfacher, etwas anzugeben wie:

  1. Dinge tun, die zwischengespeichert werden können, wenn das Dateisystem identisch ist
  2. etwas tun, das das Dateisystem ändern könnte, je nachdem, wann es ausgeführt wird
  3. tun Sie einige weitere Dinge, die zwischengespeichert werden könnten, wenn der vorherige Schritt das Dateisystem nicht geändert hat

Dieses Muster wird in Entwicklungs-Builds häufig auftauchen. Es wäre schön, eine Semantik dafür im Dockerfile zu haben.

@ctrimble Das Busen des Caches in einem Schritt führt dazu, dass der Cache immer für jeden nachfolgenden Schritt

@ cpuguy83 genau. Die Semantik meines Build-Systems ist für Entwicklungs-Builds zeitlich begrenzt. Ich muss die richtigen Builds über das Caching auswählen. Ich würde mir wirklich gerne beides zulegen.

Es gab hier beträchtliche Diskussionen, Entschuldigung, wenn es bereits vorgeschlagen wurde, aber was wäre, wenn es so etwas gäbe:

CHECK [FILE_PATH]

Alles, was Docker tun würde, ist, den MD5 (oder was auch immer ein anderer Hashwert ist) der Datei zu speichern, und wenn er sich ändert, werden alle Schritte danach ungültig.

Ich würde wahrscheinlich so etwas machen:

CHECK Gemfile
CHECK package.json
CHECK composter.json
CHECK project.json

Möglicherweise möchten Sie auch eine Überprüfung aktivieren, die nach einer bestimmten Zeitdauer verstreicht. Der Parameter cache_valid_time Ansible für das Plugin apt könnte einige Inspiration bieten: http://docs.ansible.com/ansible/apt_module.html

Dafür wäre die Syntax:

EXPIRE 1234567 
RUN apt-get update
RUN bundle install

Docker würde die letzte Ausführungszeit kennen und basierend auf "jetzt" berechnen, ob die Zeit abgelaufen war.

@atrauzzi Wir unterstützen --squash beim Build in 1.13 ( vorerst nur experimentell).

@cpuguy83 Gibt es irgendwo Dokumente oder Erklärungen zu --squash , die ich nachlesen kann? Am Anfang klingt der Name nicht so, als würde er das tun, was ich denke. Aber ich könnte (und bin höchstwahrscheinlich) falsch liegen!

@atrauzzi ja, in der Build-Referenz.

Grundsätzlich behält --squash sowohl den Layer-Cache bei als auch ein zweites Image, das so ist, als ob alles in der Dockerfile in einer einzigen Schicht passiert wäre.

Ich verstehe nicht, warum man einzeln überprüfen muss, ob ein Dateicache noch gültig ist, ADD und COPY tun dies bereits für alles, was hineinkopiert wird.

@ cpuguy83 Guter Punkt, habe nicht einmal daran gedacht, und natürlich benutze ich es bereits.

Was ist mit dem Zeitstempel/Dauer-Ansatz? Ist das machbar mit dem, was bereits vorhanden ist?

Was ist mit dem Zeitstempel/Dauer-Ansatz? Ist das machbar mit dem, was bereits vorhanden ist?

Durch Build-Argumente;

ARG expire_after=never
RUN do some thing
docker build --build-arg expire_after=2016-12-01 -t foo .

Ändere das Build-Argument, um den Cache zu sprengen

+1 für einen saubereren Weg

+1 für einen saubereren Weg

Es sollte auch separate Optionen zum Deaktivieren des Lesens des Caches und zum Deaktivieren des Schreibens in ihn geben. Sie möchten beispielsweise ein Bild von Grund auf neu erstellen und alle zwischengespeicherten Ebenen ignorieren, aber dennoch die resultierenden neuen Ebenen in den Cache schreiben.

+1

Darf ich vorschlagen, die Schrittnummer an den Build-Befehl zu übergeben?

Etwas wie das:
docker build --step 5 .

Es würde alle Caches nach und einschließlich Schritt 5 während des Builds ignorieren.

+1
Bitte.

CACHE EIN|AUS +1

Das Problem bei diesen CACHE ON|OFF Befehlen besteht darin, dass bei jedem Schritt, bei dem der Cache ausgeschaltet wird, keine Möglichkeit besteht, weitere Schritte zwischenzuspeichern. Der einzig sinnvolle Befehl wäre ENDCACHE .

Es ist eine gültige Idee / Ethos. Der Befehl soll alle nicht gecachten Layer zu einem einzigen Layer zusammenfassen, wenn der Cache wieder eingeschaltet wird. Natürlich kann man immer noch über die beste Benennung / Korrektheit der Semantik / bevorzugte Syntax des Features streiten.

+1

+1 das Must-Have-Feature

Zustimmen für CACHE ON|OFF +1

+1 Wäre toll.

Ich habe vorher nicht wirklich verstanden, wie Docker die Schritte zwischenspeichert und habe einen halben Tag damit verbracht, zu untersuchen, warum mein System nicht richtig baut. Es war das Caching von "git clone".

Hätte gerne das Schlüsselwort ALWAYS .

Wie ist es geschlossen?

Was ist die beste Lösung?

Ich habe https://github.com/moby/moby/issues/1996#issuecomment -185872769 ausprobiert und es hat funktioniert
Im Dockerfile:

ARG CACHEBUST=1
RUN git clone https://github.com/octocat/Hello-World.git

Auf der Kommandozeile:

docker build -t your-image --build-arg CACHEBUST=$(date +%s)

Warum nicht einen neuen Befehl ähnlich RUN erstellen, aber RUNNC nie für RUN NO CACHE zwischenspeichern?

Kann ich bestätigen, @habeebr (https://github.com/moby/moby/issues/1996#issuecomment-295683518) - ich verwende es in Kombination mit https://github.com/moby/moby/issues/1996# Ausgabekommentar -191543335

+1

RUNNC ist eine tolle Idee!

Warum wurde dieses Thema geschlossen? Zwischen den unzähligen Duplikaten, die im Wesentlichen dasselbe verlangen, und der langen Kommentarhistorie von mehr als einem dieser Duplikate, scheint es offensichtlich, dass ein gesundes Interesse daran besteht, diese Funktionalität verfügbar zu sehen.

Ich verstehe, dass es schwierig ist, und vielleicht hat niemand eine ausreichend elegante Lösung vorgeschlagen, die sowohl dem Bedarf gerecht wird als auch sauber genug ist, um eine attraktive Docker-Ergänzung zu sein ... aber das bedeutet nicht, dass es keinen Bedarf gibt.

Das einzige andere Argument, das ich für das Schließen gehört habe, ist, dass es andere Möglichkeiten gibt, dies zu erreichen ... aber auch dieses Argument ist nicht wirklich überzeugend. Das Erstellen mehrerer Basis-Images zu dem alleinigen Zweck, den Mangel an Cache-Steuerung zu umgehen, ist unhandlich, eine Entwertung durch ein ARG ist stumpfsinnig und nicht intuitiv. Ich kann mir vorstellen, dass Benutzer diese "Workarounds" ungefähr so ​​oft nutzen möchten, wie Docker-Entwickler offiziell einen schlampigen Hack in das Tool integrieren möchten.

es ist nicht schwer: https://github.com/moby/moby/pull/10682
einfache Lösung, einfache UX. Nur kein klarer Konsens darüber, ob es getan werden sollte.

Wow einfach wow...

Ich hätte es bereits implementiert, nur um nichts davon hören zu müssen, ganz zu schweigen davon, dass es einen klaren Konsens gibt, dass die Benutzerbasis es will. Ich war nicht auf der Entwicklerseite eines so großen Open-Source-Projekts, nur bei viel kleineren, also übersehe ich vielleicht etwas.

+1

+1 für vernünftige Sicherheit und bessere Leistung

+1

+1

+1

+1

+1

+1

Könnt ihr aufhören, das +1 zu spammen? Verwenden Sie einfach die Reaktionsfunktion zum Upvoten.

Irgendwelche Veränderungen?
Weiß immer noch nicht, warum dieses Thema geschlossen ist.
Meiner Meinung nach ist es eine unverzichtbare Funktion, die den Versionszug aus dem Remote-Git-Repository perfekt handhabt.

+1

+1

+1

+1

+1

+1

+1

+1

+1

+1

Warum das schließen? Ich denke, es ist nützlich

+1

+1

+1

Derzeit die einfachste Möglichkeit, den Cache für einen Layer (und die folgenden) zu deaktivieren:

Dockerfile

ARG CACHE_DATE
RUN wget https://raw.githubusercontent.com/want/lastest-file/master/install.sh -O - | bash

Und wenn Sie das Image erstellen, müssen --build-arg hinzugefügt werden

docker build  --build-arg CACHE_DATE="$(date)"

Dann wird der Befehl wget jedes Mal ausgeführt, wenn Sie das Image erstellen, anstatt einen Cache zu verwenden.

RUNNC oder CACHE OFF wäre schön

Das sieht in der Zwischenzeit vielversprechend aus:
http://dev.im-bot.com/docker-select-caching/

das ist:

screenshot 2018-05-26 19 03 09

Ich werde ruhig bleiben und mich der Herde anschließen:

+1

Ja, ich brauche selektives Caching für Befehle. Mein COPY schlägt in 80% der COPY niemals zwischenspeichern, sondern alles andere zwischenspeichern. Ein CACHE ON und CACHE OFF wäre toll.

RUN X
RUN X
CACHE OFF
COPY /config /etc/myapp/config
CACHE ON

@shadycuz Sie können den Cache nie wieder " COPY Direktive so weit unten wie möglich im Dockerfile platzieren (damit Docker den Build-Cache für so viel wie möglich nutzen kann Build-Prozess wie möglich, bevor der Cache ungültig gemacht wird).

Um den Cache zu einem bestimmten Zeitpunkt im Build-Prozess ungültig zu machen, können Sie sich auf die anderen Kommentare zur Verwendung von --build-arg und ARG beziehen, die hier zuvor erwähnt wurden.

@shadycuz @curtiszimmerman Ja, möglicherweise CACHE OFF aber nicht CACHE ON , da die folgenden Ebenen neu erstellt werden müssen, wenn eine frühere Ebene geändert wird.

Ich stimme zu, dass CACHE ON aus technischer Sicht keinen Sinn macht. Es hilft, die Absicht klarer auszudrücken, welche Schichten aber eigentlich entkräftet werden sollen.

Eine flexiblere Lösung wäre ein Befehl ähnlich dem RUN , der es einem Shell-Code ermöglicht, zu bestimmen, ob der Cache ungültig gemacht werden soll. Ein Exit-Code von 0 könnte "Cache verwenden" und 1 "Cache ungültig" bedeuten. Wenn kein Shell-Code angegeben wird, könnte der Standardwert sein, den Cache von hier an ungültig zu machen. Der Befehl könnte beispielsweise INVALIDATE heißen.

Warum wurde das ohne Kommentar geschlossen?

Es gab einen Kommentar, aber er wurde von github versteckt
https://github.com/moby/moby/issues/1996#issuecomment -93592837

+1

Diese Funktion wäre für mich im Moment lebensrettend.

+1

Wir schließen dies, da wir nicht so viele Anwendungsfälle aus der realen Welt sehen

212 Kommentare und gezählt, aber immer noch kein Anwendungsfall? Scheint ziemlich ignorant zu sein.

+1

+1

+1

+1

+1

das problem ist immer noch da und bedarf noch einer lösung. Es gibt noch viele Anwendungen in der realen Welt.

+1

Ich vermute, dass die Docker-Entwickler keinen Anreiz haben, dies zu implementieren, um ihre zentralisierte Gebäudeinfrastruktur vor DDsS-Bearbeitungen durch No-Cache-Anfragen zu schützen.

Ich vermute auch, dass eine parallele Infrastruktur, die No-Cache-Builds ermöglicht, für Enterprise-Anwender interessant wäre.

Insgesamt handelt es sich bei diesem Problem nicht um eine Softwarefunktion, sondern um ein Problem der Dienstskalierung.

@jaromil Das stimmt nicht ganz, da dies auch auf selbst gehosteten Repositorys nicht möglich ist.

Welche Software gibt es, um ein selbst gehostetes Repository auszuführen? Ich weiß nicht genau, was Sie meinen.
Eine einfache selbst gehostete Lösung könnte ein Cron-Klonen von Git-Repos und Runnig Docker build --no-cache sein.

@jaromil Ich glaube nicht, dass das das Problem ist. Es wäre effizienter, es für die Open-Source-Projekte von DockerHub zu haben (sowie für kostenpflichtige, sie berechnen keine Gebühren für die Anzahl der Builds). In einer CI/CD-Umgebung mit häufigen Builds wird dies noch schlimmer.

Solange Sie dies tun müssen (Sie verwenden Docker und Git und möchten nicht, dass 5 Container gemeinsam genutzte Volumes ausführen), müssen Sie den Container neu erstellen und jedes Mal hochladen, wenn Sie eine neue Version hochladen. Der gesamte Behälter.
Mit einem im Code enthaltenen No-Cache-Flag erstellen und ersetzen Sie jedes Mal, wenn Sie den Build ausführen, diese einzelne Schicht anstelle des gesamten Containers, um die Version zu aktualisieren.

Über den selbstveranstaltenden Vertreter würden Sie überrascht sein. Ich verstehe den @bluzi- Kommentar, es gibt keine ddos-Auswirkungen, wenn Sie sich selbst hosten (oder aws ecr verwenden).

Ok, das ist sicherlich ein komplexeres Szenario, das ich mir vorgestellt habe. Jetzt denke ich ... Hochladen mit einer Art Nocache-Single-Layer-Hashes ... Push und Override, was auch immer. Ich bin nicht sicher

TLDR: Ich denke, einige Verbesserungen an der Docker-Dokumentation könnten sehr hilfreich sein.

Ich bin hier gelandet, nachdem ich auf meine eigenen Probleme/Verwirrung mit dem Caching gestoßen war. Nachdem ich alle Kommentare hier und in https://github.com/moby/moby/pull/10682 gelesen hatte, fand ich eine praktikable Lösung für meinen speziellen Anwendungsfall. Aber irgendwie war ich immer noch frustriert über Dockers Reaktion darauf, und es scheint, dass viele andere genauso denken.

Wieso den? Nachdem ich dies aus verschiedenen Blickwinkeln betrachtet habe, denke ich, dass das Problem hier eine Kombination aus vagen Anwendungsfällen, zu verallgemeinerten Argumenten gegen die vorgeschlagenen Änderungen (die gültig sein können, die vorgestellten Anwendungsfälle jedoch nicht direkt ansprechen) und das Fehlen von Dokumentation für Docker-Empfehlungen für einige gängige Anwendungsfälle. Vielleicht kann ich helfen, Dinge zu klären und Dokumentationen zu identifizieren, die verbessert werden könnten, um in dieser Situation zu helfen.

Wenn ich zwischen den Zeilen lese, hört es sich für mich so an, als wären die meisten der frühen Kommentatoren dieser Funktionsanforderung mit einer Lösung zufrieden, die zusätzliche Argumente zu docker image build , um den Cache an einer bestimmten Stelle im Dockerfile zu deaktivieren. Es klingt so, als ob die aktuelle Lösung von Docker dafür (beschrieben in https://github.com/moby/moby/issues/1996#issuecomment-172606763) in den meisten Fällen ausreichen sollte, und es klingt so, als ob viele Benutzer damit zufrieden sind . (Wenn jemand einen Anwendungsfall hat, in dem er zusätzliche Argumente für docker image build bereitstellen kann, diese Lösung jedoch immer noch unzureichend ist, wäre es wahrscheinlich hilfreich, einen Kommentar hinzuzufügen, der erklärt, warum dies unzureichend ist.)

Die ganze anhaltende Frustration scheint mit der Notwendigkeit zusammenzuhängen, zusätzliche Argumente an docker image build zu übergeben, um das Caching-Verhalten zu kontrollieren. Die damit verbundenen Anwendungsfälle sind jedoch nicht sehr gut beschrieben.

Wenn ich noch einmal zwischen den Zeilen lese, scheint es mir, dass sich alle diese Anwendungsfälle entweder auf Dienste beziehen, die docker image build im Namen eines Benutzers ausführen, oder sich auf Dockerfiles beziehen, die an andere Benutzer verteilt werden, die dann docker image build ausführen docker image build ein Problem darstellt, wäre es wahrscheinlich hilfreich, einen Kommentar hinzuzufügen, der Ihren Anwendungsfall detailliert erklärt.)

In vielen dieser Fälle klingt es so, als ob der Anwendungsfall nicht die Möglichkeit erfordert, das Caching an einer bestimmten Stelle in der Dockerfile zu deaktivieren (was der ursprüngliche Punkt dieser Funktionsanforderung war). Stattdessen klingt es so, als würden viele Benutzer mit der Möglichkeit zufrieden sein, das Caching vollständig aus dem Dockerfile heraus zu deaktivieren, ohne das Argument "--no-cache" für docker image build und ohne vorherige manuelle Änderungen am Dockerfile zu erfordern bauen. (Bei der Beschreibung von Anwendungsfällen wäre es wahrscheinlich hilfreich zu erwähnen, ob ein teilweises Caching tatsächlich erforderlich ist oder ob eine vollständige Deaktivierung des Caches für Ihren Anwendungsfall ausreichend wäre.)

In Fällen, in denen ein Dienst docker image build im Namen eines Benutzers ausführt, erwartet Docker, dass alle diese Dienste entweder den Cache bedingungslos deaktivieren oder dem Benutzer die Möglichkeit geben, den Cache zu deaktivieren. Laut https://github.com/moby/moby/pull/10682#issuecomment-73777822 deaktiviert Docker Hub den Cache bedingungslos. Wenn ein Dienst dies nicht bereits tut, hat Docker https://github.com/moby/moby/pull/10682#issuecomment-159255451 vorgeschlagen, sich beim Dienstanbieter darüber zu beschweren.

Dies scheint mir eine vernünftige Position für Docker in Bezug auf Dienste zu sein, die docker image build ausführen. Diese Position muss jedoch wirklich an einer gut sichtbaren Stelle offiziell dokumentiert werden, damit sowohl Diensteanbieter als auch Nutzer wissen, was sie erwartet. Es scheint, dass diese Position oder das Caching-Verhalten von Docker Hub derzeit nirgendwo anders dokumentiert sind als in diesen spontanen Kommentaren, die tief in diesem riesigen / alten / geschlossenen Pull-Request vergraben sind versteh das falsch. Vielleicht könnte dieses Problem durch das Hinzufügen von Informationen zur docker build Referenz , die Dockers Meinung zur Verwendung von Caching durch Build-Services beschreiben, und das Hinzufügen von Informationen zur automatisierten Build-Dokumentation von Docker Hub über das Caching-Verhalten von Docker Hub behoben werden?

In Fällen, in denen Dockerfiles an andere Benutzer verteilt werden, die dann docker image build selbst ausführen, haben einige Leute argumentiert, dass die Verwendung des einfachen Befehls docker build . (ohne zusätzliche Argumente) so üblich ist, dass es so wäre für Dockerfile-Builder unangemessen, von Benutzern das Hinzufügen von Argumenten zu verlangen, während andere Personen (zum Beispiel: https://github.com/moby/moby/issues/1996#issuecomment-72238673 https://github.com/moby/moby/pull /10682#issuecomment-73820913 https://github.com/moby/moby/pull/10682#issuecomment-73992301) haben argumentiert, dass es unangemessen wäre, Benutzer bedingungslos daran zu hindern, Caching durch hartkodierte Cache-Überschreibungen in der Dockerfile zu verwenden. In Ermangelung detaillierter / zwingender Anwendungsfälle dafür hat Docker die Entscheidung der Exekutive getroffen, zusätzliche Befehlszeilenargumente zu erfordern, um das Caching zu kontrollieren, was die Ursache für einen Großteil der anhaltenden Frustration zu sein scheint. (Wenn jemand einen überzeugenden Anwendungsfall dazu hat, wäre es wahrscheinlich hilfreich, einen Kommentar hinzuzufügen, der ihn ausführlich erklärt.)

Es scheint mir jedoch, dass Docker in der Lage sein könnte, alle glücklich zu machen, indem es die Gewohnheit der Benutzer bricht, docker build . ohne zusätzliche Argumente auszuführen. Das Caching-Verhalten und das Argument "--no-cache" werden in keinem der relevanten Docker-Tutorials (wie diesem oder diesem) erwähnt
oder das ). Während die docker build Dokumentation das Argument "--no-cache" auflistet, wird es jedoch weder seine Bedeutung erläutert noch die Tatsache hervorgehoben, dass es in vielen gängigen Anwendungsfällen wichtig ist. (Beachten Sie auch, dass die docker image build Dokumentation leer ist. Sie sollte zumindest auf die docker build Dokumentation verweisen .) Es scheint, dass nur die Best Practices-Dokumentation das Caching-Verhalten tatsächlich beschreiben und die Rolle erwähnen des Arguments "--no-cache". Diese Dokumente werden jedoch wahrscheinlich nur von fortgeschrittenen Dockerfile-Autoren gelesen. Es überrascht also nicht, dass nur fortgeschrittene Benutzer mit dem Argument "--no-cache" vertraut sind und dass die meisten Benutzer docker build . ohne zusätzliche Argumente ausführen und dann verwirrt sind, wenn es sich nicht verhält wie sie oder der Dockerfile-Writer erwarten/wollen. Vielleicht könnte die Aktualisierung der Tutorials und der docker build Dokumentation, um das Argument "--no-cache" und seine Bedeutung zu erwähnen, dieses Problem beseitigen?

+1

+1

Mit dem offiziellen Tool bashbrew von docker können Sie beim

+1

+1

Der Anwendungsfall, auf den ich gerade treffe, besteht darin, vorübergehende, kurzlebige Geheimnisse als Build-Argumente für die Installation privater Pakete weiterzugeben. Das unterbricht das Caching komplett, weil es bedeutet, dass jedes Mal, wenn sich das Geheimnis ändert (im Grunde bei jedem Build), der Cache kaputt geht und die Pakete wieder neu installiert werden, obwohl die einzige Änderung das Geheimnis ist.

Ich habe versucht, dies zu umgehen, indem ich das ARG in einem Skript konsumiere, das vor der Angabe des ARG COPY'd wird, aber Docker scheint alles ungültig zu machen, nachdem das ARG deklariert wurde, wenn sich die ARG-Eingabe geändert hat.

Das Verhalten, das ich gerne sehen würde, besteht darin, ein ARG als immer zwischenspeichern zu können, entweder in der Dockerfile oder in der CLI beim Aufrufen von Build. Für Anwendungsfälle wie Geheimnisse ist das oft das, was Sie wollen; der Inhalt der Paketliste sollte bestimmen, wann der Cache ungültig gemacht wird, nicht das an ARG übergebene Argument.

Ich verstehe die Theorie, dass diese Abschnitte in ein zweites Image gezogen werden könnten, das dann als Basisimage verwendet wird, aber das ist ziemlich umständlich, wenn die Pakete von einem Projekt verwendet werden, wie in einer package.json, Requirements.txt, Gemfile usw Dieses Basis-Image würde auch ständig neu erstellt werden.

+1 bis CACHE OFF von dieser Zeilendirektive - ich habe buchstäblich Jahre darauf gewartet.

Ich musste den Cache auf Docker Hub / Docker Cloud deaktivieren und dies würde Tonnen von Zeit und Builds sparen, wenn ich die große Ebene zwischenspeichern und dann nur einen Nocache-Aktualisierungsbefehl gegen Ende der Dockerdatei ausführen könnte.

Das Verhalten, das ich gerne sehen würde, besteht darin, ein ARG als immer zwischenspeichern zu können, entweder in der Dockerfile oder in der CLI beim Aufrufen von Build. Für Anwendungsfälle wie Geheimnisse ist das oft das, was Sie wollen; der Inhalt der Paketliste sollte bestimmen, wann der Cache ungültig gemacht wird, nicht das an ARG übergebene Argument.

--build-arg PASSWORD=<wrong> könnte zu einem anderen Ergebnis als --build-arg PASSWORD=<correct> , daher bin ich mir nicht sicher, ob das bloße Betrachten des Inhalts der Paketliste dafür funktionieren würde. Der Builder kann nicht selbst vorhersagen, welche Auswirkungen das Festlegen/Ändern einer Umgebungsvariablen auf die ausgeführten Schritte haben würde (sind make DEBUG=1 foo und make DEBUG=0 foo gleich?). Die einzige Ausnahme, die derzeit gemacht wird, sind die Umgebungsvariablen xx_PROXY , bei denen davon ausgegangen wird, dass ein Proxy für Netzwerkverbindungen benötigt wird, der Wechsel zu einem anderen Proxy jedoch zum gleichen Ergebnis führen sollte. Damit dies funktioniert, wäre eine Möglichkeit erforderlich, eine bestimmte Umgebungsvariable (/build arg) anzugeben, die für das Caching ignoriert werden soll.

Beachten Sie, dass BuildKit jetzt experimentelle Unterstützung für RUN --mount=type=secret und RUN --mount=type=ssh bietet rufen Sie den Buildkit-Problem-Tracker auf https://github.com/moby/buildkit/issues).

Ich musste den Cache auf Docker Hub / Docker Cloud deaktivieren

Verwendet Docker Hub / Cloud tatsächlich Caching? Ich denke, dort wird kein Caching verwendet (wie in; es werden ephemere Build-Umgebungen verwendet)

Ich erinnere mich, dass DockerHub früher kein Build-Caching verwendet hat, aber ich hatte mir meine automatisierten Builds in der Docker Cloud kurz vor diesem Ticket angesehen und es gibt jetzt einen Building Caching-Schieberegler neben dem Autobuild-Schieberegler jedes Zweigs, obwohl er standardmäßig deaktiviert ist.

Ich wage es nicht, das Build-Caching zu aktivieren, da Schritte wie git clone nicht den neuesten Repo-Download erhalten, da nur die Direktivenzeichenfolge verglichen wird, die sich nicht ändert. Als er heute einem Kollegen dieses Thema, das uns seit Jahren ein Dorn im Auge ist, erklärt, war er überrascht, da es für viele Anwendungsfälle wie eine große Unvollkommenheit erscheint.

Ich würde es vorziehen, dass die ersten git clone && make build zwischengespeichert werden und dann einfach einen NO CACHE in einem git pull && make build Schritt ausführen, um nur ein viel kleineres Code-Update + Abhängigkeiten zu erhalten, die noch nicht als letztes installiert sind Layer, wodurch der Großteil des Images effizient zwischengespeichert wird, nicht nur für Builds, sondern noch wichtiger für alle Clients, die im Moment jedes Mal Hunderte von MB an Layern neu herunterladen und ersetzen müssen, was äußerst ineffizient ist.

Die Größe liegt daran, dass viele der Projekte eine Vielzahl von Abhängigkeiten aufweisen, z. Systempakete + Perl CPAN-Module + Python PyPI-Module usw.

Selbst die Verwendung von Alpine ist nicht viel kleiner, wenn Sie die Systempaketabhängigkeiten und die CPAN- und PyPI-Abhängigkeiten hinzufügen, da ich Alpine seit Jahren verwende, um zu versuchen, kleinere Bilder zu erstellen, aber wenn Sie viele Abhängigkeiten haben, funktioniert dies nicht mehr machen einen großen Unterschied, wenn die Basis kleiner beginnt, da das Hinzufügen von Systempaketen das meiste davon gleich wieder hinzufügt.

Das Zwischenspeichern der früheren Schichten, die alle Systempakete + CPAN + PyPI-Module enthalten, würde bedeuten, dass sich in der letzten Schicht der Updates nur sehr wenig ändern sollte, da ich in den meisten Fällen keine funktionierenden installierten Module aktualisiere (ich habe Skripte aus meinen Bash-Tools verwendet Utility-Submodul-Repository, um nur Pakete zu installieren, die noch nicht installiert sind, um die Installation unnötiger Nicht-Bugfix-Updates zu vermeiden)

Ich habe eine Weile versucht, einen Trick wie das Ändern von ARG zu verwenden (eine Idee, die ich beim Durchsuchen von Blogs wie http://dev.im-bot.com/docker-select-caching/ hatte):

In Dockerfile:

ARG NOCACHE=0

Führen Sie dann Docker build wie folgt aus:

docker build --build-arg NOCACHE=$(date +%s) ...

aber ich glaube nicht, dass dies in der Docker Cloud möglich ist.

Es gibt Umgebungsvariablen, aber es scheint nicht möglich zu sein, dynamische Inhalte wie die obige Epoche zu verwenden (oder zumindest nicht dokumentiert, die ich finden konnte), und bei Umgebungsvariablen bin ich mir nicht sicher, ob dies das Caching für diese Direktivenzeile ab ungültig machen würde.

@thaJeztah Ja, diese Art von Verhalten könnte leicht negative Folgen haben, wenn sie missverstanden oder missbraucht wird, aber es würde bestimmte Anwendungsfälle sehr gut lösen.

--build-arg PASSWORD=<wrong> könnte zu einem anderen Ergebnis als --build-arg PASSWORD=<correct> , daher bin ich mir nicht sicher, ob es dafür funktionieren würde, nur den Inhalt der Paketliste zu betrachten

Obwohl Sie Recht haben, dass dies zu anderen Ergebnissen führen würde, ist es mir egal, ob das Kennwort richtig oder falsch ist, wenn sich die Paketliste nicht geändert hat; Die Pakete befinden sich bereits im vorherigen Image, sodass der Benutzer, der dies ausführt, bereits Zugriff hat (dh es ist kein Sicherheitsrisiko), und wenn das Passwort zuvor falsch war, würde ich erwarten, dass der Dockerfile-Autor die Installation fehlschlägt Wenn dies erforderlich ist, könnten Sie nach dem Festlegen des Kennworts immer noch die Möglichkeit haben, Pakete korrekt zu installieren.

Ja, ich habe mir etwas wie docker build --force-cache-build-arg SECRET=supersecret . Das ist ziemlich klobig, ich bin sicher, jemand könnte sich etwas Besseres einfallen lassen.

@HariSekhon Es hört sich so an, als ob Ihr Anwendungsfall tatsächlich das Gegenteil von meinem ist, oder? Sie wollen selektiv Kraft vermissen die Cache, anstatt selektiv Kraft , um den Cache - Treffer?

Das Hinzufügen hat bei mir funktioniert:

ADD http://date.jsontest.com/ /tmp/bustcache

aber diese Seite ist gerade down. Das sollte funktionieren

ADD http://api.geonames.org/timezoneJSON?formatted=true&lat=47.01&lng=10.2&username=demo&style=full /tmp/bustcache

@itdependsnetworks

Perfekt, das ist ein guter Workaround und die Site ist jetzt wieder verfügbar. Es ist auch nützlich, das Erstellungsdatum des Images aufzuzeichnen.

Ich hatte dies versucht und ähnliche andere spezielle Dateien sollten sich jedes Mal ändern

COPY /dev/random ...

aber das hat nicht funktioniert, obwohl RUN ls -l -R /etc solche Dateien anzeigte, wurden sie immer nicht gefunden, ich vermute, dass es einen Schutz gegen die Verwendung spezieller Dateien gibt.

Jetzt denke ich mehr darüber nach, auf DockerHub / Docker Cloud könnten Sie wahrscheinlich auch einen Pre-Build-Hook verwenden, um eine Datei mit einem Datumsstempel zu generieren und diese dann direkt vor der Ebene, die Sie cachebusten möchten, in das Image KOPIEREN, um ein ähnliches Ergebnis zu erzielen, obwohl das ADD Die oben gezeigte ist meiner Meinung nach besser auf lokale Docker- und Cloud-Builds übertragbar.

Wir müssen eine zuverlässigere Datumsdruck-Site für diesen Cache-Busting-Workaround finden - beide oben genannten scheinen Demos zu sein / haben Kontingente und sind daher unzuverlässig und brechen zufällig Builds.

Der erste bricht ständig sein Tageskontingent und der zweite gibt jetzt diesen Fehler aus

{"status": {
  "message": "the daily limit of 20000 credits for demo has been exceeded. Please use an application specific account. Do not use the demo account for your application.",
  "value": 18
}}

Ich denke, es wäre großartig, eine Anweisung zu haben, die ich in eine Docker-Datei einfügen kann, die bei jedem Build ausgeführt wird und wenn sich die Ausgabe vom letzten Build unterscheidet, werden nachfolgende Ebenen neu erstellt.

Beispielverwendung wäre:

FROM something
... 
CACHE_BUST git ls-remote my-git-repo HEAD
RUN git clone --depth=1 my-git-repo ...
...
CMD ["my-cmd"]

Der Befehl in der obigen CACHE_BUST-Anweisung gibt den SHA aus dem HEAD des angegebenen Repositorys aus. Auf diese Weise kann meine Dockerdatei aufgrund von Änderungen am Repository wissen, ob sie geklont werden soll oder nicht.

Alle meine Anwendungsfälle hier beziehen sich auf nicht-deterministische netzwerkbezogene Schichten, wie oben gezeigt. Derzeit kann ich hier ARG für alle meine Bedürfnisse verwenden, aber das bedeutet, dass ich oft ein Build-Skript brauche, das eine Dockerdatei verwendet, wenn es schön wäre, nur die Dockerdatei selbst zu verwalten. (plus einige Tools erlauben keine Argumente)

Mein aktueller Arbeitsablauf würde so aussehen:

ARG SHA_TO_BUILD
RUN echo SHA_TO_BUILD
RUN git clone ...
...everything else reliant on that clone
$> ./build-my-image.sh $(get-latest-sha)

Ich halte es für eine schlechte Idee, das Caching für jeden Befehl ein- und auszuschalten. Dateien sollten so geschrieben werden, dass, wenn eine Ebene neu erstellt werden muss, auch der Rest neu erstellt werden muss. Aber ich denke, es wäre schön, an einer bestimmten Stelle in der Datei einen Neuaufbau erzwingen zu können.

so ein tolles Feature, warum noch ausstehend?

Ein weiterer Anwendungsfall ist, wenn sich der Inhalt einer Datei ändert, Dockerfile jedoch nicht.

Wenn ich beispielsweise ein COPY file.txt . und file.txt ändere, wird Docker immer noch die zwischengespeicherte alte Version verwenden.

Wenn Docker eine Prüfsumme der kopierten Dateien erstellen und beim nächsten Mal verwenden würde, um festzustellen, ob die zwischengespeicherte Schicht verwendet werden soll, würde das Problem lösen.

Im Moment bin ich gezwungen, --no-cache und das lädt viel mehr herunter und leistet viel mehr als nötig (Zeit- und Bandbreitenverschwendung).

@brennancheung Wenn das der Fall ist, ist es ein Fehler. Zögern Sie nicht, eine separate Ausgabe mit reproduzierbaren Schritten zu öffnen.

Ich denke, der Hauptpunkt in dem, was @brennancheung
https://github.com/brennancheung sagt zum Beispiel, wenn du es bist
Laden einer Konfigurationsdatei (oder etwas Ähnliches). Du musst nicht
Installieren Sie die gesamte Anwendung neu, aktualisieren Sie einfach diese Dateien und die Befehle
damit verbunden, führen Sie den Docker aus und voila, das System ist eingestellt.
Natürlich können Sie die Konfigurationsdatei oft einfach näher an das Ende von
Ihren Stapel, aber das ist nicht immer der Fall.

Am Mi., 20. März 2019 um 00:10 Uhr schrieb Tibor Vass <
[email protected]>:

@brennancheung https://github.com/brennancheung wenn das der Fall ist,
es ist ein Fehler. Zögern Sie nicht, eine separate Ausgabe mit reproduzierbaren Schritten zu öffnen.


Sie erhalten dies, weil Sie einen Kommentar abgegeben haben.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/moby/moby/issues/1996#issuecomment-474666893 oder stumm
der Faden
https://github.com/notifications/unsubscribe-auth/ALBon0edO9m5BU3C5Ik2i__9eogZc1Jiks5vYaaNgaJpZM4BB_sR
.

--
Thiago Rodrigues

Habe dies versucht https://github.com/moby/moby/issues/1996#issuecomment -185872769

Aber es wirkt sich nur auf den Cache bei/nach der ersten Verwendung aus und nicht nur auf seine Definition.

https://docs.docker.com/engine/reference/builder/#impact -on-build-caching

Wenn ein Dockerfile eine ARG-Variable definiert, deren Wert sich von einem vorherigen Build unterscheidet, tritt bei seiner ersten Verwendung ein „Cache-Miss“ auf, nicht bei seiner Definition.

@samstav "erste Verwendung" gibt es das erste RUN nach dem ARG (wenn das ARG mit einer Build-Phase ist), also:

ARG FOO=bar

FROM something
RUN echo "this won't be affected if the value of FOO changes"
ARG FOO
RUN echo "this step will be executed again if the value of FOO changes"

FROM something-else
RUN echo "this won't be affected because this stage doesn't use the FOO build-arg"

Das Obige hängt ein wenig davon ab, wenn Sie den Builder der nächsten Generation (BuildKit) verwenden, also mit aktiviertem DOCKER_BUILDKIT=1 , da das BuildKit die Bauphasen überspringen kann, wenn sie für die letzte Phase nicht benötigt werden (oder die Bauphasen überspringen). wenn sie vollständig zwischengespeichert werden können)

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen