当前位置: 首页 > 知识库问答 >
问题:

Docker图像“层”是什么?

钱展
2023-03-14

我是Docker的新手,正在尝试准确理解Docker映像是什么。Docker映像的每个定义都使用术语“层”,但似乎没有定义层的含义。

从Docker官方文件:

我们已经看到Docker图像是只读模板,从中启动Docker容器。每个图像由一系列层组成。Docker利用union文件系统将这些层合并到单个图像中。Union文件系统允许透明地覆盖单独文件系统(称为分支)的文件和目录,形成单个连贯的文件系统。

所以我问,什么是层(确切地说);有人能举几个具体的例子吗?这些层是如何“咬合在一起”形成图像的?

共有3个答案

许彭祖
2023-03-14

他们用一个例子对我来说最有意义...

让我们以Dockerfile为例:

FROM busybox

RUN mkdir /data
# imagine this is downloading source code
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one 
RUN chmod -R 0777 /data
# imagine this is compiling the app
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/two 
RUN chmod -R 0777 /data
# and now this cleans up that downloaded source code
RUN rm /data/one 

CMD ls -alh /data

每个dd命令都会将一个1M文件输出到磁盘。让我们用一个额外的标志来构建图像,以保存临时容器

docker image build --rm=false .

在输出中,您将看到每个正在运行的命令都发生在我们现在保留的临时容器中,而不是自动删除:

...
Step 2/7 : RUN mkdir /data
 ---> Running in 04c5fa1360b0
 ---> 9b4368667b8c
Step 3/7 : RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one
 ---> Running in f1b72db3bfaa
1024+0 records in
1024+0 records out
1048576 bytes (1.0MB) copied, 0.006002 seconds, 166.6MB/s
 ---> ea2506fc6e11

如果在每个容器id上运行docker diff,您将看到在这些容器中创建了哪些文件:

$ docker diff 04c5fa1360b0  # mkdir /data
A /data
$ docker diff f1b72db3bfaa  # dd if=/dev/zero bs=1024 count=1024 of=/data/one
C /data
A /data/one
$ docker diff 81c607555a7d  # chmod -R 0777 /data
C /data
C /data/one
$ docker diff 1bd249e1a47b  # dd if=/dev/zero bs=1024 count=1024 of=/data/two
C /data
A /data/two
$ docker diff 038bd2bc5aea  # chmod -R 0777 /data
C /data/one
C /data/two
$ docker diff 504c6e9b6637  # rm /data/one
C /data
D /data/one

A为前缀的每一行都在添加文件,C表示对现有文件的更改,D表示删除。

上述每个容器文件系统差异都进入一个“层”,当您将映像作为容器运行时,该层将被组装。当有添加或更改时,整个文件都在每一层中,因此这些chmod命令中的每一个都会导致整个文件被复制到下一层,尽管只是更改了一个权限位。删除的/数据/一个文件仍在前几层中,事实上有3次,当你拉取图像时,它将通过网络复制并存储在磁盘上。

您可以使用docker历史记录命令查看创建现有映像图层的命令。您还可以在图像上运行docker镜像检查并查看RootFS部分下的图层列表。

以下是上图的历史记录:

IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
a81cfb93008c        4 seconds ago       /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "ls -…   0B
f36265598aef        5 seconds ago       /bin/sh -c rm /data/one                         0B
c79aff033b1c        7 seconds ago       /bin/sh -c chmod -R 0777 /data                  2.1MB
b821dfe9ea38        10 seconds ago      /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
a5602b8e8c69        13 seconds ago      /bin/sh -c chmod -R 0777 /data                  1.05MB
08ec3c707b11        15 seconds ago      /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
ed27832cb6c7        18 seconds ago      /bin/sh -c mkdir /data                          0B
22c2dd5ee85d        2 weeks ago         /bin/sh -c #(nop)  CMD ["sh"]                   0B
<missing>           2 weeks ago         /bin/sh -c #(nop) ADD file:2a4c44bdcb743a52f…   1.16MB

最新的图层列在顶部。值得注意的是,底部有两层相当古老。它们来自busybox图像本身。当您构建一个图像时,您将继承您在“来自”行中指定的图像的所有层。还添加了一些层来更改图像元数据,如CMD行。它们几乎不占用任何空间,更多的是用于记录应用于正在运行的图像的设置。

这些层有几个优点。首先,它们是不变的。一旦创建,由sha256哈希标识的层将永远不会更改。这种不变性使图像能够安全地构建并相互分叉。如果两个DockerFile具有相同的初始行集,并且构建在同一台服务器上,那么它们将共享相同的初始层集,从而节省磁盘空间。这也意味着,如果重建图像,Dockerfile的最后几行发生更改,则只需要重建这些层,其余层可以从层缓存中重用。这可以快速重建docker图像。

在容器中,您可以看到映像文件系统,但该文件系统没有被复制。在这些映像层的顶部,容器挂载它自己的读写文件系统层。文件的每一次读取都经过这些层,直到它到达一个已将文件标记为删除的层,该层中有一个文件副本,或者读取用完了要搜索的层。每次写入都会在容器特定的读写层中进行修改。

这些层的一个缺点是生成复制文件的图像,或者发送在以后的层中删除的文件。解决方案通常是将多个命令合并为单个运行命令。尤其是在修改现有文件或删除文件时,您希望这些步骤在最初创建它们的同一命令中运行。上述Dockerfile的重写如下所示:

FROM busybox

RUN mkdir /data \
 && dd if=/dev/zero bs=1024 count=1024 of=/data/one \
 && chmod -R 0777 /data \
 && dd if=/dev/zero bs=1024 count=1024 of=/data/two \
 && chmod -R 0777 /data \
 && rm /data/one

CMD ls -alh /data

如果比较结果图像:

  • busybox:~1MB
  • 第一张图片:~6MB
  • 第二张图片:~2MB

只需将人为示例中的一些行合并在一起,我们就可以在图像中获得相同的结果内容,并将图像从5MB压缩到您在最终图像中看到的1MB文件。

戴浩初
2023-03-14

docker容器映像是使用dockerfile创建的。dockerfile中的每一行都将创建一个层。考虑以下虚拟示例:

FROM ubuntu             #This has its own number of layers say "X"
MAINTAINER FOO          #This is one layer 
RUN mkdir /tmp/foo      #This is one layer 
RUN apt-get install vim #This is one layer 

这将创建一个最终的图像,其中总层数为X 3

昝浩阔
2023-03-14

我可能会迟到,但这是我的10美分(补充ashishjain的回答):

基本上,层或图像层是对图像或中间图像的更改。您在Dockerfile中指定的每个命令(来自运行复制等)都会导致上一个图像发生更改,从而创建一个新层。当你使用git的时候,你可以把它看作是一个暂存更改:你添加一个文件的更改,然后再添加一个,然后再添加一个。。。

考虑以下Dockerfile:

FROM rails:onbuild
ENV RAILS_ENV production
ENTRYPOINT ["bundle", "exec", "puma"]

首先,我们选择一个起始图像:rails:onbuild,它又有许多层。我们在开始图像的顶部添加了另一层,使用命令设置环境变量RAILS\u ENV。然后,我们告诉docker运行bundle exec puma(启动rails服务器)。这是另一层。

在构建图像时,层的概念非常有用。由于层是中间图像,如果您对Dockerfile进行更改,docker将仅重建更改后的层和更改后的层。这称为层缓存。

你可以在这里读到更多。

 类似资料:
  • 我对Docker是全新的,我正在努力理解Docker形象到底是什么。Docker图像的每个定义都使用术语“层”,但似乎没有定义层的含义。

  • 我需要了解docker图像注册表的脱机使用情况 当docker图像从microsoft官方网站中提取、调整,然后推送到注册表时,它是完整的图像还是缺少图层 当其他主机从注册表中提取图像(可能脱机使用)时,客户端主机是否仍需要internet连接才能从microsoft服务器中提取缺失/机密层?(或者是从microsoft提取的完整图像,然后推送到注册表?) 签名呢?当图像被调整、存储在其中的应用程

  • 我正在尝试编写一个程序,以确保容器的父(或祖父母或曾祖父母等)是已批准的容器列表中的容器。(以确保我的公司仅使用经批准的容器。) 当我在我的图像上运行命令时,我得到一些json响应。json的一部分如下所示: 我以为这些就是我容器图像的层次。但该列表不包含容器映像的父级。所谓父级,我指的是在子句中用于创建我检查过的图像的容器图像。)(我使用命令进行了检查。) 这些价值观是什么? 更重要的是,有没有

  • 在这种情况下,这些rest层ID是否与其他一些图像相对应呢?如果是真的,我可以视图层为图像吗?

  • 让我们以whalesay图片为例<代码>docker history显示以下内容: 我想提取显示为的层。有这样做的工具/方法吗?

  • 这个问题的根源是从docker私有注册表中提取的速度非常慢。 然后我发现通过注册表远程API的速度是可以的。 现在我得到一个图像的层。如何将其作为映像加载到docker守护程序? ps: 我试着加载docker 结果如下。 FATA[0015]错误:打开 /home/docker/data/docker/tmp/docker-import-087506163/repo/etc/json:没有这样的