Wie generiere ich eine Docker-Datei aus einem Bild?

241

Ist es möglich, aus einem Bild eine Docker-Datei zu generieren? Ich möchte aus zwei Gründen wissen:

  1. Ich kann Bilder aus dem Repository herunterladen, möchte aber das Rezept sehen, das sie generiert hat.

  2. Ich mag die Idee, Schnappschüsse zu speichern, aber wenn ich fertig bin, wäre es schön, ein strukturiertes Format zu haben, um zu überprüfen, was getan wurde.

user1026169
quelle
Sie können Portainer.io verwenden portainer.io Es handelt sich um eine Web-App, die in einem Docker-Container ausgeführt wird, mit dem alle (fast) Inhalte Ihrer Container verwaltet werden. Sogar Bilder werden empfangen.
Vincent

Antworten:

98

Aktualisieren:

Zitat aus @ aleungs Kommentar:

centurylink/dockerfile-from-imagefunktioniert nicht mit Docker der neuen Version. Dieser funktioniert für mich:hub.docker.com/r/chenzj/dfimage

Wie generiere ich eine Docker-Datei aus einem Bild?

Sie können.

Erster Weg

$ docker pull centurylink/dockerfile-from-image
$ alias dfimage="docker run -v /var/run/docker.sock:/var/run/docker.sock --rm centurylink/dockerfile-from-image"
$ dfimage --help
Usage: dockerfile-from-image.rb [options] <image_id>
    -f, --full-tree                  Generate Dockerfile for all parent layers
    -h, --help                       Show this message

Hier ist das Beispiel zum Generieren der Docker-Datei aus einem vorhandenen Image selenium/node-firefox-debug

core@core-01 ~ $ docker pull centurylink/dockerfile-from-image
core@core-01 ~ $ alias dfimage="docker run -v /var/run/docker.sock:/var/run/docker.sock --rm centurylink/dockerfile-from-image"
core@core-01 ~ $ dfimage selenium/node-firefox-debug
ADD file:b43bf069650bac07b66289f35bfdaf474b6b45cac843230a69391a3ee342a273 in /
RUN echo '#!/bin/sh' > /usr/sbin/policy-rc.d    && echo 'exit 101' >> /usr/sbin/policy-rc.d     && chmod +x /usr/sbin/policy-rc.d       && dpkg-divert --local --rename --add /sbin/initctl     && cp -a /usr/sbin/policy-rc.d /sbin/initctl    && sed -i 's/^exit.*/exit 0/' /sbin/initctl         && echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup         && echo 'DPkg::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' > /etc/apt/apt.conf.d/docker-clean   && echo 'APT::Update::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' >> /etc/apt/apt.conf.d/docker-clean   && echo 'Dir::Cache::pkgcache ""; Dir::Cache::srcpkgcache "";' >> /etc/apt/apt.conf.d/docker-clean      && echo 'Acquire::Languages "none";' > /etc/apt/apt.conf.d/docker-no-languages      && echo 'Acquire::GzipIndexes "true"; Acquire::CompressionTypes::Order:: "gz";' > /etc/apt/apt.conf.d/docker-gzip-indexes
RUN sed -i 's/^#\s*\(deb.*universe\)$/\1/g' /etc/apt/sources.list
CMD ["/bin/bash"]
MAINTAINER Selenium <[email protected]>
RUN echo "deb http://archive.ubuntu.com/ubuntu trusty main universe\n" > /etc/apt/sources.list && echo "deb http://archive.ubuntu.com/ubuntu trusty-updates main universe\n" >> /etc/apt/sources.list
RUN apt-get update -qqy && apt-get -qqy --no-install-recommends install ca-certificates openjdk-7-jre-headless unzip wget && rm -rf /var/lib/apt/lists/* && sed -i 's/\/dev\/urandom/\/dev\/.\/urandom/' ./usr/lib/jvm/java-7-openjdk-amd64/jre/lib/security/java.security
RUN mkdir -p /opt/selenium && wget --no-verbose http://selenium-release.storage.googleapis.com/2.46/selenium-server-standalone-2.46.0.jar -O /opt/selenium/selenium-server-standalone.jar
RUN sudo useradd seluser --shell /bin/bash --create-home && sudo usermod -a -G sudo seluser && echo 'ALL ALL = (ALL) NOPASSWD: ALL' >> /etc/sudoers && echo 'seluser:secret' | chpasswd
MAINTAINER Selenium <[email protected]>
ENV DEBIAN_FRONTEND=noninteractive
ENV DEBCONF_NONINTERACTIVE_SEEN=true
ENV TZ=US/Pacific
RUN echo "US/Pacific" | sudo tee /etc/timezone && dpkg-reconfigure --frontend noninteractive tzdata
RUN apt-get update -qqy && apt-get -qqy install xvfb && rm -rf /var/lib/apt/lists/*
COPY file:335d2f6f9bfe311d2b38034ceab3b2ae2a1e07b9b203b330cac9857d6e17c148 in /opt/bin/entry_point.sh
RUN chmod +x /opt/bin/entry_point.sh
ENV SCREEN_WIDTH=1360
ENV SCREEN_HEIGHT=1020
ENV SCREEN_DEPTH=24
ENV DISPLAY=:99.0
USER [seluser]
CMD ["/opt/bin/entry_point.sh"]
MAINTAINER Selenium <[email protected]>
USER [root]
RUN apt-get update -qqy && apt-get -qqy --no-install-recommends install firefox && rm -rf /var/lib/apt/lists/*
COPY file:52a2a815e3bb6b85c5adfbceaabb5665b63f63ef0fb0e3f774624ee399415f84 in /opt/selenium/config.json
USER [seluser]
MAINTAINER Selenium <[email protected]>
USER [root]
RUN apt-get update -qqy && apt-get -qqy install x11vnc && rm -rf /var/lib/apt/lists/* && mkdir -p ~/.vnc && x11vnc -storepasswd secret ~/.vnc/passwd
ENV LANGUAGE=en_US.UTF-8
ENV LANG=en_US.UTF-8
RUN locale-gen en_US.UTF-8 && dpkg-reconfigure --frontend noninteractive locales && apt-get update -qqy && apt-get -qqy --no-install-recommends install language-pack-en && rm -rf /var/lib/apt/lists/*
RUN apt-get update -qqy && apt-get -qqy --no-install-recommends install fonts-ipafont-gothic xfonts-100dpi xfonts-75dpi xfonts-cyrillic xfonts-scalable && rm -rf /var/lib/apt/lists/*
RUN apt-get update -qqy && apt-get -qqy install fluxbox && rm -rf /var/lib/apt/lists/*
COPY file:90e3a7f757c3df44d541b59234ad4ca996f799455eb8d426218619b244ebba68 in /opt/bin/entry_point.sh
RUN chmod +x /opt/bin/entry_point.sh
EXPOSE 5900/tcp

Zweiter Weg

Hier müssen Sie das Image nicht auf lokal ziehen und es muss kein Befehl ausgeführt werden.

Wenn Sie das obige Bild als Beispiel verwenden, können Sie Dockerfile-Befehle über die folgende URL abrufen:

https://imagelayers.io/?images=selenium%2Fnode-firefox-debug:latest

Warten Sie eine Weile, es werden zwei Fenster angezeigt, das Aufwärtsfenster listet die Ebenen auf, das Abwärtsfenster listet den Befehl in Dockerfile auf

imagelayers.io Screenshot

Das URL-Format lautet:

https://imagelayers.io/?images=<USER>%2F<IMAGE>:<TAG>

In der Tat wird imagelayers.io von gebaut Centurylink

BMW
quelle
3
Dies ist der Docker-Weg und sollte als ausgewählte Antwort markiert werden.
Kytwb
2
@jenson es ist nicht genau das gleiche, kann 95% abdecken. Funktioniert aber nicht mit gequetschtem Bild.
BMW
5
@BMW Könnten Sie bitte helfen, dieses Problem zu beheben, indem Sie das Image aus Ihrem Beispiel ausführen? /usr/lib/ruby/gems/2.2.0/gems/excon-0.45.4/lib/excon/unix_socket.rb:14:in `connect_nonblock ': Verbindung abgelehnt - connect (2) für / var / run / docker .sock (Errno :: ECONNREFUSED) (Excon :: Errors :: SocketError)
lange
8
centurylink / dockerfile-from-image funktioniert nicht mit Docker der neuen Version. Dieser funktioniert für mich: hub.docker.com/r/chenzj/dfimage
aleung
6
imagelayers.io scheint kaputt zu sein. Es kann kein Bild finden, einschließlich seiner Demos
Robert Lugg
165

Verwenden Sie den docker history --no-truncBefehl , um zu verstehen, wie ein Docker-Image erstellt wurde .

Sie können eine Docker-Datei aus einem Image erstellen, diese enthält jedoch nicht alles, was Sie vollständig verstehen möchten, wie das Image generiert wurde. Sie können vernünftigerweise die Teile MAINTAINER, ENV, EXPOSE, VOLUME, WORKDIR, ENTRYPOINT, CMD und ONBUILD der Docker-Datei extrahieren.

Das folgende Skript sollte für Sie funktionieren:

#!/bin/bash
docker history --no-trunc "$1" | \
sed -n -e 's,.*/bin/sh -c #(nop) \(MAINTAINER .*[^ ]\) *0 B,\1,p' | \
head -1
docker inspect --format='{{range $e := .Config.Env}}
ENV {{$e}}
{{end}}{{range $e,$v := .Config.ExposedPorts}}
EXPOSE {{$e}}
{{end}}{{range $e,$v := .Config.Volumes}}
VOLUME {{$e}}
{{end}}{{with .Config.User}}USER {{.}}{{end}}
{{with .Config.WorkingDir}}WORKDIR {{.}}{{end}}
{{with .Config.Entrypoint}}ENTRYPOINT {{json .}}{{end}}
{{with .Config.Cmd}}CMD {{json .}}{{end}}
{{with .Config.OnBuild}}ONBUILD {{json .}}{{end}}' "$1"

Ich verwende dies als Teil eines Skripts, um laufende Container als Bilder neu zu erstellen: https://github.com/docbill/docker-scripts/blob/master/docker-rebase

Die Docker-Datei ist hauptsächlich nützlich, wenn Sie ein Bild neu verpacken möchten.

Zu beachten ist, dass ein Docker-Image eigentlich nur die Teersicherung einer realen oder virtuellen Maschine sein kann. Auf diese Weise habe ich mehrere Docker-Bilder erstellt. Sogar der Build-Verlauf zeigt mir, wie ich als ersten Schritt beim Erstellen des Images eine riesige TAR-Datei importiere ...

user6856
quelle
1
Es bringt mich: json: Array kann nicht in Go-Wert vom Typ Typ entmarschiert werden.ContainerJSON
Mohsen
Können Sie Ihren letzten Kommentar genauer beschreiben? Ist alles in / nur wie gewohnt geplant? Oder gibt es Sonderfälle?
Robert Lugg
Ich denke, dies ist eine 6-jährige Antwort, aber ich bekommeError response from daemon: page not found
João Ciocca
53

Ich habe den eigentlichen Befehl in der akzeptierten Antwort irgendwie absolut verpasst, also ist es hier wieder etwas sichtbarer in seinem eigenen Absatz, zu sehen, wie viele Leute wie ich sind

$ docker history --no-trunc <IMAGE_ID>
user7610
quelle
1
Warum brauchen wir also ub.docker.com/r/chenzj/dfimage? Es ist sogar eine neuere Antwort.
lucid_dreamer
3
Ich denke, weil docker historydie Dockerfile-Zeilen in umgekehrter Reihenfolge gedruckt werden und die RUNAnweisungen (Sie erhalten nur den Befehl selbst, nicht das RUNKeyworkd davor) und andere Dinge gelöscht werden, müssen Sie sie manuell bearbeiten, um zu einer baubaren Dockerfile zu gelangen. Das andere Tool kann diese Bearbeitung automatisch für Sie durchführen (ich habe es nicht ausprobiert, daher weiß ich es nicht.)
user7610
@ user7610 Ihr Befehl zeigt nur den Verlauf des vom Hub gezogenen Bildes an. Wie kann ich meine Befehle auf Docker-Bildern sehen?
BarzanHayati
@BarzanHayati Kannst du es als neue Frage stellen und hier verlinken? Seien Sie sehr genau, wenn Sie fragen. Zeigen Sie den Befehl zum Starten des Bildes an, geben Sie dann einige Befehle aus, die Sie später als Beispiel sehen möchten, stoppen Sie dann den Container (wenn Sie dies tatsächlich tun) und fragen Sie, wie Sie die ausgegebenen Befehle abrufen können. Vielen Dank.
user7610
1
@ user7610 Ich könnte es fragen, aber sobald ich es gefragt habe, muss ich es löschen, weil andere Benutzer mir Minuspunkte für wiederholte Fragen geben.
BarzanHayati
34

Eine Bash-Lösung:

docker history --no-trunc $argv  | tac | tr -s ' ' | cut -d " " -f 5- | sed 's,^/bin/sh -c #(nop) ,,g' | sed 's,^/bin/sh -c,RUN,g' | sed 's, && ,\n  & ,g' | sed 's,\s*[0-9]*[\.]*[0-9]*\s*[kMG]*B\s*$,,g' | head -n -1

Schritt für Schritt Erklärungen:

tac : reverse the file
tr -s ' '                                       trim multiple whitespaces into 1
cut -d " " -f 5-                                remove the first fields (until X months/years ago)
sed 's,^/bin/sh -c #(nop) ,,g'                  remove /bin/sh calls for ENV,LABEL...
sed 's,^/bin/sh -c,RUN,g'                       remove /bin/sh calls for RUN
sed 's, && ,\n  & ,g'                           pretty print multi command lines following Docker best practices
sed 's,\s*[0-9]*[\.]*[0-9]*\s*[kMG]*B\s*$,,g'      remove layer size information
head -n -1                                      remove last line ("SIZE COMMENT" in this case)

Beispiel:

 ~  dih ubuntu:18.04
ADD file:28c0771e44ff530dba3f237024acc38e8ec9293d60f0e44c8c78536c12f13a0b in /
RUN set -xe
   &&  echo '#!/bin/sh' > /usr/sbin/policy-rc.d
   &&  echo 'exit 101' >> /usr/sbin/policy-rc.d
   &&  chmod +x /usr/sbin/policy-rc.d
   &&  dpkg-divert --local --rename --add /sbin/initctl
   &&  cp -a /usr/sbin/policy-rc.d /sbin/initctl
   &&  sed -i 's/^exit.*/exit 0/' /sbin/initctl
   &&  echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup
   &&  echo 'DPkg::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' > /etc/apt/apt.conf.d/docker-clean
   &&  echo 'APT::Update::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' >> /etc/apt/apt.conf.d/docker-clean
   &&  echo 'Dir::Cache::pkgcache ""; Dir::Cache::srcpkgcache "";' >> /etc/apt/apt.conf.d/docker-clean
   &&  echo 'Acquire::Languages "none";' > /etc/apt/apt.conf.d/docker-no-languages
   &&  echo 'Acquire::GzipIndexes "true"; Acquire::CompressionTypes::Order:: "gz";' > /etc/apt/apt.conf.d/docker-gzip-indexes
   &&  echo 'Apt::AutoRemove::SuggestsImportant "false";' > /etc/apt/apt.conf.d/docker-autoremove-suggests
RUN rm -rf /var/lib/apt/lists/*
RUN sed -i 's/^#\s*\(deb.*universe\)$/\1/g' /etc/apt/sources.list
RUN mkdir -p /run/systemd
   &&  echo 'docker' > /run/systemd/container
CMD ["/bin/bash"]
Fallino
quelle
1
Die einfachste Lösung. Danke dir!
user3576508
Dies fügt keinen abschließenden Backslash hinzu, wenn mehrzeilige RUN-Anweisungen aufgelöst werden. Ich habe meine eigene Antwort hinzugefügt, die davon inspiriert ist.
Scott Centoni
tac ist auf dem Mac nicht verfügbar, daher können Sie sich wie folgt für awk entscheiden: | awk '{print NR, $ 0}' | sort -nr | sed 's / ^ [0-9] * //' |
Phulei
11

Dies ist derzeit nicht möglich (es sei denn, der Autor des Bildes hat die Docker-Datei ausdrücklich angegeben).

Es ist jedoch definitiv etwas Nützliches! Es gibt zwei Dinge, die helfen, diese Funktion zu erhalten.

  1. Vertrauenswürdige Builds (detailliert in dieser Docker-Dev-Diskussion
  2. Detailliertere Metadaten in den aufeinanderfolgenden Bildern, die durch den Erstellungsprozess erstellt wurden. Auf lange Sicht sollten die Metadaten angeben, welcher Erstellungsbefehl das Bild erzeugt hat, was bedeutet, dass es möglich sein wird, die Docker-Datei aus einer Folge von Bildern zu rekonstruieren.
jpetazzo
quelle
8

Update Dezember 2018 auf die Antwort von BMW

docker pull chenzj/dfimage
alias dfimage="docker run -v /var/run/docker.sock:/var/run/docker.sock --rm chenzj/dfimage"
dfimage IMAGE_ID > Dockerfile
AndrewD
quelle
6

Dies ergibt sich aus der Antwort von @ fallino mit einigen Anpassungen und Vereinfachungen unter Verwendung der Ausgabeformatoption für den Docker-Verlauf . Da macOS und Gnu / Linux unterschiedliche Befehlszeilenprogramme haben, ist für Mac eine andere Version erforderlich. Wenn Sie nur die eine oder andere benötigen, können Sie nur diese Zeilen verwenden.

#!/bin/bash
case "$OSTYPE" in
    linux*)
        docker history --no-trunc --format "{{.CreatedBy}}" $1 | # extract information from layers
        tac                                                    | # reverse the file
        sed 's,^\(|3.*\)\?/bin/\(ba\)\?sh -c,RUN,'             | # change /bin/(ba)?sh calls to RUN
        sed 's,^RUN #(nop) *,,'                                | # remove RUN #(nop) calls for ENV,LABEL...
        sed 's,  *&&  *, \\\n \&\& ,g'                           # pretty print multi command lines following Docker best practices
    ;;
    darwin*)
        docker history --no-trunc --format "{{.CreatedBy}}" $1 | # extract information from layers
        tail -r                                                | # reverse the file
        sed -E 's,^(\|3.*)?/bin/(ba)?sh -c,RUN,'               | # change /bin/(ba)?sh calls to RUN
        sed 's,^RUN #(nop) *,,'                                | # remove RUN #(nop) calls for ENV,LABEL...
        sed $'s,  *&&  *, \\\ \\\n \&\& ,g'                      # pretty print multi command lines following Docker best practices
    ;;
    *)
        echo "unknown OSTYPE: $OSTYPE"
    ;;
esac
Scott Centoni
quelle
5

docker pull chenzj/dfimage


alias dfimage="docker run -v /var/run/docker.sock:/var/run/docker.sock --rm chenzj/dfimage"

dfimage image_id

unten ist die Ausgabe des Befehls dfimage: -

$ dfimage 0f1947a021ce

VON Knoten: 8 WORKDIR / usr / src / app

COPY-Datei: e76d2e84545dedbe901b7b7b0c8d2c9733baa07cc821054efec48f623e29218c in ./

RUN / bin / sh -c npm installieren

COPY dir: a89a4894689a38cbf3895fdc0870878272bb9e09268149a87a6974a274b2184a in.

EXPOSE 8080

CMD ["npm" "start"]

user128364
quelle