引言
你是否曾经遇到过一个想要使用的 docker 镜像,但却无法修改以适应你的特定需求?或者你可能发现了一个喜欢的 docker 镜像,但想要了解它是如何构建的?在这两种情况下,将 docker 镜像逆向生成一个 dockerfile 可以使用一些工具来实现。
将 docker 镜像转换为 dockerfile 意味着获取现有的 docker 镜像,并使用它来创建一个你可以修改和控制的 dockerfile。
这个过程让你能够理解 docker 镜像的内部运作方式,进行修改,更新镜像以在不同平台上运行,或者根据特定需求对其进行优化。
在这篇博客文章中,我们将通过使用一些开源工具,带领您逐步解读 docker 镜像并转换为 dockerfile 的过程。
使用dedockify工具实现
docker 镜像就像黑匣子,包含了在镜像构建过程中执行的一系列指令层。
现在有了 dedockify,一个使用 python 脚本的工具,可以帮助重建创建镜像所使用的 dockerfile 的近似版本。
dedockify 的工作原理是利用存储在每个镜像层旁边的元数据。它通过沿着层级树向后遍历,收集与每个层相关联的命令。
这个过程使它能够重建在镜像构建过程中执行的命令序列。
然而,有一个问题:如果使用了 copy 或 add 指令,dedockify 生成的输出不会完全匹配原始的 dockerfile。这是因为 dedockify 无法访问在执行原始的 docker build 命令时存在的构建上下文。
要使用 dedockify,可以将其作为一个 docker 容器运行:
docker run -v /var/run/docker.sock:/var/run/docker.sock dedockify <imageid>
参数 <imageid>
是镜像 id(可以是缩短形式或完整的镜像 id)。
该脚本通过与 docker api 交互来查询各个镜像层的元数据,因此需要访问 docker api 套接字。上面显示的 -v 标志使得在运行脚本的容器内部可以使用 docker 套接字。
工作原理是什么?
当从 dockerfile 构建镜像时,dockerfile 中的每个指令都会生成一个新的层。您可以使用 docker images 命令和(现在已弃用的)--tree 标志来查看所有的镜像层。
$ docker images --tree warning: '--tree' is deprecated, it will be removed soon. see usage. └─511136ea3c5a virtual size: 0 b tags: scratch:latest └─1e8abad02296 virtual size: 121.8 mb └─f106b5d7508a virtual size: 121.8 mb └─0ae4b97648db virtual size: 690.2 mb └─a2df34bb17f4 virtual size: 808.3 mb tags: buildpack-deps:latest └─86258af941f7 virtual size: 808.6 mb └─1dc22fbdefef virtual size: 846.7 mb └─00227c86ea87 virtual size: 863.7 mb └─564e6df9f1e2 virtual size: 1.009 gb └─55a2d383d743 virtual size: 1.009 gb └─367e535883e4 virtual size: 1.154 gb └─a47bb557ed2a virtual size: 1.154 gb └─0d4496202bc0 virtual size: 1.157 gb └─5db44b586412 virtual size: 1.446 gb └─bef6f00c8d6d virtual size: 1.451 gb └─5f9bee597a47 virtual size: 1.451 gb └─bb98b84e0658 virtual size: 1.452 gb └─6556c531b6c1 virtual size: 1.552 gb └─569e14fd7575 virtual size: 1.552 gb └─fc3a205ba3de virtual size: 1.555 gb └─5fd3b530d269 virtual size: 1.555 gb └─6bdb3289ca8b virtual size: 1.555 gb └─011aa33ba92b virtual size: 1.555 gb tags: ruby:2, ruby:2.1, ruby:2.1.1, ruby:latest
这些层中的每一个都是在 dockerfile 中执行指令的结果。事实上,如果您对这些层中的任何一个执行 docker inspect,您可以看到用于生成该层的指令。
$ docker inspect 011aa33ba92b [{ . . . "containerconfig": { "cmd": [ "/bin/sh", "-c", "#(nop) onbuild run [ ! -e gemfile ] || bundle install --system" ], . . . }]
docker 示例:
以下是一个示例,展示了如何拉取官方的 docker ruby 镜像并生成该镜像的 dockerfile。
$ docker pull mrhavens/dedockify using default tag: latest latest: pulling from dedockify $ alias dedockify="docker run -v /var/run/docker.sock:/var/run/docker.sock --rm mrhavens/dedockify" $ dedockify <imageid> from buildpack-deps:latest run useradd -g users user run apt-get update && apt-get install -y bison procps run apt-get update && apt-get install -y ruby add dir:03090a5fdc5feb8b4f1d6a69214c37b5f6d653f5185cddb6bf7fd71e6ded561c in /usr/src/ruby workdir /usr/src/ruby run chown -r user:users . user user run autoconf && ./configure --disable-install-doc run make -j"$(nproc)" run make check user root run apt-get purge -y ruby run make install run echo 'gem: --no-rdoc --no-ri' >> /.gemrc run gem install bundler onbuild add . /usr/src/app onbuild workdir /usr/src/app onbuild run [ ! -e gemfile ] || bundle install --system
使用dive工具实现
dive 是一个用于探索 docker 镜像、层内容,并发现缩小 docker/oci 镜像大小的方法的工具。
dive 是一个用于探索 docker 镜像、层内容,并发现可以减小镜像大小的方法的工具。它提供了对每个层内容的详细分解,包括文件大小、权限等。特别适用于识别可以删除以减小镜像大小的不必要文件或依赖项。
特点:
- 详细的层内容分解:dive 提供了对 docker 或 oci 镜像中每个层内容的详细分解。它显示每个文件的大小、权限和其他元数据。
- 色彩编码界面:dive 使用色彩编码界面突出显示不同类型的文件。这使得识别并删除不必要的文件或依赖项变得容易。
- 交互式探索:dive 允许您交互式地探索每个层的内容。您可以浏览各个层、查看单个文件,并进行更改以优化您的镜像。
- 优化建议:dive 提供了优化镜像的建议。它识别大文件、不必要的依赖项和其他潜在的优化方案。
使用方法:
要使用 dive,您需要在系统上安装它,并针对一个 docker 或 oci 镜像运行它:
dive <imageid>
例如,要分析官方的 alpine linux 镜像,您可以运行:
dive alpine:latest
然后 dive 将显示镜像层的详细分解,让您可以探索每个层的内容并识别潜在的优化。
除了像 dive 这样的第三方工具外,我们可以立即使用的工具是 docker history。如果我们在示例1镜像上使用 docker history 命令,我们可以查看在 dockerfile 中用来创建该镜像的条目。
docker history nginx
因此,我们应该得到以下结果:
image created created by size comment
374e0127c1bc 25 minutes ago /bin/sh -c #(nop) copy file:aa717ff85b39d3ed… 0b
84acff3a5554 25 minutes ago /bin/sh -c #(nop) copy file:2a949ad55eee33f6… 0b
a9cc49948e40 25 minutes ago /bin/sh -c #(nop) copy file:e3c862873fa89cbf… 0b
请注意,created by 列中的所有内容都被截断了。这些是通过 bourne shell 传递的 dockerfile 指令。这些信息可能对重新创建我们的 dockerfile 有用,尽管在这里被截断了,但我们也可以通过使用 --no-trunc 选项来查看所有内容:
$ docker history example1 --no-trunc image created created by size comment sha256:374e0127c1bc51bca9330c01a9956be163850162f3c9f3be0340bb142bc57d81 29 minutes ago /bin/sh -c #(nop) copy file:aa717ff85b39d3ed034eed42bc1186230cfca081010d9dde956468decdf8bf20 in / 0b sha256:84acff3a5554aea9a3a98549286347dd466d46db6aa7c2e13bb77f0012490cef 29 minutes ago /bin/sh -c #(nop) copy file:2a949ad55eee33f6191c82c4554fe83e069d84e9d9d8802f5584c34e79e5622c in / 0b sha256:a9cc49948e40d15166b06dab42ea0e388f9905dfdddee7092f9f291d481467fc 29 minutes ago /bin/sh -c #(nop) copy file:e3c862873fa89cbf2870e2afb7f411d5367d37a4aea01f2620f7314d3370edcc in / 0b
虽然这里包含一些有用的数据,但从命令行解析可能会有些挑战。我们也可以使用 docker inspect。
dockerfile from image (dfimage)
类似于 docker history 命令的工作方式,python 脚本可以使用 docker 存储在每个镜像层旁边的元数据重新创建(近似地)用于生成镜像的 dockerfile。
https://github.com/laniksj/dfimage
python 脚本本身被打包为一个 docker 镜像,这样就可以很容易地使用 docker run 命令来执行:
docker run -v /var/run/docker.sock:/var/run/docker.sock dfimage ruby:latest
ruby:latest 参数是镜像名称和标签(可以是缩写形式或完整的镜像名称和标签)。
由于该脚本与 docker api 交互以查询各种镜像层的元数据,因此它需要访问 docker api 套接字。上面显示的 -v 标志使得 docker 套接字在运行脚本的容器内可用。
请注意,该脚本仅适用于存在于您本地镜像仓库中的镜像(即您在键入 docker images 时看到的内容)。如果要为本地仓库中不存在的镜像生成 dockerfile,则首先需要使用 docker pull 命令拉取该镜像。
总结
将 docker 镜像逆向工程为 dockerfile,或者称为“回溯 docker 镜像”,是一种有用的技术,可以帮助理解和重新创建镜像的构建过程。工具如 dive 和 dedockify 可以通过分析镜像层和元数据来生成相应的 dockerfile,从而提供帮助。
以上就是详解如何基于docker镜像逆向生成dockerfile的详细内容,更多关于docker镜像逆向生成dockerfile的资料请关注代码网其它相关文章!
发表评论