我是Docker的新手,我正在努力理解Docker图像到底是什么。Docker映像的每个定义都使用术语“层”,但似乎并没有定义层的含义。
来自Docker官方文档:
我们已经看到Docker镜像是启动Docker容器的只读模板。每张图像都由一系列图层组成。Docker利用联合文件系统将这些层组合成单个映像。联合文件系统允许透明地覆盖独立文件系统(称为分支)的文件和目录,从而形成一个统一的文件系统。
所以我问,什么是层;有人能举几个具体的例子吗?这些图层是如何“合在一起”形成图像的呢?
我是Docker的新手,我正在努力理解Docker图像到底是什么。Docker映像的每个定义都使用术语“层”,但似乎并没有定义层的含义。
来自Docker官方文档:
我们已经看到Docker镜像是启动Docker容器的只读模板。每张图像都由一系列图层组成。Docker利用联合文件系统将这些层组合成单个映像。联合文件系统允许透明地覆盖独立文件系统(称为分支)的文件和目录,从而形成一个统一的文件系统。
所以我问,什么是层;有人能举几个具体的例子吗?这些图层是如何“合在一起”形成图像的呢?
当前回答
自Docker v1.10以来,随着内容可寻址存储的引入,“层”的概念变得非常不同。图层没有图像或属于图像的概念,它们只是可以在图像之间共享的文件和目录的集合。图层和图像被分离。
例如,在一个从基础映像本地构建的映像上,比如说ubuntu:14.04, docker history命令会生成映像链,但是有些映像id会显示为'missing',因为构建历史不再加载。组成这些图像的图层可以通过
docker inspect <image_id> | jq -r '.[].RootFS'
如果存储驱动选择为aufs,则层内容存储在/var/lib/docker/aufs/diff。但是这些层是用一个随机生成的缓存ID命名的,似乎只有出于安全考虑,Docker引擎才知道层和它的缓存ID之间的链接。我还在想办法弄清楚
图像与其构成层之间的对应关系 磁盘上层的实际位置和大小
这个博客提供了很多见解。
其他回答
我认为官方文件给出了非常详细的解释: https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/。
(来源:docker.com)
image由很多层组成,这些层通常是从Dockerfile中生成的,Dockerfile中的每一行都将创建一个新的层,结果是一个image,用repo:tag的形式表示,如ubuntu:15.04。
欲了解更多信息,请考虑阅读上面的官方文档。
谢谢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
图层是包含文件和文件夹的文件夹,这些文件和文件夹是创建图像的结果。
例如:
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
我曾经认为它们就像前一层的差别。在阅读了这里的一些答案后,我不太确定;它们被描述为对文件系统的更改集。我写了一些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...>
您可以看到,即使在这两种情况下对文件系统的更改是相同的,顺序也很重要。
我个人的理解是我们可以将docker层与github提交进行比较。对于你的base image(你的fresh master repo),你做了几次提交,每一次提交都在改变你的master状态,这在docker中也是一样的,每一层都在做一些基于之前中间层的操作。然后,这一层成为下一层的新中间层。