了解 docker 层和未来的变化 [英] Understanding docker layers and future changes

查看:19
本文介绍了了解 docker 层和未来的变化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

<块引用>

每个 Docker 映像都引用了代表文件系统差异的只读层列表.层相互堆叠,形成容器根文件系统的基础.

和,

<块引用>

因为每个容器都有自己的瘦可写容器层,所有的变化都存储在这个容器层中,这意味着多个容器可以共享访问同一个底层镜像 却拥有自己的数据状态.

还有,

<块引用>

Docker 映像的各层本质上只是通过运行某些命令生成的文件.您可以在 /var/lib/docker/aufs/diff 查看 Docker 主机上每一层的内容.

现在,问题,

  • 假设我逐层构建 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 images B, C, D 每个只在其层中添加 pkgB、pkgC 和 pkgD.如果我将 pkgA 添加到 A B, C, D 构建后,会发生什么?——我想应该有一个单一版本的真理,作为一个单一的系统,什么是包,那么对于这种情况会是什么?
  • 如果我只升级 A 中的包怎么办?这应该没问题吧?其余的 docker 镜像也会看到这些变化吗?

解决方案

总体而言,每个图像都包含其父图像,作为嵌入字节或作为对本地缓存中图像的硬"引用(如果它已经存在).

父级"是指 Dockerfile 中的 FROM: someimage 指令.

我还写了hard",因为参考实际上是父图像的 sha246 摘要.如果父项的任何位发生变化,摘要将有所不同.

这里主要有三种情况:

  1. 您从清除缓存开始(docker image ls -a 什么也不显示).如果你 docker pull ... 来自公共注册表的一些图像,它将嵌入其父级.docker ps -a 应该只显示一个图像.

  2. 如果您的缓存中已经有父图像,则 docker pull ... 不会再次下载父图像.在这种情况下,拉取的图像会引用缓存中的父级.

  3. 如果您从清除缓存本地构建,docker 将下载父映像并生成一个引用父映像的子映像.

最后还是一样的结果.如果您将父图像替换为较新的版本,则摘要将不一样.

如果另一个镜像引用了一个镜像,Docker 不会让你删除它.当您将图像推送到注册表时,父级是嵌入的(我在这里略过注册表端的缓存行为).我认为您也可以使用 docker exportdocker import 嵌入父级,但我还没有尝试过.例如,docker export B,然后从 docker 缓存中删除 A 和 B,docker import B 应该只显示一个图像.

您可以使用

获得实际的父关系

docker 镜像检查 <image-id>|grep -E "Id|父母"

结合

docker image ls -a --digests

检查关系.

更多信息.

当您构建映像时,会发生以下步骤:

  1. 构建上下文通过 docker 守护进程发送到主机.这基本上是 Dockerfile 所在目录中的所有文件.这就是为什么使用 .dockerignore 仅发送在 Dockerfile 中复制的文件很重要的原因.
  2. docker 守护进程使用 Dockerfile 中的 FROM 指令创建一个临时容器.这是导入的图像,包括它自己的导入图像.然后 Dockefile 中的每条指令都在该容器内执行.当在临时容器中进行持久更改(如复制)时,它会保存其状态.这有效地为最终图像添加了一层.
  3. 执行完 DOCKERFILE 指令后,临时容器将被销毁.剩下的就是最终图像.

您可以使用以下命令查看图像中的所有图层docker 历史 <image-id>

请注意,这提供了一种方便的方式来调试 Dockerfile.您应该会看到与 Dockerfile 中的持久指令相对应的层的 id.您可以使用 docker run --rm -it <id next to layer> 从任何层创建一个新容器.sh 并手动执行后面的 Dockerfile 指令.

So,

Each Docker image references a list of read-only layers that represent filesystem differences. Layers are stacked on top of each other to form a base for a container’s root filesystem.

and,

Because each container has its own thin writable container layer, and all changes are stored in this container layer, this means that multiple containers can share access to the same underlying image and yet have their own data state.

and also,

Layers of a Docker image are essentially just files generated from running some command. You can view the contents of each layer on the Docker host at /var/lib/docker/aufs/diff.

Now, questions,

  • Say I build my docker images layer by layer. A < B < C < D, etc.
  • Now if I update my docker image A, would the rest of docker images B, C, D see the changes as well, provided that the changes are not touched by them when building them? E.g., adding /etc/apt/sources.list.d/somethingnew that was never there before.
  • If I had built another set of docker images layer by layer. A < X < Y < Z, then the above changes will be reflected in X, Y, Z as well, right?
  • Now if however, the future changes to A, is made to the same file that will be changed when building B, C, D, then what would happen? For e.g., let's make it simple that docker images B, C, D each only add pkgB, pkgC, and pkgD in its layer. If I add a pkgA to A after B, C, D are build, what would happen? -- I guess there should be one single version of truth as what packages are in, for a single system, so what would it be for this case?
  • What if I'm only upgrading the packages in A? This should be OK right? Would the rest of docker images see the changes as well?

解决方案

Overall, each image contains its parent image, either as embedded bytes or as a "hard" reference to an image in your local cache if it is already there.

By "parent" I mean the FROM: someimage instruction in your Dockerfile.

I also wrote "hard" since the reference is actually a sha246 digest of the parent image. If any bit of the parent changes, the digest will be different.

There are three main cases here:

  1. You start with a clear cache (docker image ls -a shows nothing). If you docker pull ... some image from a public registry, it will have its parent embedded. A docker ps -a should show only one image.

  2. If however you already have the parent image in your cache, the docker pull ... won't download the parent again. In that case, the pulled image has a reference to the parent in your cache.

  3. If you build locally from a clear cache, docker will download the parent image and produce a child image with a reference to the parent.

It's still the same result at the end. If you replace the parent image with a newer version, the digest won't be the same.

Docker won't let you delete an image if another image references it. When you push your image to a registry, the parent is embedded (I'm skimping over caching behaviour on the registry side here). I think that you can also embed the parent by using docker export and docker import but I haven't tried it. For instance, docker export B, then delete A and B from your docker cache and docker import B should show only one image.

You can get the actual parent relationship using

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

combine that with

docker image ls -a --digests

To inspect the relationships.

Some more info.

When you build an image, the following steps occur:

  1. The build context is sent to the host with the docker daemon. This is basically all the files in the directory that your Dockerfile is in. That's why it is important to make use of .dockerignore to only send files that are COPY'd in your Dockerfile.
  2. The docker daemon creates a temporary container using the FROM instruction in the Dockerfile. This is the imported image, including its own imported images. Then every instruction in the Dockefile is executed inside that container. When a persistent change is made in the temporary container (like COPY'ing), it then saves its state. This effectively adds a layer to the final image.
  3. Once finished executing the DOCKERFILE instructions, the temporary container is destroyed. You are left with the final image.

You can see all the layers in the image using docker history <image-id>

Note that this offers a handy way to debug a Dockerfile. You should see an id for the layers that correspond to persistent instructions in your Dockerfile. You can create a new container from any layer using docker run --rm -it <id next to layer> sh and manually execute the Dockerfile instructions that follow.

这篇关于了解 docker 层和未来的变化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆