Як створити Dockerfile із зображення?


241

Чи можливо генерувати Dockerfile із зображення? Я хочу знати з двох причин:

  1. Я можу завантажити зображення з сховища, але хотів би побачити рецепт, який їх створив.

  2. Мені подобається ідея збереження знімків, але як тільки я закінчу, було б непогано мати структурований формат для перегляду зробленого.


Ви можете використовувати Portainer.io portainer.io Це веб-додаток, який працює всередині контейнера докера, який використовується для управління всіма (майже) речами про ваші контейнери. Навіть зображення рецепти.
Вінсент

Відповіді:


98

Як генерувати або повертати Dockerfile із зображення?

Ти можеш.

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

Він автоматично витягне цільове зображення докера та експортує Dockerfile. Параметр -sV=1.36не завжди потрібен.

Довідка: https://hub.docker.com/repository/docker/alpine/dfimage

нижче - стара відповідь, вона більше не працює.

$ 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

3
Це Докерський шлях і його слід позначати як обрану відповідь.
kytwb

2
@jenson це не зовсім точно, може покрити 95%. Але не спрацьовує зі стислим зображенням.
BMW

5
@BMW Чи можете ви допомогти вирішити цю проблему із запуском зображення зі свого прикладу? /usr/lib/ruby/gems/2.2.0/gems/excon-0.45.4/lib/excon/unix_socket.rb:14:in `connect_nonblock ': Підключення відхилено - підключити (2) для / var / run / docker .sock (Errno :: ECONNREFUSED) (Excon :: Помилки :: SocketError)
довгий

8
centurylink / dockerfile-from-image не працює з докер-новою версією. Цей для мене працює: hub.docker.com/r/chenzj/dfimage
aleung

6
imagelayers.io, здається, зламаний. Він не може знайти жодного зображення, включаючи його демо
Роберт Лугг

165

Щоб зрозуміти, як побудовано зображення докера, скористайтеся docker history --no-truncкомандою.

Ви можете створити файл докера з зображення, але він не буде містити все, що ви хотіли б повністю зрозуміти, як генерується зображення. Розумно, що ви можете витягти, це частини MAINTAINER, ENV, EXPOSE, VOLUME, WORKDIR, ENTRYPOINT, CMD та ONBUILD докерфайлу.

Наступний сценарій повинен працювати для вас:

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

Я використовую це як частину сценарію для відновлення запущених контейнерів у вигляді зображень: https://github.com/docbill/docker-scripts/blob/master/docker-rebase

Dockerfile в основному корисний, якщо ви хочете мати можливість перепакувати зображення.

Що потрібно пам’ятати, це те, що зображення докера може бути фактично резервним копією реального або віртуальної машини. Я зробив кілька зображень докера таким чином. Навіть історія збірки показує, що я імпортує величезний файл tar, як перший крок у створенні зображення ...


1
Це отримує мене: json: не може зняти масивний масив у значенні Go type type.ContainerJSON
Mohsen

Чи можете ви описати свій останній коментар детальніше? Чи все в / просто таргетовано як нормально? Або є особливі випадки?
Роберт Лугг

Я вважаю, що це відповідь 6, але я отримуюError response from daemon: page not found
Жоао Ціокка,

53

Я якось абсолютно пропустив фактичну команду у прийнятій відповіді, тому ось вона знову, трохи видніша у власному абзаці, щоб побачити, скільки людей схожі на мене

$ docker history --no-trunc <IMAGE_ID>

1
То навіщо нам це потрібно ub.docker.com/r/chenzj/dfimage? Це навіть більш свіжа відповідь.
lucid_dreamer

3
Я здогадуюсь, тому що docker historyдрукує рядки Dockerfile у зворотному порядку, і він видаляє RUNінструкції (ви отримуєте лише саму команду, а не RUNклавіатуру перед нею) та інші речі, тому вам потрібно відредагувати її вручну, щоб дістатися до Dockerfile, який можна скласти. Цей інший інструмент може зробити це редагування автоматично для вас (я його не пробував, тому не знаю.)
user7610

@ user7610 ваша команда просто показує історію витягнутого зображення з концентратора. Як я міг бачити свої команди на докерських зображеннях?
BarzanHayati

@BarzanHayati Чи можете ви задати це питання як нове запитання та зв’язати його тут? Будьте дуже конкретні, коли запитуєте. Покажіть команду для запуску зображення, а потім видайте кілька команд, які ви хочете пізніше побачити, як приклад, потім зупиніть контейнер (якщо це насправді робиться насправді), а потім запитайте, як отримати видані команди. Дякую.
користувач7610

1
@ user7610 Я міг би його задати, але як тільки я його запитав, я повинен його видалити, оскільки інші користувачі дають мені мінус балів за повторне запитання.
BarzanHayati

35

Баш-рішення:

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

Покрокові пояснення:

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)

Приклад:

 ~  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"]

1
Найпростіше рішення. Дякую!
користувач3576508

Це не додає зворотної косої риски, коли вона розбиває багаторядкові оператори RUN. Я додав власну відповідь, натхненну цим.
Скотт Сентоні

tac недоступний на mac, тому ви можете піти на awk, як нижче: | awk '{print NR, $ 0}' | сортувати -nr | sed 's / ^ [0-9] * //' |
фулей

11

Наразі це неможливо (якщо тільки автор зображення явно не включив Dockerfile).

Однак це, безумовно, щось корисне! Є дві речі, які допоможуть отримати цю функцію.

  1. Довірені складання (детально описано в цій дискусії про docker-dev
  2. Більш детальні метадані в послідовних зображеннях, отриманих процесом збирання. У перспективі метадані повинні вказувати, яка команда побудови створювала зображення, а це означає, що можна буде реконструювати Dockerfile із послідовності зображень.

8

Оновіть грудень 2018 року на відповідь 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

6

Це отримується з відповіді @ fallino, з деякими коригуваннями та спрощеннями, використовуючи параметр вихідного формату для історії докера . Оскільки macOS та Gnu / Linux мають різні утиліти командного рядка, для Mac потрібна інша версія. Якщо вам потрібен лише той чи інший, ви можете просто використовувати ці рядки.

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

5

docker pull chenzj/dfimage


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

dfimage image_id

нижче - вихід команди dfimage: -

$ dfimage 0f1947a021ce

ВІД вузла: 8 WORKDIR / usr / src / app

Файл копіювання: e76d2e84545dedbe901b7b7b0c8d2c9733baa07cc821054efec48f623e29218c в ./

RUN / bin / sh -c npm встановити

COPY dir: a89a4894689a38cbf3895fdc0870878272bb9e09268149a87a6974a274b2184a в.

ВИДАЧА 8080

CMD ["npm" "start"]

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.