【docker知识】如何从镜像返回它的Dockerfile文件

这篇具有很好参考价值的文章主要介绍了【docker知识】如何从镜像返回它的Dockerfile文件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、说明

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

二、逆向的需求

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

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

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

三、使用Docker的history命令

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

        这是一个用于 Node.js 应用程序的简单 Dockerfile:

FROM node:16
COPY app.js .
RUN app.js --init
CMD ["app.js"]

编译镜像:docker build:

$ docker build -t node-app:latest .

现在使用 docker history 检查图像的层历史:

$ docker history node-app:latest
IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
c06fc21a8eed   8 seconds ago    /bin/sh -c #(nop)  CMD ["app.js"]               0B        
74d58e07103b   8 seconds ago    /bin/sh -c ./app.js --init                      0B        
22ea63ef9389   19 seconds ago   /bin/sh -c #(nop) COPY file:0c0828d0765af4dd...   50B       
424bc28f998d   4 days ago       /bin/sh -c #(nop)  CMD ["node"]                 0B        
<missing>      4 days ago       /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry...   0B        
...

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

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

$ docker history node-app:latest --format "{{.CreatedBy}}" --no-trunc
/bin/sh -c #(nop)  CMD ["app.js"]
/bin/sh -c ./app.js --init
/bin/sh -c #(nop) COPY file:0c0828d0765af4dd87b893f355e5dff77d6932d452f5681dfb98fd9cf05e8eb1 in . 
/bin/sh -c #(nop)  CMD ["node"]
/bin/sh -c #(nop)  ENTRYPOINT ["docker-entrypoint.sh"]
...

      从此命令列表中,您可以大致了解组装镜像的步骤。对于像这样的简单镜像,这些信息完全可以准确地重现 Dockerfile。

四、使用 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使用方法示例

1)安装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

2)常用参数

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

3)将镜像逆向为dockfile

# 逆向镜像
whaler 镜像名# 示例
[master root ~]# whaler -sV=1.36 nginx
Analyzing nginx
Docker Version: 20.10.7
GraphDriver: overlay2
Environment Variables
|PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|NGINX_VERSION=1.21.5
|NJS_VERSION=0.7.1
|PKG_RELEASE=1~bullseyeOpen Ports
|80Image user
|User is rootPotential secrets:
Dockerfile:
CMD ["bash"]
LABEL maintainer=NGINX Docker Maintainers <docker-maint@nginx.com>
ENV NGINX_VERSION=1.21.5
ENV NJS_VERSION=0.7.1
ENV PKG_RELEASE=1~bullseye
RUN set -x  \&& addgroup --system --gid 101 nginx  \&& adduser --system --disabled-login --ingroup nginx --no-create-home --home /nonexistent --gecos "nginx user" --shell /bin/false --uid 101 nginx  \&& apt-get update  \&& apt-get install --no-install-recommends --no-install-suggests -y gnupg1 ca-certificates  \&& NGINX_GPGKEY=573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62; found=''; for server in hkp://keyserver.ubuntu.com:80 pgp.mit.edu ; do echo "Fetching GPG key $NGINX_GPGKEY from $server"; apt-key adv --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$NGINX_GPGKEY"  \&& found=yes  \&& break; done; test -z "$found"  \&& echo >&2 "error: failed to fetch GPG key $NGINX_GPGKEY"  \&& exit 1; apt-get remove --purge --auto-remove -y gnupg1  \&& rm -rf /var/lib/apt/lists/*  \&& dpkgArch="$(dpkg --print-architecture)"  \&& nginxPackages=" nginx=${NGINX_VERSION}-${PKG_RELEASE} nginx-module-xslt=${NGINX_VERSION}-${PKG_RELEASE} nginx-module-geoip=${NGINX_VERSION}-${PKG_RELEASE} nginx-module-image-filter=${NGINX_VERSION}-${PKG_RELEASE} nginx-module-njs=${NGINX_VERSION}+${NJS_VERSION}-${PKG_RELEASE} "  \&& case "$dpkgArch" in amd64|arm64) echo "deb https://nginx.org/packages/mainline/debian/ bullseye nginx" >> /etc/apt/sources.list.d/nginx.list  \&& apt-get update ;; *) echo "deb-src https://nginx.org/packages/mainline/debian/ bullseye nginx" >> /etc/apt/sources.list.d/nginx.list  \&& tempDir="$(mktemp -d)"  \&& chmod 777 "$tempDir"  \&& savedAptMark="$(apt-mark showmanual)"  \&& apt-get update  \&& apt-get build-dep -y $nginxPackages  \&& ( cd "$tempDir"  \&& DEB_BUILD_OPTIONS="nocheck parallel=$(nproc)" apt-get source --compile $nginxPackages )  \&& apt-mark showmanual | xargs apt-mark auto > /dev/null  \&& { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; }  \&& ls -lAFh "$tempDir"  \&& ( cd "$tempDir"  \&& dpkg-scanpackages . > Packages )  \&& grep '^Package: ' "$tempDir/Packages"  \&& echo "deb [ trusted=yes ] file://$tempDir ./" > /etc/apt/sources.list.d/temp.list  \&& apt-get -o Acquire::GzipIndexes=false update ;; esac  \&& apt-get install --no-install-recommends --no-install-suggests -y $nginxPackages gettext-base curl  \&& apt-get remove --purge --auto-remove -y  \&& rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx.list  \&& if [ -n "$tempDir" ]; then apt-get purge -y --auto-remove  \&& rm -rf "$tempDir" /etc/apt/sources.list.d/temp.list; fi  \&& ln -sf /dev/stdout /var/log/nginx/access.log  \&& ln -sf /dev/stderr /var/log/nginx/error.log  \&& mkdir /docker-entrypoint.d
COPY file:65504f71f5855ca017fb64d502ce873a31b2e0decd75297a8fb0a287f97acf92 in /docker-entrypoint.shCOPY file:0b866ff3fc1ef5b03c4e6c8c513ae014f691fb05d530257dfffd07035c1b75da in /docker-entrypoint.ddocker-entrypoint.d/docker-entrypoint.d/10-listen-on-ipv6-by-default.shCOPY file:0fd5fca330dcd6a7de297435e32af634f29f7132ed0550d342cad9fd20158258 in /docker-entrypoint.ddocker-entrypoint.d/docker-entrypoint.d/20-envsubst-on-templates.shCOPY file:09a214a3e07c919af2fb2d7c749ccbc446b8c10eb217366e5a65640ee9edcc25 in /docker-entrypoint.ddocker-entrypoint.d/docker-entrypoint.d/30-tune-worker-processes.shENTRYPOINT ["/docker-entrypoint.sh"]
EXPOSE 80
STOPSIGNAL SIGQUIT
CMD ["nginx" "-g" "daemon off;"]

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

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

    docker pull pegleg/whaler

启动whaler容器,分析nginx:latest镜像

docker run -t --rm -v /var/run/docker.sock:/var/run/docker.sock:ro pegleg/whaler -sV=1.36 nginx:latest
docker build --rm -t pegleg/whaler .
alias whaler="docker run -t --rm -v /var/run/docker.sock:/var/run/docker.sock:ro pegleg/whaler"
whaler -sV=1.36 nginx:latest

这个工具会自动拉取目标 docker 镜像。参数 -sV=1.36 并不总是必需的。

        

五、使用 Dfimage 自动提取图层

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

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

Analyzing node-app:latest
Docker Version: 20.10.13
GraphDriver: overlay2
Environment Variables
|PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|NODE_VERSION=16.14.2
|YARN_VERSION=1.22.18

Image user
|User is root

Dockerfile:
...
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["node"]
COPY file:bcbc3d5784a8f1017653685866d30e230cae61d0da13dae32525b784383ac75f in .
    app.js

RUN ./app.js --init
CMD ["app.js"]

        创建的 Dockerfile 包含从头开始(空文件系统)到指定镜像的最后一层所需的一切。它包括来自基础镜像的所有层。您可以在上面示例输出的第一个 ENTRYPOINT 和 CMD 指令中看到这些(为简洁起见,其他基础镜像层已被省略)。

        除了 COPY 之外,我们镜像的特定指令与原始 Dockerfile 中的内容相匹配。您现在可以将这些指令复制到一个新的 Dockerfile 中,使用整个 dfimage 输出或只获取与最终镜像相关的部分。后一种选择只有在您知道原始基础图像的轮廓时才有可能,因此您可以在文件顶部添加 FROM 指令。

六、逆向工程的局限性

        在许多情况下,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 指令进行一些手动调整,恢复已转换为上下文引用的宿主机文件路径。文章来源地址https://www.toymoban.com/news/detail-765568.html

到了这里,关于【docker知识】如何从镜像返回它的Dockerfile文件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Docker】如何编写Dockerfile,深入理解 Dockerfile:构建精简且高效的容器镜像

    Docker 是一种轻量级的容器化技术,使得应用程序和它们的依赖可以被打包到一个容器中,方便在不同环境中运行。Dockerfile 是用于定义 Docker 镜像的文本文件,其中包含了一系列的指令,这些指令描述了镜像中应该包含哪些内容和如何配置。 在开始编写 Dockerfile 之前,确保你

    2024年01月24日
    浏览(40)
  • 如何在 Linux 命令行下玩转 Docker——如何使用 Dockerfile 来构建和运行容器镜像

    作者:禅与计算机程序设计艺术 Docker 是一款开源的容器化技术,它利用 Linux 内核的容器特性,将应用部署到独立的进程环境中。基于容器技术可以极大地提高开发者和运维人员的效率,降低部署、测试和生产环节中的成本,有效地实现云计算资源的弹性伸缩。 本文主要介绍

    2024年02月07日
    浏览(41)
  • 在Docker中使用Dockerfile实现ISO文件转化为完整版Centos镜像,并搭建集群数据仓库

    在上一篇文章中,我们提到了如何使用Docker官方版本的centos7搭建容器集群并实现同一ip下使用不同端口的ssh远程登录,但是其中遇到了非常多的问题,例如: 官方的centos7过于“简陋”,导致我们运行脚本时因为没有预装依赖包而报错! 这个可太致命了,所以这篇文章教大家

    2024年02月12日
    浏览(34)
  • 【Docker】5、Dockerfile 自定义镜像(镜像结构、Dockerfile 语法、把 Java 项目弄成镜像)

    镜像结构 Dockerfile 语法 构建 Java 项目 ① 之前使用的镜像都是 DockerHub 官方提供的 ② 开发者需要将自己的微服务制作为镜像 镜像 是由 应用程序 及其需要的 系统函数库 、 环境 、 配置 、 依赖 打包而成。 📝 镜像是 分层结构 ,每一层称为一个 Layer 1️⃣ BaseImage 层:包含基

    2024年02月03日
    浏览(33)
  • Docker定制镜像(Dockerfile)

             dockerfile 是用来构建 docker 镜像的 命令参数脚本 文件。         镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、

    2024年02月07日
    浏览(40)
  • 【docker】dockerfile构建镜像

    Dockerfile 是一个文本文件,文件中包含了一条条的指令(instruction),用于构建镜像。每一条指定构建一层镜像,因此每一条指令的内容,就是描述该层镜像应当如何构建。 1、dockerfile是 自定义镜像 的一套规则 2、dockerfile由多条指令构成,dockerfile的每一条指令都会对应于do

    2024年02月05日
    浏览(44)
  • 【Docker】Dockerfile构建最小镜像

    接下来看看由辉辉所写的关于Docker的相关操作吧 目录 🥳🥳Welcome 的Huihui\\\'s Code World ! !🥳🥳 前言 一.Dockerfile是什么 二.Dockerfile的基本结构 三.基础镜像的选择 四. 自定义镜像 0.jar包的准备 1.jar同级目录下创建Dockerfile文件 2.创建镜像 3.运行镜像 (1)上传jre (2)编辑Dockerdil

    2024年01月17日
    浏览(44)
  • docker (八)-dockerfile制作镜像

    dockerfile通常包含以下几个常用命令: FROM   打包使用的基础镜像 WORKDIR   相当于cd命令,进入工作目录 COPY   将宿主机的文件复制到容器内 RUN   打包时执行的命令,相当于打包过程中在容器中执行shell脚本,通常用来安装应用程序所需要的依赖、设置权限、初始化配置文件

    2024年02月21日
    浏览(37)
  • 【docker】Dockerfile自定义镜像

            📝个人主页: 五敷有你         🔥系列专栏: 中间件 ⛺️稳中求进,晒太阳 常见的镜像在DockerHub就能找到,但是我们自己写的项目就必须自己构建镜像了。 而要自定义镜像,就必须先了解镜像的结构才行。 镜像是将应用程序及其需要的系统函数库、环境、配

    2024年04月15日
    浏览(44)
  • Docker | 使用Dockerfile制作镜像

    ✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏:Docker系列 ✨特色专栏: MySQL学习 🥭本文内容: Docker | 使用Dockerfile制作镜像 📚个人知识库: [Leo知识库]https://gaoziman.gitee.io/blogs/),欢迎大家访

    2024年02月04日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包