如何从图像生成Dockerfile ?

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

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

  2. 我喜欢保存快照的想法,但一旦我完成了,有一个结构化的格式来回顾所做的事情会很好。

298718 次浏览

在这一点上是不可能的(除非图像的作者显式地包含Dockerfile)。

然而,它绝对是有用的东西!有两件事将有助于获得这个特性。

  1. 可信构建(详见这个docker-dev讨论
  2. 构建过程生成的连续映像中的更详细的元数据。从长远来看,元数据应该指出是哪个构建命令生成了映像,这意味着可以从一系列映像重建Dockerfile。
要了解如何构建docker映像,请使用 docker history --no-trunc命令。< / p >

您可以从映像构建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 < / p >

如果您希望能够重新打包图像,Dockerfile主要是有用的。

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

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

你可以。主要是。

注意:它不会生成可以直接与docker build一起使用的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

现在,如果您选择一个特定的标记,hub.docker.com将直接使用详细命令显示图像层。

enter image description here

奖金

如果您想知道每一层中哪些文件被更改

alias dive="docker run -ti --rm  -v /var/run/docker.sock:/var/run/docker.sock wagoodman/dive"
dive nginx:latest

enter image description here

在左边,您可以看到每个层的命令,在右边(用tab跳转),黄线是该层中一些文件被更改的文件夹

(使用SPACE折叠目录)

旧的答案

下面是旧的答案,它不再工作了。

$ 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

不知何故,我完全错过了公认答案中的实际命令,所以在这里,它在自己的段落中更明显一些,看看有多少人像我一样

$ docker history --no-trunc <IMAGE_ID>

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的答案,通过使用码头工人的历史的输出格式选项进行了一些调整和简化。因为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

2018年12月更新宝马的答案

chenzj/dfimage -如hub.docker.com所述,从其他映像中重新生成Dockerfile。所以你可以这样使用它:

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

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 node:8
WORKDIR /usr/src/app


COPY file:e76d2e84545dedbe901b7b7b0c8d2c9733baa07cc821054efec48f623e29218c in ./
RUN /bin/sh -c npm install
COPY dir:a89a4894689a38cbf3895fdc0870878272bb9e09268149a87a6974a274b2184a in .


EXPOSE 8080
CMD ["npm" "start"]

image2df是什么

image2df是通过图像生成Dockerfile的工具。

这个工具是非常有用的,当你只有docker镜像,需要生成一个Dockerfile。

它是如何工作的

根据图像的历史信息进行反向解析。

如何使用这个图像

# Command alias
echo "alias image2df='docker run -v /var/run/docker.sock:/var/run/docker.sock --rm cucker/image2df'" >> ~/.bashrc
. ~/.bashrc


# Excute command
image2df <IMAGE>
  • < p >看帮助

    docker run --rm cucker/image2df --help
    
  • 例如< p >

    $ echo "alias image2df='docker run -v /var/run/docker.sock:/var/run/docker.sock --rm cucker/image2df'" >> ~/.bashrc
    $ . ~/.bashrc
    $ docker pull mysql
    $ image2df mysql
    
    
    ========== Dockerfile ==========
    FROM mysql:latest
    RUN groupadd -r mysql && useradd -r -g mysql mysql
    RUN apt-get update && apt-get install -y --no-install-recommends gnupg dirmngr && rm -rf /var/lib/apt/lists/*
    ENV GOSU_VERSION=1.12
    RUN set -eux; \
    savedAptMark="$(apt-mark showmanual)"; \
    apt-get update; \
    apt-get install -y --no-install-recommends ca-certificates wget; \
    rm -rf /var/lib/apt/lists/*; \
    dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \
    wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \
    wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \
    export GNUPGHOME="$(mktemp -d)"; \
    gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \
    gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \
    gpgconf --kill all; \
    rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \
    apt-mark auto '.*' > /dev/null; \
    [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark > /dev/null; \
    apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
    chmod +x /usr/local/bin/gosu; \
    gosu --version; \
    gosu nobody true
    RUN mkdir /docker-entrypoint-initdb.d
    RUN apt-get update && apt-get install -y --no-install-recommends \
    pwgen \
    openssl \
    perl \
    xz-utils \
    && rm -rf /var/lib/apt/lists/*
    RUN set -ex; \
    key='A4A9406876FCBD3C456770C88C718D3B5072E1F5'; \
    export GNUPGHOME="$(mktemp -d)"; \
    gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \
    gpg --batch --export "$key" > /etc/apt/trusted.gpg.d/mysql.gpg; \
    gpgconf --kill all; \
    rm -rf "$GNUPGHOME"; \
    apt-key list > /dev/null
    ENV MYSQL_MAJOR=8.0
    ENV MYSQL_VERSION=8.0.24-1debian10
    RUN echo 'deb http://repo.mysql.com/apt/debian/ buster mysql-8.0' > /etc/apt/sources.list.d/mysql.list
    RUN { \
    echo mysql-community-server mysql-community-server/data-dir select ''; \
    echo mysql-community-server mysql-community-server/root-pass password ''; \
    echo mysql-community-server mysql-community-server/re-root-pass password ''; \
    echo mysql-community-server mysql-community-server/remove-test-db select false; \
    } | debconf-set-selections \
    && apt-get update \
    && apt-get install -y \
    mysql-community-client="${MYSQL_VERSION}" \
    mysql-community-server-core="${MYSQL_VERSION}" \
    && rm -rf /var/lib/apt/lists/* \
    && rm -rf /var/lib/mysql && mkdir -p /var/lib/mysql /var/run/mysqld \
    && chown -R mysql:mysql /var/lib/mysql /var/run/mysqld \
    && chmod 1777 /var/run/mysqld /var/lib/mysql
    VOLUME [/var/lib/mysql]
    COPY dir:2e040acc386ebd23b8571951a51e6cb93647df091bc26159b8c757ef82b3fcda in /etc/mysql/
    COPY file:345a22fe55d3e6783a17075612415413487e7dba27fbf1000a67c7870364b739 in /usr/local/bin/
    RUN ln -s usr/local/bin/docker-entrypoint.sh /entrypoint.sh # backwards compat
    ENTRYPOINT ["docker-entrypoint.sh"]
    EXPOSE 3306 33060
    CMD ["mysqld"]
    
  • < p > 参考

如果您对Docker中心注册表中的图像感兴趣,并想查看Dockerfile?。

例子:

如果你想查看image "jupyter/ datasscience -notebook"输入单词“dockerfile”;在浏览器的地址栏中,如下所示。

https://hub.docker.com/r/jupyter/datascience-notebook/ enter image description here < / p >

https://hub.docker.com/r/jupyter/datascience-notebook/Dockerfile

enter image description here

< p >注意: 并不是所有的图像都有Dockerfile,例如https://hub.docker.com/r/redislabs/redisinsight/Dockerfile 有时这种方式比在Github中搜索Dockerfile快得多