Как сгенерировать Dockerfile из изображения?

241

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

  1. Я могу скачать изображения из репозитория, но хотел бы увидеть рецепт, который их сгенерировал.

  2. Мне нравится идея сохранения снимков, но как только я это сделаю, было бы неплохо иметь структурированный формат для просмотра того, что было сделано.

user1026169
источник
Вы можете использовать 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
BMW
источник
3
Это путь Docker и должен быть помечен как выбранный ответ.
kytwb
2
@ Дженсон это не совсем то же самое, может покрыть 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 ': соединение отклонено - connect (2) для / var / run / docker .sock (Errno :: ECONNREFUSED) (Excon :: Errors :: SocketError)
длинный
8
Centurylink / Dockerfile-from-image не работает с новой версией Docker. Этот работает для меня: hub.docker.com/r/chenzj/dfimage
aleung
6
imagelayers.io, кажется, сломан. Он не может найти ни одного изображения, включая свои демонстрационные
Роберт Лугг
165

Чтобы понять, как был создан образ докера, используйте docker history --no-truncкоманду.

Вы можете создать файл Docker из изображения, но он не будет содержать всего, что вы хотели бы полностью понять, как было сгенерировано изображение. Разумно то, что вы можете извлечь, это части Dockerfile: 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-файл как первый шаг в создании образа ...

user6856
источник
1
Это заставляет меня: JSON: не может распаковать массив в значение Go типа types.ContainerJSON
Мохсен
Можете ли вы описать свой последний комментарий более подробно? Все в / только смонтировано как обычно? Или есть особые случаи?
Роберт Лугг
Я считаю, что это 6-летний ответ, но я получаюError response from daemon: page not found
Жоау Чокка
53

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

$ docker history --no-trunc <IMAGE_ID>
user7610
источник
1
Так зачем нам ub.docker.com/r/chenzj/dfimage? Это даже более свежий ответ.
lucid_dreamer
3
Я думаю, потому что docker historyпечатает строки Dockerfile в обратном порядке, и он отбрасывает RUNинструкции (вы получаете только саму команду, а не RUNkeyworkd перед ней) и другие вещи, так что вам нужно отредактировать ее вручную, чтобы получить готовый Dockerfile. Этот другой инструмент может сделать это редактирование автоматически для вас (я не пробовал, поэтому я не знаю.)
user7610
@ user7610 ваша команда просто показывает историю вытащенного изображения из концентратора. Как я могу увидеть мои команды на изображениях докера?
BarzanHayati
@BarzanHayati Можете ли вы задать новый вопрос и связать его здесь? Будьте очень конкретны, когда спрашиваете. Покажите команду для запуска изображения, затем выполните несколько команд, которые вы хотите позже увидеть, в качестве примера, затем остановите контейнер (если это то, что вы действительно делаете в реальности), а затем спросите, как получить введенные команды. Спасибо.
user7610
1
@ user7610 Я мог бы спросить это, но как только я спросил это, я должен удалить это, потому что другие пользователи дают мне минусовые очки за повторный вопрос.
BarzanHayati
35

Решение 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

Пошаговые пояснения:

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"]
fallino
источник
1
Самое простое решение. Спасибо!
user3576508
Это не добавляет обратную косую черту, когда она разбивает многострочные операторы RUN. Я добавил свой собственный ответ, вдохновленный этим.
Скотт Чентони
TAC недоступен на Mac, поэтому вы можете перейти к awk, как показано ниже: | awk '{print NR, $ 0}' | сортировать -nr | sed 's / ^ [0-9] * //' |
phulei
11

На данный момент это невозможно (если автор изображения явно не включил Dockerfile).

Тем не менее, это определенно что-то полезное! Есть две вещи, которые помогут получить эту функцию.

  1. Надежные сборки (подробно в этом обсуждении docker-dev
  2. Более подробные метаданные в последовательных изображениях, создаваемых в процессе сборки. В долгосрочной перспективе метаданные должны указывать, какая команда построения создала образ, а это значит, что будет возможно восстановить Dockerfile из последовательности изображений.
jpetazzo
источник
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
AndrewD
источник
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

Файл COPY: e76d2e84545dedbe901b7b7b0c8d2c9733baa07cc821054efec48f623e29218c in ./

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

COPY dir: a89a4894689a38cbf3895fdc0870878272bb9e09268149a87a6974a274b2184a в.

ЭКСПОЗИЦИЯ 8080

CMD ["npm" "start"]

user128364
источник