一、说明
        Docker 镜像是通过构建 Dockerfiles 创建的。构建过程执行 Dockerfile 中的指令来创建构成最终镜像的文件系统层。 如果给出已有图像,您可以检索构建它的 Dockerfile 吗?在本文中,我们将研究两种可以实现此目的的方法。

二、逆向的需求
        当您构建自己的 Docker 映像时,您应该将 Dockerfile 作为版本控制文件存储在源存储库中。这种做法可确保您始终可以检索用于组装镜像的说明。

        如果您使用公共Registoy中的镜像,您将无法访问它的Dockerfile。或者您可能正在使用不直接提供 Dockerfile 的镜像快照。在这些情况下,您需要一种可以从计算机上的镜像提取 Dockerfile 的技术。

        Docker 不提供任何内置功能来实现这一点。您可以自己设法进行逆向工程,以按需生成图像 Dockerfile 的近似版本。

三、使用Docker的history命令

        docker history 命令显示镜像的层历史。它显示了用于构建每个连续文件系统层的命令,使其成为复制 Dockerfile 时的一个很好的起点。

历史包括图像中层的完整列表,包括从 node:16 基本镜像继承的层。层是有序的,所以最近的层在第一层。您可以根据创建时间确定示例 Dockerfile 创建的层的起始位置。这些显示了 Dockerfile 中使用的 COPY 和 CMD 指令的内部表示。

        当表格仅限于显示每一层的命令时,docker history 输出更有用。您也可以禁用截断以查看与每一层关联的完整命令:

[root@localhost jettopro-usbmuxd]# docker history   harbor.jettech.com/jettoui/jettopro-usbmuxd:v1.0 --format "{{.CreatedBy}}" --no-trunc  
/bin/sh -c #(nop)  ENTRYPOINT ["/bin/sh" "-c" "usbmuxd -v -f"]
/bin/sh -c #(nop)  VOLUME [/var/run]
/bin/sh -c #(nop)  VOLUME [/dev]
/bin/sh -c #(nop) WORKDIR /opt
/bin/sh -c #(nop)  MAINTAINER wu_bo3@hoperun.com

/bin/sh -c #(nop)  CMD ["/bin/bash"]
/bin/sh -c #(nop) ADD file:cdbc7eeb8f0a474970be6c866f99789fb8be4d72874e68cf75461403c8c2651e in / 
/bin/sh -c #(nop)  ENV DISTTAG=f39container FGC=f39 FBR=f39
/bin/sh -c #(nop)  LABEL maintainer=Clement Verna <cverna@fedoraproject.org>

四、使用 Whaler自动提取图层
        从 docker 历史记录中复制命令是一个费力的过程。基本是手工处理。幸运的是,有可用的社区工具可以根据镜像的层历史自动创建 Dockerfile。另一个选择是,由 Alpine 组织打包到 alpine/dfimage (Dockerfile-from-Image) Docker 镜像中的 Whaler工具。

4.1 什么是Whaler
        Whaler 是一个 Go 程序,旨在将 docker 镜像逆向工程到创建它的 Dockerfile 中。它当前执行以下操作

从图像生成 Dockerfile

搜索添加的文件名以查找潜在的秘密文件

提取由 Docker ADD/COPY 指令添加的文件

它还显示杂项。信息,如端口打开、它运行的用户和环境变量。

4.2 Whaler使用方法示例

# 安装whaler到/usr/local/bin/目录下
wget -cO /usr/local/bin/whaler https://github.com/P3GLEG/Whaler/releases/download/1.0/Whaler_linux_amd64# 赋予可执行权限
chmod +x /usr/local/bin/whaler

# 将docker客户端ID设置为特定版本-sV
whaler -sV=1.36 # 打印有关图像的所有详细信息 -v 
whaler -v 镜像名# 将镜像曾保存到当前目录-x

4.3 容器板的Whaler使用方法示例 

尝试使用whaler,首先拉取whaler的镜像。

    docker pull pegleg/whaler
[root@localhost jettopro-usbmuxd]# docker run -t --rm -v /var/run/docker.sock:/var/run/docker.sock:ro pegleg/whaler -sV=1.36 harbor.jettech.com/jettoui/jettopro-usbmuxd:v1.0


CMD ["/bin/bash"]


MAINTAINER wu_bo3@hoperun.com
WORKDIR /opt
VOLUME [/dev]
VOLUME [/var/run]
ENTRYPOINT ["/bin/sh" "-c" "usbmuxd -v -f"]

五、使用 Dfimage 自动提取图层

        运行 dfimage 镜像并提供 Docker 标签将输出一个 Dockerfile,可用于复制引用的图像。您必须将主机的 Docker 套接字绑定到 dfimage 容器中,以便它可以访问您的图像列表并在需要时拉取标签。

docker run --rm 
    -v /var/run/docker.sock:/var/run/docker.sock 
    alpine/dfimage node-app:latest

六、逆向工程的局限性
        在许多情况下,dfimage 将能够组装一个可用的 Dockerfile。尽管如此,它并不完美,也不能保证完全匹配。与镜像的原始 Dockerfile 相比的差异程度将根据所使用的指令而有所不同。

        并非所有指令都在层历史记录中捕获。不受支持的将丢失,您无法确定它们是什么。使用 RUN、ENV、WORKDIR、ENTRYPOINT 和 CMD 等命令和元数据指令可获得最佳准确性。如果他们的命令没有导致文件系统更改,则 RUN 指令仍然可能会丢失,这意味着没有创建新的镜像层。

        当您到达最终目的地时,这足以帮助您了解复制的内容以及原因。然后,您可以使用此信息将新的源路径插入到 Dockerfile 中,您可以将其用于未来的构建。在其他情况下,检查图像中的文件可能有助于揭示副本的用途,以便您可以为主机路径确定一个有意义的文件名。

七、总结
        Docker 不提供直接从image反推出Dockerfile 的方法。不过,仍然可以将构建过程拼凑起来。对于指令很少的简单图像,您通常可以通过查看 docker history 命令输出中的 CREATED BY 列来手动恢复成指令。

        具有更复杂构建过程的更大图像最好使用 dfimage 等工具进行分析。这会为您解析复杂的 dockerfile代码,生成一个新的 Dockerfile,且与可能的原始 Dockerfile 尽量匹配。

        逆向工程工作并不完美,一些 Dockerfile 指令在构建过程中丢失或损坏。因此,您不可假定以这种方式创建的 Dockerfile 是原始文件的准确恢复。您可能还必须对 ADD 和 COPY 指令进行一些手动调整,恢复已转换为上下文引用的宿主机文件路径。

更多推荐