From 9d74485ed606d8c8146e1bd017f44c13b0024c8a Mon Sep 17 00:00:00 2001 From: Xingyu Wang Date: Thu, 1 Apr 2021 21:55:55 +0800 Subject: [PATCH] PRF @DCOLIVERSUN --- ...0318 Reverse Engineering a Docker Image.md | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/translated/tech/20210318 Reverse Engineering a Docker Image.md b/translated/tech/20210318 Reverse Engineering a Docker Image.md index 9ffb64ac2b..4fb8e78d40 100644 --- a/translated/tech/20210318 Reverse Engineering a Docker Image.md +++ b/translated/tech/20210318 Reverse Engineering a Docker Image.md @@ -3,16 +3,18 @@ [#]: author: (Simon Arneaud https://theartofmachinery.com) [#]: collector: (lujun9972) [#]: translator: (DCOLIVERSUN) -[#]: reviewer: ( ) +[#]: reviewer: (wxy) [#]: publisher: ( ) [#]: url: ( ) -Docker 镜像逆向工程 +一次 Docker 镜像的逆向工程 ====== -本文介绍的内容开始于一个咨询陷阱:政府组织 A 让政府组织 B 开发一个网络应用程序。政府机构 B 把部分工作外包给某个人。后来,项目的托管和维护被外包给一家私人公司 C。C 公司发现,之前外包的人(过世很久了)已经构建了一个自定义的 Docker 镜像,并使镜像成为系统构建的依赖项,但这个人没有提交原始的 Dockerfile。C 公司有合同义务管理这个 Docker 镜像,可是他们他们没有源代码。C 公司偶尔叫我进去做各种工作,所以处理一些关于这个神秘 Docker 镜像的事情就成了我的工作。 +![](https://img.linux.net.cn/data/attachment/album/202104/01/215523oajrgjo77irb7nun.jpg) -幸运的是,这个 Docker 镜像格式比它应有的样子透明多了。虽然还需要做一些侦查工作,但只要解剖一个镜像文件,就能发现很多东西。例如,这里有一个 [Prettier 代码格式][1]镜像可供快速浏览。 +这要从一次咨询的失误说起:政府组织 A 让政府组织 B 开发一个 Web 应用程序。政府机构 B 把部分工作外包给某个人。后来,项目的托管和维护被外包给一家私人公司 C。C 公司发现,之前外包的人(已经离开很久了)构建了一个自定义的 Docker 镜像,并将其成为系统构建的依赖项,但这个人没有提交原始的 Dockerfile。C 公司有合同义务管理这个 Docker 镜像,可是他们他们没有源代码。C 公司偶尔叫我进去做各种工作,所以处理一些关于这个神秘 Docker 镜像的事情就成了我的工作。 + +幸运的是,Docker 镜像的格式比想象的透明多了。虽然还需要做一些侦查工作,但只要解剖一个镜像文件,就能发现很多东西。例如,这里有一个 [Prettier 代码格式化][1] 的镜像可供快速浏览。 首先,让 Docker 守护进程daemon拉取镜像,然后将镜像提取到文件中: @@ -42,7 +44,7 @@ manifest.json repositories ``` -如你所见,Docker 在命名时经常使用哈希hash。我们看看 `manifest.json`。它在难以阅读的压缩 JSON 中,不过 [`jq` JSON Swiss Army knife][2]可以很好地打印 JSON: +如你所见,Docker 在命名时经常使用哈希hash。我们看看 `manifest.json`。它是以难以阅读的压缩 JSON 写的,不过 [JSON 瑞士军刀 jq][2] 可以很好地打印 JSON: ``` $ jq . manifest.json @@ -61,7 +63,7 @@ $ jq . manifest.json ] ``` -请注意,这三层对应三个 hash 命名的目录。我们以后再看。现在,让我们看看 `Config` 键指向的 JSON 文件。文件名有点长,所有我把第一点放在这里: +请注意,这三个Layer对应三个以哈希命名的目录。我们以后再看。现在,让我们看看 `Config` 键指向的 JSON 文件。它有点长,所以我只在这里转储第一部分: ``` $ jq . 88f38be28f05f38dba94ce0c1328ebe2b963b65848ab96594f8172a9c3b0f25b.json | head -n 20 @@ -87,9 +89,9 @@ $ jq . 88f38be28f05f38dba94ce0c1328ebe2b963b65848ab96594f8172a9c3b0f25b.json | h "Image": "sha256:93e72874b338c1e0734025e1d8ebe259d4f16265dc2840f88c4c754e1c01ba0a", ``` -最重要的是 `history` 列表,它列出了镜像中的每一层。Docker 镜像由这些层堆叠而成。Dockerfile 中几乎每条命令都会变成一个层,描述该命令对镜像所做的更改。如果你执行 `RUN script.sh` 命令,创建 `really_big_file`,然后你用 `RUN rm really_big_file` 命令删除文件,Docker 镜像实际生成两层:一个包含 `really_big_file`,一个包含 `.wh.really_big_file` 记录来删除它。整个镜像文件大小不变。这就是为什么你会经常看到像 `RUN script.sh && rm really_big_file` 这样的 Dockerfile 命令链接在一起——它保障所有更改都合并到一层中。 +最重要的是 `history` 列表,它列出了镜像中的每一层。Docker 镜像由这些层堆叠而成。Dockerfile 中几乎每条命令都会变成一个层,描述该命令对镜像所做的更改。如果你执行 `RUN script.sh` 命令创建了 `really_big_file`,然后用 `RUN rm really_big_file` 命令删除文件,Docker 镜像实际生成两层:一个包含 `really_big_file`,一个包含 `.wh.really_big_file` 记录来删除它。整个镜像文件大小不变。这就是为什么你会经常看到像 `RUN script.sh && rm really_big_file` 这样的 Dockerfile 命令链接在一起——它保障所有更改都合并到一层中。 -以下是 Docker 镜像中记录的所有层。注意,大多数层不改变文件系统镜像,并且 `empty_layer` 标记为 true。以下只有三个层是非空的,与我们之前描述的相符。 +以下是该 Docker 镜像中记录的所有层。注意,大多数层不改变文件系统镜像,并且 `empty_layer` 标记为 `true`。以下只有三个层是非空的,与我们之前描述的相符。 ``` $ jq .history 88f38be28f05f38dba94ce0c1328ebe2b963b65848ab96594f8172a9c3b0f25b.json @@ -162,7 +164,7 @@ m=${NODEJS_VERSION} && npm install -g prettier@${PRETTIER_VERSION} && np ] ``` -太棒了!所有的命令都在 `created_by` 字段中,我们几乎可以用这些命令重建 Dockerfile。但不是完全可以。最上面的 `ADD` 命令实际上没有给我们需要添加的文件。`COPY` 命令也没有全部信息。因为 `FROM` 命令会扩展到继承基础 Docker 镜像的所有层,所以可能会跟丢该命令。 +太棒了!所有的命令都在 `created_by` 字段中,我们几乎可以用这些命令重建 Dockerfile。但不是完全可以。最上面的 `ADD` 命令实际上没有给我们需要添加的文件。`COPY` 命令也没有全部信息。我们还失去了 `FROM` 语句,因为它们扩展成了从基础 Docker 镜像继承的所有层。 我们可以通过查看时间戳timestamp,按 Dockerfile 对层进行分组。大多数层的时间戳相差不到一分钟,代表每一层构建所需的时间。但是前两层是 `2020-04-24`,其余的是 `2020-04-29`。这是因为前两层来自一个基础 Docker 镜像。理想情况下,我们可以找出一个 `FROM` 命令来获得这个镜像,这样我们就有了一个可维护的 Dockerfile。 @@ -215,7 +217,7 @@ $ cat etc/alpine-release 3.11.6 ``` -如果你拉取、解压 `alpine:3.11.6`,你会发现里面有一个非空层,`layer.tar`与 Prettier 镜像基础层中的 `layer.tar` 是一样的。 +如果你拉取、解压 `alpine:3.11.6`,你会发现里面有一个非空层,`layer.tar` 与 Prettier 镜像基础层中的 `layer.tar` 是一样的。 出于兴趣,另外两个非空层是什么?第二层是包含 Prettier 安装包的主层。它有 528 个条目,包含 Prettier、一堆依赖项和证书更新: @@ -264,7 +266,7 @@ $ tar tf 6c37da2ee7de579a0bf5495df32ba3e7807b0a42e2a02779206d165f55f1ba70/layer. work/ ``` -[原始 Dockerfile 在 Prettier 的 git repo 中][4] +[原始 Dockerfile 在 Prettier 的 git 仓库中][4]。 -------------------------------------------------------------------------------- @@ -273,7 +275,7 @@ via: https://theartofmachinery.com/2021/03/18/reverse_engineering_a_docker_image 作者:[Simon Arneaud][a] 选题:[lujun9972][b] 译者:[DCOLIVERSUN](https://github.com/DCOLIVERSUN) -校对:[校对者ID](https://github.com/校对者ID) +校对:[wxy](https://github.com/wxy) 本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出