docker 守护程序中的文件存储在哪里?

Where are files stored in docker daemon?

我尝试通过 ADD 命令添加一个文件,然后将其删除。但是 docker 图像的大小也表明它包含该文件!如果我将 * 放在 .dockerignore 中,它将不适用于 ADD

Docker 文件:

from ubuntu:20.04

ADD myfile /tmp

RUN rm /tmp/*

然后我通过 $ docker build -t testwf .

第一阶段显示如下:

Sending build context to Docker daemon  34.21MB

myfile 个文件的大小约为 33MB

$ docker images
REPOSITORY                       TAG       IMAGE ID       CREATED          SIZE
testwf                           latest    96543168ab34   16 minutes ago   107MB
ubuntu                           20.04     ba6acccedd29   5 weeks ago      72.8MB

实际上,我应该得到一个 72.8MBubuntu 相同大小的图像,而不是 107MB,它大致等于 72.8MB 加上 33MB!换句话说,如果我没有使用 ADD 命令的那个文件,有什么方法可以访问容器中的文件,因为它被复制到 Docker daemon?

更新

正如评论中提到的 HansKilian 文件进入其中一层,最终图像构建在该层之上。有什么方法可以去掉该层以减小最终图像的尺寸吗?

$ docker history testwf:latest                                                                  
IMAGE          CREATED         CREATED BY                                      SIZE      COMMENT
2af2733972ab   4 seconds ago   /bin/sh -c rm /tmp/*                            0B
40d13da4e0cc   4 seconds ago   /bin/sh -c #(nop) ADD file:0ddf694d27b108b4a…   34.2MB
ba6acccedd29   5 weeks ago     /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>      5 weeks ago     /bin/sh -c #(nop) ADD file:5d68d27cc15a80653…   72.8MB

您正在寻找的是 Docker 多阶段构建,您首先使用图像进行构建,并使用所有依赖项,然后构建仅包含相关工件的新图像。这样您就不必删除不需要的文件,甚至不包括它们。

https://docs.docker.com/develop/develop-images/multistage-build/

您可以multistage构建:

FROM alpine:latest  
ADD myfile /tmp

from ubuntu:20.04
COPY --from=0 /tmp/myfile ./
RUN rm /tmp/*

在Docker中有几种“合并”中间层的方法:

更多详情:

原则上,Dockerfile中的每个命令都会在最终镜像中执行命令后添加一个包含文件系统的新“层”,Docker这里的帮助是您可以保存每个层仅通过它与 前一层 的差异,所以我们不会为相同的文件浪费磁盘 space。
例如,如果我们在第 0 层之上执行 add 然后 remove 命令,则 add 命令创建仅包含添加文件的第 1 层。 remove 命令创建第 2 层,将文件标记为已删除。由于每一层仅比较其与前一层的差异,Docker 在构建期间不知道第 2 层与第 0 层相同。如果我们重复 add/delete 命令,每次添加时,我们都会创建一个与文件大小相等的额外层。因此,我们可能会构建具有相同(最终)内容但大小不同的多个图像。例如,我们可能会创建一个 32MB 的文件,然后 add/delete 将它两次复制到同一张图片,例如:

from ubuntu:latest

ADD big_file .
RUN rm big_file
ADD big_file .
RUN rm big_file

docker build . -t big_file:latest 构建它得到一个大小等于 + 32 MB * 2:

的图像
REPOSITORY                          TAG        IMAGE ID       CREATED         SIZE
big_file                            latest     ddd32b7a8519   2 minutes ago   140MB
ubuntu                              latest     ba6acccedd29   5 weeks ago     72.8MB

我们可以通过 docker history <IMAGE> 检查 big_file 内的图层并获取

IMAGE          CREATED         CREATED BY                                      SIZE      COMMENT
ddd32b7a8519   4 minutes ago   /bin/sh -c rm big_file                          0B        
c20573523c30   4 minutes ago   /bin/sh -c #(nop) ADD file:937071a2cba4a5d8b…   33.6MB    
80ae0642e3ad   4 minutes ago   /bin/sh -c rm big_file                          0B        
0538ebbf489c   4 minutes ago   /bin/sh -c #(nop) ADD file:937071a2cba4a5d8b…   33.6MB    
ba6acccedd29   5 weeks ago     /bin/sh -c #(nop)  CMD ["bash"]                 0B        
<missing>      5 weeks ago     /bin/sh -c #(nop) ADD file:5d68d27cc15a80653…   72.8MB

那么以上三种方法有什么作用呢?

  • 多阶段构建

丢掉前一阶段的所有层,只复制指定的文件到下一阶段。例如

from ubuntu:latest

ADD big_file .
RUN rm big_file
ADD big_file .
RUN rm big_file
ADD big_file .

from ubuntu:latest
COPY --from=0 big_file .

构建它给出了两个图像,一个用于 stage-0,另一个用于 stage-1。

REPOSITORY                          TAG        IMAGE ID       CREATED          SIZE
<none>                              <none>     6d844f18d92e   5 seconds ago    173MB
big_file                            latest     4b1025db1335   33 seconds ago   106MB
ubuntu                              latest     ba6acccedd29   5 weeks ago      72.8MB

检查stage-1图像,很明显stage-0图像中的层没有被复制。它只包含一个由 COPY --from=0 big_file . 命令创建的额外层。

IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
4b1025db1335   47 seconds ago   /bin/sh -c #(nop) COPY file:937071a2cba4a5d8…   33.6MB    
ba6acccedd29   5 weeks ago      /bin/sh -c #(nop)  CMD ["bash"]                 0B        
<missing>      5 weeks ago      /bin/sh -c #(nop) ADD file:5d68d27cc15a80653…   72.8MB   

它适合你从stage-0图像中清楚你需要什么的情况。一个很好的例子是您可以在 stage-0 中编译并仅将二进制文件复制到 stage-1。然而,一个常见的错误是,人们可能会忘记复制阶段 1 映像中缺少的二进制文件所需的动态库,因为这两个映像是两个不同的映像,具有各自的基础映像和层。

  • --squash

类似于git中的squash。它在每一层中加载并应用 diff 以创建一个新层,并仅在构建的图像中使用新层。

使用docker build . -t big_file:latest --squash构建给出三个图像s

REPOSITORY                          TAG        IMAGE ID       CREATED         SIZE
big_file                            latest     6903fba8cef3   2 seconds ago   72.8MB
<none>                              <none>     28ed65140111   3 seconds ago   140MB
ubuntu                              latest     ba6acccedd29   5 weeks ago     72.8MB

28ed65140111是压缩前的图像,检查big_file

中的图层
IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
6903fba8cef3   10 seconds ago                                                   0B        merge sha256:28ed65140111012d7604df5123b9be16ab4bfc62dd799259001b5d609ceb8e18 to sha256:ba6acccedd2923aee4c2acc6a23780b14ed4b8a5fa4e14e252a23b846df9b6c1
<missing>      11 seconds ago   /bin/sh -c rm big_file                          0B        
<missing>      12 seconds ago   /bin/sh -c #(nop) ADD file:937071a2cba4a5d8b…   0B        
<missing>      13 seconds ago   /bin/sh -c rm big_file                          0B        
<missing>      14 seconds ago   /bin/sh -c #(nop) ADD file:937071a2cba4a5d8b…   0B        
<missing>      5 weeks ago      /bin/sh -c #(nop)  CMD ["bash"]                 0B        
<missing>      5 weeks ago      /bin/sh -c #(nop) ADD file:5d68d27cc15a80653…   72.8MB 

加载所有差异后,与基础图像没有什么不同,所以合并层6903fba8cef3是空的。但是 squash 构建目前是一项实验性功能。

  • export/import

请注意导出适用于容器而不是图像,它只转储容器文件系统的当前状态,并且忽略 图像 中的图层信息。如果我们转储一个容器 运行 我们的 big_file 图像,然后使用 docker export <CONTAINER_ID> > big_file.tar && docker import - big_file:load < big_file.tar 重新导入它,我们得到一个“空”图像,如下所示:

IMAGE          CREATED          CREATED BY   SIZE      COMMENT
06f4d01022e7   13 seconds ago                72.8MB    Imported from -

现在我们无法知道图像是如何构建的,因为层没有被转储。

哪个更好真的取决于...,但是 Docker 中层的概念非常重要。 Docker 永远不会忘记任何东西,除非你以某种方式删除或合并图层。