4

如何基于Docker镜像逆向生成Dockerfile

 6 months ago
source link: https://www.51cto.com/article/783071.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

如何基于Docker镜像逆向生成Dockerfile

2024-03-06 18:11:06
将 Docker 镜像逆向工程为 Dockerfile,或者称为“回溯 Docker 镜像”,是一种有用的技术,可以帮助理解和重新创建镜像的构建过程。

你是否曾经遇到过一个想要使用的 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,从而提供帮助。

责任编辑:武晓燕 来源: 云原生运维圈

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK