Jak wygenerować plik dokowania z obrazu?

241

Czy można wygenerować plik dokowania z obrazu? Chcę wiedzieć z dwóch powodów:

  1. Mogę pobierać obrazy z repozytorium, ale chciałbym zobaczyć przepis, który je wygenerował.

  2. Podoba mi się pomysł zapisywania migawek, ale kiedy już to zrobię, dobrze byłoby mieć ustrukturyzowany format do przeglądu tego, co zostało zrobione.

użytkownik1026169
źródło
Możesz użyć Portainer.io portainer.io Jest to aplikacja internetowa działająca w kontenerze dokowanym służącym do zarządzania wszystkimi (prawie) rzeczami dotyczącymi twoich kontenerów. Nawet obrazy są odbierane.
Vincent

Odpowiedzi:

98

Jak wygenerować lub odwrócić plik dokowania z obrazu?

Możesz.

alias dfimage="docker run -v /var/run/docker.sock:/var/run/docker.sock --rm alpine/dfimage"
dfimage -sV=1.36 nginx:latest

Wyciągnie automatycznie docelowy obraz dokera i wyeksportuje Dockerfile. Parametr -sV=1.36nie zawsze jest wymagany.

Odniesienie: https://hub.docker.com/repository/docker/alpine/dfimage

poniżej jest stara odpowiedź, to już nie działa.

$ 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
BMW
źródło
3
Jest to sposób Dockera i powinien być oznaczony jako wybrana odpowiedź.
kytwb,
2
@jenson to nie jest dokładnie to samo, może pokryć 95%. Ale nie działa z zgniecionym obrazem.
BMW
5
@BMW Czy możesz pomóc w rozwiązaniu tego problemu z uruchomieniem obrazu z Twojego przykładu? /usr/lib/ruby/gems/2.2.0/gems/excon-0.45.4/lib/excon/unix_socket.rb:14:in `connect_nonblock ': odmowa połączenia - connect (2) dla / var / run / docker .sock (Errno :: ECONNREFUSED) (Excon :: Błędy :: SocketError)
długi
8
centurylink / dockerfile-from-image nie działa z dokerem nowej wersji. Ten działa dla mnie: hub.docker.com/r/chenzj/dfimage
aleung
6
imagelayers.io wydaje się być zepsuty. Nie może znaleźć żadnego obrazu, w tym jego demo
Robert Lugg
165

Aby zrozumieć, jak zbudowano obraz dokera, użyj docker history --no-truncpolecenia.

Możesz zbudować plik dokera z obrazu, ale nie będzie on zawierał wszystkiego, co chciałbyś w pełni zrozumieć, w jaki sposób obraz został wygenerowany. Rozsądnie można wyodrębnić części MAINTAINER, ENV, EXPOSE, VOLUME, WORKDIR, ENTRYPOINT, CMD i ONBUILD z pliku dockerfile.

Poniższy skrypt powinien działać dla Ciebie:

#!/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"

Używam tego jako części skryptu do odbudowywania działających kontenerów jako obrazów: https://github.com/docbill/docker-scripts/blob/master/docker-rebase

Plik Docker jest przydatny głównie, jeśli chcesz móc ponownie spakować obraz.

Należy pamiętać, że obraz dokera może być po prostu kopią zapasową tar rzeczywistej lub wirtualnej maszyny. W ten sposób wykonałem kilka obrazów dokerów. Nawet historia kompilacji pokazuje mi importowanie ogromnego pliku tar jako pierwszy krok w tworzeniu obrazu ...

użytkownik6856
źródło
1
Dostaje mnie: json: nie można odmazać tablicy na wartość Go typów typów.ContainerJSON
Mohsen
Czy możesz bardziej szczegółowo opisać swój ostatni komentarz? Czy wszystko jest w / tylko tar'owane normalnie? Czy są jakieś specjalne przypadki?
Robert Lugg
Myślę, że to odpowiedź 6-letnia, ale dostajęError response from daemon: page not found
João Ciocca
53

Jakoś absolutnie przegapiłem rzeczywiste polecenie w przyjętej odpowiedzi, więc tutaj znowu, nieco bardziej widoczne w swoim akapicie, zobaczyć, ile osób jest takich jak ja

$ docker history --no-trunc <IMAGE_ID>
użytkownik7610
źródło
1
Dlaczego więc potrzebujemy ub.docker.com/r/chenzj/dfimage? To nawet nowsza odpowiedź.
lucid_dreamer
3
Chyba dlatego, że docker historydrukuje wiersze Dockerfile w odwrotnej kolejności i upuszcza RUNinstrukcje (dostajesz tylko samo polecenie, a nie RUNklucz przed nim) i inne rzeczy, więc musisz go edytować ręcznie, aby dostać się do pliku Docker. To inne narzędzie może wykonać tę edycję automatycznie dla ciebie (nie próbowałem, więc nie wiem.)
user7610
@ user7610 twoje polecenie po prostu pokazuje historię ściągnięcia obrazu z centrum. Jak mogę zobaczyć moje polecenia na obrazach dokerów?
BarzanHayati,
@BarzanHayati Czy możesz zadać to pytanie jako nowe i połączyć je tutaj? Mów bardzo precyzyjnie. Pokaż polecenie, aby uruchomić obraz, a następnie wydaj kilka poleceń, które chcesz później zobaczyć, na przykład, a następnie zatrzymaj kontener (jeśli tak naprawdę robisz w rzeczywistości), a następnie zapytaj, jak pobrać wydane polecenia. Dzięki.
user7610,
1
@ user7610 Mógłbym o to zapytać, ale jak tylko o to poproszę, muszę go usunąć, ponieważ inni użytkownicy dają mi punkty ujemne za powtórzone pytanie.
BarzanHayati,
35

Rozwiązanie bash:

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

Wyjaśnienia krok po kroku:

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)

Przykład:

 ~  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
źródło
1
Najprostsze rozwiązanie. Dziękuję Ci!
user3576508
Nie dodaje to końcowego ukośnika odwrotnego, gdy rozbija wieloliniowe instrukcje RUN. Dodałem własną odpowiedź zainspirowaną tym.
Scott Centoni,
tac nie jest dostępny na Macu, więc możesz przejść na awk jak poniżej: | awk '{print NR, 0 $}' | sort -nr | sed 's / ^ [0-9] * //' |
phulei
11

W tym momencie nie jest to możliwe (chyba że autor obrazu wyraźnie dołączył plik Docker).

Jest to jednak zdecydowanie przydatne! Istnieją dwie rzeczy, które pomogą uzyskać tę funkcję.

  1. Zaufane kompilacje (szczegółowo omówione w tej dyskusji docker-dev)
  2. Bardziej szczegółowe metadane w kolejnych obrazach tworzonych przez proces kompilacji. Na dłuższą metę metadane powinny wskazywać, które polecenie kompilacji wytworzyło obraz, co oznacza, że ​​możliwe będzie zrekonstruowanie pliku Docker z sekwencji obrazów.
jpetazzo
źródło
8

Zaktualizuj grudzień 2018 do odpowiedzi 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
źródło
6

Wywodzi się to z odpowiedzi @ fallino, z pewnymi poprawkami i uproszczeniami poprzez użycie opcji formatu wyjściowego dla historii dokera . Ponieważ macOS i Gnu / Linux mają różne narzędzia wiersza poleceń, wymagana jest inna wersja dla komputerów Mac. Jeśli potrzebujesz tylko jednego lub drugiego, możesz po prostu użyć tych linii.

#!/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
źródło
5

docker pull chenzj/dfimage


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

dfimage image_id

poniżej jest ouput polecenia dfimage: -

$ dfimage 0f1947a021ce

Z węzła: 8 WORKDIR / usr / src / app

Plik COPY: e76d2e84545dedbe901b7b7b0c8d2c9733baa07cc821054efec48f623e29218c w ./

RUN / bin / sh -c npm install

KOPIA reż: a89a4894689a38cbf3895fdc0870878272bb9e09268149a87a6974a274b2184a w.

EKSPOZYCJA 8080

CMD [„npm” „start”]

użytkownik128364
źródło