如何从映像生成Dockerfile?


241

是否可以从映像生成Dockerfile?我想知道有两个原因:

  1. 我可以从存储库下载图像,但希望查看生成它们的配方。

  2. 我喜欢保存快照的想法,但是一旦完成,最好有一种结构化的格式来查看所做的事情。


您可以使用Portainer.io portainer.io这是一个Web应用程序是一个码头工人容器内运行用来管理你所有的容器(几乎)的东西。甚至图像也可以接收。
文森特

Answers:


98

如何从映像生成或反转Dockerfile?

您可以。

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

它将自动拉出目标docker映像并导出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
这是Docker方式,应标记为已选择答案。
kytwb 2015年

2
@jenson并不完全相同,可以覆盖95%。但不适用于压缩的图像。
宝马

5
@BMW您能帮您解决示例中运行映像的问题吗?/usr/lib/ruby/gems/2.2.0/gems/excon-0.45.4/lib/excon/unix_socket.rb:14:在connect_nonblock中:拒绝连接-/ var / run / docker的connect(2) .sock(错误:: ECONNREFUSED)(EXCON ::错误:: SocketError)

8
Centurylink / dockerfile-from-image不适用于新版本的docker。这对我有用
aleung

6
imagelayers.io似乎坏了。它找不到任何图像,包括演示图像
Robert Lugg

165

要了解如何构建docker映像,请使用 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主要有用。

要记住的是,Docker镜像实际上只能是真实或虚拟机的tar备份。我已经用这种方式制作了几个docker镜像。甚至构建历史记录也显示了我导入一个巨大的tar文件作为创建映像的第一步...


1
它得到我:json:无法将数组解组为类型type的Go值。ContainerJSON–
Mohsen

您能否更详细地描述您的最后评论?一切都正常吗?还是有特殊情况?
罗伯特·拉格

我认为这是一个6yo的答案,但我越来越Error response from daemon: page not found
若昂CIOCCA

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您的命令仅显示从集线器提取图像的历史记录。我如何在docker映像上看到我的命令?
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"]

1
最直接的解决方案。谢谢!
user3576508

当它破坏多行RUN语句时,它不会添加结尾的反斜杠。受此启发,我添加了自己的答案。
Scott Centoni,

tac在Mac上不可用,因此您可以像下面这样使用awk:awk'{print NR,$ 0}'| 排序-nr | sed's / ^ [0-9] * //'|
phulei

11

在这一点上是不可能的(除非映像的作者明确包含Dockerfile)。

但是,这绝对是有用的!有两件事将有助于获得此功能。

  1. 受信任的构建(在此docker-dev讨论中详细介绍
  2. 构建过程产生的连续图像中的更详细的元数据。从长远来看,元数据应指示生成该映像的生成命令,这意味着可以从一系列映像中重建Dockerfile。

8

更新2018年12月宝马的答案

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

FROM节点:8 WORKDIR / usr / src / app

COPY文件:./中的e76d2e84545dedbe901b7b7b0c8d2c9733baa07cc821054efec48f623e29218c

运行/ bin / sh -c npm install

COPY dir:中的a89a4894689a38cbf3895fdc0870878272bb9e09268149a87a6974a274b2184a。

展览8080

CMD [“ npm”“开始”]

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.