如何检索已在 Docker 映像中添加然后删除的文件?

Eri*_*kMD 1 docker

假设你有一个这样的工作目录:

$ tree .
.
??? Dockerfile
??? file.txt
Run Code Online (Sandbox Code Playgroud)

并且Dockerfile包含:

FROM debian:9

WORKDIR /usr/src/foo

COPY file.txt .

RUN echo Some random command involving file.txt \
  && rm -f file.txt
Run Code Online (Sandbox Code Playgroud)

然后构建相应的镜像并将其推送到给定的 Docker 注册表:

$ docker build -t foo/bar .
$ docker login #…
$ docker push foo/bar
Run Code Online (Sandbox Code Playgroud)

有没有一种方法(或几种方法)从图像中检索file.txt,添加内容然后在中间层中删除?答案是否取决于 的选择WORKDIR

lar*_*sks 5

有没有一种方法(或几种方法)可以从图像中检索在中间层中添加然后删除的 file.txt 的内容?

是的!

答案是否取决于 WORKDIR 的选择?

WORKDIR不会做的比改变当前的工作目录以外的任何其他。


当您从 Dockerfile 构建映像时,Dockerfile 中的每个指令都会创建一个新层。“映像”只是在运行容器时组合起来形成容器文件系统的层的集合。这些层中的每一个都可以在磁盘上的/var/lib/docker. 例如,假设我使用这个 Dockerfile 构建了一个镜像:

FROM debian:9
COPY file.txt /root/file.txt
RUN rm -f /root/file.txt
Run Code Online (Sandbox Code Playgroud)

在该目录中,我有一个名为的文件file.txt,其中包含以下文本:

hello world
Run Code Online (Sandbox Code Playgroud)

如果我运行docker build -t erikmd .,我会看到:

Sending build context to Docker daemon  3.072kB
Step 1/3 : FROM debian:9
 ---> d508d16c64cd
Step 2/3 : COPY file.txt /root/file.txt
 ---> Using cache
 ---> 6f06029c1cca
Step 3/3 : RUN rm -f /root/file.txt
 ---> Using cache
 ---> a2dc62c823c9
Successfully built a2dc62c823c9
Successfully tagged erikmd:latest
Run Code Online (Sandbox Code Playgroud)

在构建过程中的每一步都生成新的层,并且它是提供使用表示中间图像是所有的结果Dockerfile命令到该点的图像ID。鉴于关于输出,我可以运行:

$ docker run --rm 6f06029c1cca cat /root/file.txt
Run Code Online (Sandbox Code Playgroud)

并查看文件的内容:

hello world
Run Code Online (Sandbox Code Playgroud)

但是,如果我只是构建图像呢?在这种情况下,我将首先使用docker image inspect命令查看包含图像的图层列表:

$ docker image inspect erikmd | jq '.[0].RootFS.Layers'
[
  "sha256:13d5529fd232cacdd8cd561148560e0bf5d65dbc1149faf0c68240985607c303",
  "sha256:41494b03ef195ce6db527bd68b89cbebdace66210b4c142e95f8553fcb0bf51e",
  "sha256:1948a4bd00b6f1712667bb2c68d1fe6eb60fbbcdf8bad62653208c23bf2602a5"
]
Run Code Online (Sandbox Code Playgroud)

上面,jq只是一个查询JSON数据的工具。如果您不方便,您可以目视检查docker image inspect相同信息的输出jq

假设使用overlay2存储驱动程序的默认 Docker 配置,您将在/var/lib/docker/image/overlay2/layerdb/sha256/*/diff. 因此,例如:

# grep -l 13d5529fd232cacdd8cd561148560e0bf5d65dbc1149faf0c68240985607c303 \
  /var/lib/docker/image/overlay2/layerdb/sha256/*/diff
/var/lib/docker/image/overlay2/layerdb/sha256/13d5529fd232cacdd8cd561148560e0bf5d65dbc1149faf0c68240985607c303/diff
Run Code Online (Sandbox Code Playgroud)

第一层是debian:9图像。我们可以通过运行来确认:

$ docker image inspect debian:9 | jq '.[0].RootFS.Layers'
[
  "sha256:13d5529fd232cacdd8cd561148560e0bf5d65dbc1149faf0c68240985607c303"
]
Run Code Online (Sandbox Code Playgroud)

......所以我们会忽略它。让我们找到第二层:

# grep -l 41494b03ef195ce6db527bd68b89cbebdace66210b4c142e95f8553fcb0bf51e \
  /var/lib/docker/image/overlay2/layerdb/sha256/*/diff
/var/lib/docker/image/overlay2/layerdb/sha256/14347a192896a59fdf5c1a9ffcac2f93025433c66136d3531d7bbb3aec53efc7/diff
Run Code Online (Sandbox Code Playgroud)

在与该diff文件相同的目录中,我们会找到一个名为的文件cache-id

# cat image/overlay2/layerdb/sha256/14347a192896a59fdf5c1a9ffcac2f93025433c66136d3531d7bbb3aec53efc7/cache-id
118b1e4a401873e1db8849c0821d0280b4cf9ef621ccb70cf14fe672dc74ef75
Run Code Online (Sandbox Code Playgroud)

cache-id识别到其中的层已经被提取的目录; 我们可以在下面找到它/var/lib/docker/overlay2/<id>

# ls /var/lib/docker/overlay2/118b1e4a401873e1db8849c0821d0280b4cf9ef621ccb70cf14fe672dc74ef75
diff/ link lower work/
Run Code Online (Sandbox Code Playgroud)

我们对diff/目录的内容感兴趣:

# find /var/lib/docker/overlay2/118b1e4a401873e1db8849c0821d0280b4cf9ef6
21ccb70cf14fe672dc74ef75/diff/
/var/lib/docker/overlay2/118b1e4a401873e1db8849c0821d0280b4cf9ef621ccb70cf14fe672dc74ef75/diff/
/var/lib/docker/overlay2/118b1e4a401873e1db8849c0821d0280b4cf9ef621ccb70cf14fe672dc74ef75/diff/root
/var/lib/docker/overlay2/118b1e4a401873e1db8849c0821d0280b4cf9ef621ccb70cf14fe672dc74ef75/diff/root/file.txt
Run Code Online (Sandbox Code Playgroud)

就在那里!


注意以上所有假设您使用的是overlay2存储驱动程序(这是当今大多数平台(如果不是所有平台)的默认设置)。如果您使用不同的驱动程序,磁盘上的布局将有所不同。