
Ich habe lange Zeit eine App mit Docker und einem Zwischencontainer erstellt, z. B. würde ich einen Build erstellen, myapp:base
in den alle Kerndateien kopiert wurden:
FROM ubuntu:17.10
ADD app /app
Nun kann der Hauptcontainer myapp:release
einfach mit diesem erstellt werden
FROM myapp:base
ADD app /app
Möglicherweise werden einige Dateien im app
Verzeichnis geändert, und ich hätte am Ende eine kleine zusätzliche Ebene.
Vor kurzem hat dieses Finale jedoch ADD
zu einer viel größeren Schicht geführt, und ich vermute, dass es mit einem Docker-Update zusammenhängt (ich verwende Docker-Version 18.02.0-ce, Build fc4de44).
Hat sich etwas daran geändert, wie Docker herausfindet, was anders ist? Wie kann ich zu einem effizienten Build zurückkehren, das nur eine kleine Anzahl aktualisierter Dateien in einer Ebene enthält?
Schritte zum Reproduzieren:
# make a dummy dir with a 64kb file in it
mkdir -p files
truncate -s 64k files/64k.file
# base container has a copy of the files
cat << EOF > Dockerfile.base
FROM ubuntu:16.04
COPY files/ /root/
EOF
# derived container should just have any updates
cat << EOF > Dockerfile.derived
FROM q899941:base
COPY files/ /root/
EOF
# build them....
docker build --file Dockerfile.base -t q899941:base .
docker build --file Dockerfile.derived -t q899941:derived .
# now let's review the layers
docker history q899941:derived
Ich erhalte dieses Ergebnis
IMAGE CREATED CREATED BY SIZE
4e1eb5168d55 Less than a second ago /bin/sh -c #(nop) COPY dir:8e20ede288278c71e… 65.5kB
022626ac5cf0 Less than a second ago /bin/sh -c #(nop) COPY dir:8e20ede288278c71e… 65.5kB
0458a4468cbc 5 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 5 weeks ago /bin/sh -c mkdir -p /run/systemd && echo 'do… 7B
<missing> 5 weeks ago /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$… 2.76kB
<missing> 5 weeks ago /bin/sh -c rm -rf /var/lib/apt/lists/* 0B
<missing> 5 weeks ago /bin/sh -c set -xe && echo '#!/bin/sh' > /… 745B
<missing> 5 weeks ago /bin/sh -c #(nop) ADD file:a3344b835ea6fdc56… 112MB
Die oberste Ebene ist 64 KB groß, obwohl sich keine Dateien geändert haben.
Antwort1
Es scheint, dies ist einbekanntes Problem, aber nicht eines, das genügend Leute interessiert!
- Gibt es eine Möglichkeit, einem Docker-Image nur geänderte Dateien als neue Ebene hinzuzufügen – ohne auf Docker-Commit zurückgreifen zu müssen?ist eine StackOverflow-Frage, die dasselbe Thema abdeckt.
- Es scheint, dass das erwartete Verhalten mit dem Overlay-Speichertreiber funktioniert hat, aber nach einigen Systemaktualisierungen begann ich, Overlay2 zu verwenden, das alle Dateien in eine Ebene kopiert und nicht nur die geänderten
- Eine mögliche Lösung wäre zwar die Rückkehr zum Overlay, diese scheint jedoch mittlerweile stark veraltet zu sein.Eine alternative Methode zum Erstellen von „Diff“-Ebenen wird hier ausführlich beschrieben.
Ich habe schließlich eine einfache Sache gemacht, die in einem derKommentareim Fehlerbericht:
#clean up any previous attempt...
docker rm -f uniquename 2> /dev/null
# now take your base container, mount the updated dir as /src
# then rsync from /src to the target dir - only updated files will
# actually be written, and we use --delete to ensure removed files are
# taken out...
docker run --name uniquename \
-v ~/repo/mycode:/src \
${REPO}/${IMAGE}:${BASE} \
rsync -ar --no-owner --no-group \
--exclude-from '/src/.dockerignore' --delete \
/src/ /app/
# we can commit that updated container with a tag
docker commit uniquename ${REPO}/${IMAGE}:${NEW_TAG}
Noch etwas: Diese Lösung schien die vorhandene zu löschen CMD
, die den Standardstartbefehl für meine Container bereitstellte. Nachdem ich diese Diff-Ebene hinzugefügt hatte, hatte ich also eine weitere Docker-Datei, um einen Container aus dem obigen „Diff“-Build mit dem CMD
hinzugefügten wieder zu erstellen.