了解Docker层和未来的变化

时间:2019-03-15 01:21:18

标签: docker ubuntu debian

So

enter image description here

  

每个Docker映像均引用代表文件系统差异的只读层的列表。各个层堆叠在一起,形成容器根文件系统的基础。

enter image description here

  

因为每个容器都有其自己的可写薄容器层,并且所有更改都存储在该容器层中,所以这意味着多个容器可以共享访问相同的基础映像 >却拥有自己的数据状态。

also

  

Docker镜像的层实际上只是通过运行某些命令而生成的文件。您可以在/var/lib/docker/aufs/diff上查看Docker主机上每一层的内容。

现在,问题

  • 说我逐层构建我的码头工人镜像。 A < B < C < D
  • 现在,如果我更新我的Docker映像 A,则只要Docker映像B, C, D不会在未触及更改的情况下也能看到更改建立他们?例如,添加从未有过的/etc/apt/sources.list.d/somethingnew
  • 如果我逐层构建了另一套 docker镜像。 A < X < Y < Z,那么以上更改也将反映在X, Y, Z中,对吗?
  • 现在,如果将来对A的更改是对同一文件进行的,而在构建B, C, D时将进行更改,那么会发生什么呢?例如,让我们简单起见,docker映像B, C, D每个仅在其层中添加pkgB,pkgC和pkgD。如果在A构建完成后向B, C, D 添加pkgA,会发生什么情况? -我猜应该有一个单一版本的真理,因为对于单个系统,其中包含什么软件包,那么这种情况会是什么?
  • 如果我仅升级 A中的软件包怎么办?这样应该可以吧?其余Docker映像也会看到更改吗?

1 个答案:

答案 0 :(得分:1)

总体而言,每个图像都包含其父图像,可以是嵌入式字节,也可以是对本地缓存中图像的“硬”引用(如果已有的话)。

“父母”是指Dockerfile中的FROM: someimage指令。

我还写了“ hard”,因为该引用实际上是父图像的sha246摘要。如果父级的任何一位更改,则摘要将有所不同。

这里有三种主要情况:

  1. 您首先要使用明确的缓存(docker image ls -a什么也不显示)。如果您docker pull ...来自公共注册表的某些图像,则其父图像将被嵌入。 docker ps -a应该只显示一张图像。

  2. 但是,如果缓存中已经有父映像,则docker pull ...将不会再次下载父映像。在这种情况下,提取的图像会在缓存中引用父对象。

  3. 如果您从明确的缓存中进行本地构建,则docker将下载父映像并生成一个引用父映像的子映像。

最后仍然是相同的结果。如果将父映像替换为较新的版本,则摘要将不同。

如果另一个映像引用了Docker,Docker将不允许您删除它。当您将映像推送到注册表时,父级已嵌入(我在此处跳过了注册表端的缓存行为)。我认为您也可以使用docker exportdocker import来嵌入父对象,但我还没有尝试过。例如,docker export B,然后从docker缓存中删除A和B,而docker import B应该只显示一个图像。

您可以使用来获得实际的父母关系

docker image inspect <image-id> | grep -E "Id|Parent"

组合
docker image ls -a --digests

检查关系。

更多信息。

构建映像时,将发生以下步骤:

  1. 构建上下文通过docker守护程序发送到主机。这基本上是Dockerfile所在目录中的所有文件。这就是为什么使用.dockerignore仅发送Dockerfile中COPY的文件很重要的原因。
  2. Docker守护程序使用Dockerfile中的FROM指令创建一个临时容器。这是导入的图像,包括其自己的导入图像。然后,在该容器内执行Dockefile中的每条指令。在临时容器中进行持久更改(例如COPY'ing)后,它将保存其状态。这样可以有效地在最终图像上添加一层。
  3. 完成DOCKERFILE指令执行后,临时容器将被破坏。您将获得最终的图像。

您可以使用来查看图像中的所有图层 docker history <image-id>

请注意,这提供了调试Dockerfile的便捷方法。您应该在Dockerfile中看到对应于持久性指令的层的ID。您可以使用docker run --rm -it <id next to layer> sh从任何层创建一个新容器,并手动执行随后的Dockerfile指令。