我是Docker的新手,我正在努力理解Docker图像到底是什么。Docker映像的每个定义都使用术语“层”,但似乎并没有定义层的含义。

来自Docker官方文档:

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

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


当前回答

谢谢david Castillo提供的有用信息。 我认为这个层是一个图像的二进制改变或指令,可以很容易地完成或撤消。 它们是一步一步完成的,就像一层加一层一样,所以我们称之为“层”。

要了解更多信息,你可以像这样查看“docker历史”:

docker images --tree
Warning: '--tree' is deprecated, it will be removed soon. See usage.
└─511136ea3c5a Virtual Size: 0 B Tags: scratch:latest
  └─59e359cb35ef Virtual Size: 85.18 MB
    └─e8d37d9e3476 Virtual Size: 85.18 MB Tags: debian:wheezy
      └─c58b36b8f285 Virtual Size: 85.18 MB
        └─90ea6e05b074 Virtual Size: 118.6 MB
          └─5dc74cffc471 Virtual Size: 118.6 MB Tags: vim:latest

其他回答

我曾经认为它们就像前一层的差别。在阅读了这里的一些答案后,我不太确定;它们被描述为对文件系统的更改集。我写了一些dockerfile来说明它们更像差异文件,也就是说,它们确实依赖于前面的层。

给定这两个dockerfile

FROM bash
RUN mkdir /data
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/two
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/three

and

FROM bash
RUN mkdir /data
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/three
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/two
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one

如果它们只是关于文件系统的更改,人们会期望相同的层集,但事实并非如此:

$ docker history img_1
IMAGE               CREATED             CREATED BY                                      SIZE
30daa166a9c5        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
4467d16e79f5        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
c299561fd031        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
646feb178431        6 minutes ago       /bin/sh -c mkdir /data                          0B
78664daf24f4        2 weeks ago         /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>           2 weeks ago         /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B
<more missing...>

and

$ docker history img_2
IMAGE               CREATED             CREATED BY                                      SIZE
f55c91305f8c        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
29b3b627c76f        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
18360be603aa        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
646feb178431        6 minutes ago       /bin/sh -c mkdir /data                          0B
78664daf24f4        2 weeks ago         /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>           2 weeks ago         /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B
<more missing...>

您可以看到,即使在这两种情况下对文件系统的更改是相同的,顺序也很重要。

图层是包含文件和文件夹的文件夹,这些文件和文件夹是创建图像的结果。

例如:

FROM alpine:3.14            # Layer 1
RUN apk add --no-cache tree # Layer 2
COPY test.txt /tmp/         # Layer 3
ENTRYPOINT ["tree"]

这个Dockerfile将创建三个文件夹,然后将它们复制到主机系统并“合并”在一起,创建所谓的联合文件系统。这些文件夹实际上并没有在物理上合并,但是使用了Union Mount来创建它们合并的假象。

在上面的例子中,会有:

# Layer 1
/var/lib/docker/overlay2/1d06...35310/diff
bin    dev    etc    home   lib    media  mnt    opt    proc   root   run    sbin   srv    sys    tmp    usr    var

# Layer 2
/var/lib/docker/overlay2/23wgom2anm2uysvg988r3tw9c/diff
etc  lib  usr  var
           bin
             tree

# Layer 3
/var/lib/docker/overlay2/41htpkg76b3zwg29kqsb103of/diff
tmp
 test.txt

然后使用前面提到的mount命令“合并”所有这些文件夹,创建最终的Linux文件系统,然后使用chroot命令或类似命令将其设置为正在运行的进程(也就是容器)的根目录(在本例中为“树”)。

更多信息可以在这里找到:https://martinheinz.dev/blog/44

谢谢david Castillo提供的有用信息。 我认为这个层是一个图像的二进制改变或指令,可以很容易地完成或撤消。 它们是一步一步完成的,就像一层加一层一样,所以我们称之为“层”。

要了解更多信息,你可以像这样查看“docker历史”:

docker images --tree
Warning: '--tree' is deprecated, it will be removed soon. See usage.
└─511136ea3c5a Virtual Size: 0 B Tags: scratch:latest
  └─59e359cb35ef Virtual Size: 85.18 MB
    └─e8d37d9e3476 Virtual Size: 85.18 MB Tags: debian:wheezy
      └─c58b36b8f285 Virtual Size: 85.18 MB
        └─90ea6e05b074 Virtual Size: 118.6 MB
          └─5dc74cffc471 Virtual Size: 118.6 MB Tags: vim:latest

我认为官方文件给出了非常详细的解释: https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/。

(来源:docker.com)

image由很多层组成,这些层通常是从Dockerfile中生成的,Dockerfile中的每一行都将创建一个新的层,结果是一个image,用repo:tag的形式表示,如ubuntu:15.04。

欲了解更多信息,请考虑阅读上面的官方文档。

我可能会迟到,但以下是我的看法(补充ashishjain的回答):

基本上,一个层,或图像层是图像或中间图像的变化。你在Dockerfile中指定的每个命令(FROM, RUN, COPY等)都会导致之前的图像发生变化,从而创建一个新层。在使用git时,您可以将其视为阶段性更改:添加一个文件的更改,然后是另一个文件,然后是另一个文件……

考虑下面的Dockerfile:

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

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

层的概念在构建图像时派上了用场。因为图层是中间图像,如果你对Dockerfile做了更改,docker将只重建被更改的层和之后的层。这被称为层缓存。

你可以在这里阅读更多信息。