Docker 在输出中缺少层 ID [英] Docker missing layer IDs in output

查看:21
本文介绍了Docker 在输出中缺少层 ID的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚使用官方指南在 Ubuntu 上全新安装了 Docker:

<块引用>

变革的主要驱动力之一是缺乏检测图像内容在推送到注册表或从注册表中拉取期间是否被篡改的方法,例如

<块引用>

因此,当从注册表中提取 Docker 映像并使用 docker history 命令显示其内容时,输出将提供类似于:

$ docker history swarm按尺寸创建的图像创建注释c54bba046158 9 天前/bin/sh -c #(nop) CMD ["--help"] 0 B<失踪>9 天前/bin/sh -c #(nop) ENTRYPOINT &{["/swarm"]} 0 B<失踪>9 天前/bin/sh -c #(nop) VOLUME [/.swarm] 0 B<失踪>9 天前/bin/sh -c #(nop) EXPOSE 2375/tcp 0 B<失踪>9 天前/bin/sh -c #(nop) ENV SWARM_HOST=:2375 0 B<失踪>9 天前/bin/sh -c #(nop) COPY dir:b76b2255a3b423981a 0 B<失踪>9 天前/bin/sh -c #(nop) COPY file:5acf949e76228329d 277.2 kB<失踪>9 天前/bin/sh -c #(nop) 复制文件:a2157cec2320f541a 19.06 MB

<块引用>

IMAGE 字段中的 值,除了图像的一层之外,其他所有层的值都具有误导性且有点不幸.它传达了错误的建议,但没有错误,因为图层不再与相应的图像和 ID 同义.
我认为将该字段留空会更合适.

此外,图像 ID 似乎与最上层相关联,但实际上,图像 ID 不属于"任何层.相反,这些层共同属于映像,并提供其文件系统定义.

但是(本地与远程图像):

<块引用>

Docker 主机上本地构建的映像的处理方式略有不同.
本地构建的镜像的通用内容保持不变——它是一个包含配置项的配置对象,包括层摘要的有序列表.

但是,当在本地 Docker 主机上构建映像期间提交层时,会同时创建一个中间"映像.
就像所有其他图像一样,它有一个配置项,它是要作为图像一部分合并的层摘要列表,其 ID 或摘要包含配置对象的哈希值.中间图像没有用名称标记,但是,它们确实有一个父"键,其中包含父图像的 ID.

中间镜像和对父镜像的引用,是为了方便使用Docker的构建缓存.

$ docker history jbloggs/my_image:latest按尺寸创建的图像创建注释26cca5b0c787 52 秒前/bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/bin/b 0 B97e47fb9e0a6 52 秒前/bin/sh -c apt-get update &&apt-get 安装 16.98 MB1742affe03b5 13 天前/bin/sh -c #(nop) CMD ["/bin/bash"] 0 B<失踪>13 天前/bin/sh -c #(nop) 添加文件:5d8521419ad6cfb695 125.1 MB

<块引用>

在这个例子中,最上面的两层是在本地镜像构建期间创建的,而底层来自构建的基础镜像(例如 Dockerfile 指令 FROM debian).

我们可以使用 docker inspect 命令来查看与图像关联的层摘要:

docker history 命令显示图像有四层,但 docker inspect 建议只有三层.
这是因为两条 CMD 指令为图像生成元数据,不添加任何内容,因此 'diff' 为空.
摘要 5f70bf18a08a 是空层的 SHA256 哈希值,并由相关的两个层共享.

当一个本地构建的镜像被推送到注册中心时,它只是与其组成层一起上传的叶镜像,并且后续由另一个 Docker 主机拉取不会产生任何中间父镜像.

这是因为一旦镜像通过注册表提供给不同 Docker 主机上的其他潜在用户,它实际上变为只读,并且不再需要支持构建缓存的组件.
代替图像 ID, 被插入到历史输出中的位置.

最后:

<块引用>

Docker 在 Docker 主机上用于层差异"的摘要,包含差异的 tar 存档内容的 sha256 哈希.
在将层作为推送的一部分上传到注册表之前,它会被压缩以提高带宽效率. 还创建了一个清单来描述图像的内容,其中包含压缩层的摘要内容.因此,清单中各层的摘要与其未压缩状态下生成的摘要不同.

I just did a fresh install of Docker on Ubuntu using the official guidelines: https://docs.docker.com/engine/installation/linux/ubuntulinux/

When I pull an image using "sudo docker pull ubuntu" and then "sudo docker history ubuntu" it returns missing layer IDs in the columns. Using the documentation example ( https://docs.docker.com/engine/reference/commandline/history/ ) my output is:

IMAGE CREATED CREATED BY SIZE COMMENT
3e23a5875458 8 days ago /bin/sh -c #(nop) ENV LC_ALL=C.UTF-8 0 B
"missing" 8 days ago /bin/sh -c dpkg-reconfigure locales && loc 1.245 MB
"missing" 8 days ago /bin/sh -c apt-get update && apt-get install 338.3 MB

and so on. Only the base layer ID shows, the rest is "missing". I tried installing on another Ubuntu machine connected to a different network and it has the same problem for any image that I download.

Does someone know what's causing this or able to help me fix it? I rely on this layer ID since I'm gathering some statistics on the reusability of layers so I need this ID to show correctly.

解决方案

As mentioned in your issue 20131, this could be the consequence of the new docker 1.10 content addressability migration

From the Docker blog post:

Starting from v1.10 we completely change the way Docker addresses the image data on disk.
Previously, every image and layer used a randomly assigned UUID.
In 1.10 we implemented a content addressable method using an ID, based on a secure hash of the image and layer data.

That is why thaJeztah comments:

I think this is expected; the content-addressable storage no longer uses "parent" images to chain the image-layers together.
Newly pulled images also no longer will show the intermediate images (these "missing" images will only be shown for images that were present on the host, but have been migrated to the new storage)


Update June 2016 (3 months later)

Nigel Brown has a detailed article about those "missing" images.

Explaining Docker Image IDs

A layer or 'diff' is created during the Docker image build process, and results when commands are run in a container, which produce new or modified files and directories.
These new or modified files and directories are 'committed' as a new layer.

Historically (pre Docker v1.10), each time a new layer was created as a result of a commit action, Docker also created a corresponding image, which was identified by a randomly generated 256-bit UUID, usually referred to as an image ID

One of the big drivers for change, came from the lack of a means of detecting whether an image's contents had been tampered with during a push to or pull from a registry, such as the Docker Hub. This led to robust criticism from the community at large, and led to a series of changes, culminating in content addressable IDs.

Since Docker v1.10, generally, images and layers are no longer synonymous.
Instead, an image directly references one or more layers that eventually contribute to a derived container's filesystem.

Layers are now identified by a digest, which takes the form algorithm:hex;

A Docker image now consists of a configuration object, which (amongst other things) contains an ordered list of layer digests, which enables the Docker Engine to assemble a container's filesystem with reference to layer digests rather than parent images.

So, when a Docker image is pulled from a registry, and the docker history command is used to reveal its contents, the output provides something similar to:

$ docker history swarm
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT  
c54bba046158        9 days ago          /bin/sh -c #(nop) CMD ["--help"]                0 B  
<missing>           9 days ago          /bin/sh -c #(nop) ENTRYPOINT &{["/swarm"]}      0 B  
<missing>           9 days ago          /bin/sh -c #(nop) VOLUME [/.swarm]              0 B  
<missing>           9 days ago          /bin/sh -c #(nop) EXPOSE 2375/tcp               0 B  
<missing>           9 days ago          /bin/sh -c #(nop) ENV SWARM_HOST=:2375          0 B  
<missing>           9 days ago          /bin/sh -c #(nop) COPY dir:b76b2255a3b423981a   0 B  
<missing>           9 days ago          /bin/sh -c #(nop) COPY file:5acf949e76228329d   277.2 kB  
<missing>           9 days ago          /bin/sh -c #(nop) COPY file:a2157cec2320f541a   19.06 MB  

The <missing> value in the IMAGE field for all but one of the layers of the image, is misleading and a little unfortunate. It conveys the suggestion of an error, but there is no error as layers are no longer synonymous with a corresponding image and ID.
I think it would have been more appropriate to have left the field blank.

Also, the image ID appears to be associated with the uppermost layer, but in fact, the image ID doesn't 'belong' to any of the layers. Rather, the layers collectively belong to the image, and provide its filesystem definition.

But (local vs. remote images):

locally built images on a Docker host are treated slightly differently.
The generic content of an image built locally remains the same - it is a configuration object containing configuration items, including an ordered list of layer digests.

However, when a layer is committed during an image build on a local Docker host, an 'intermediate' image is created at the same time.
Just like all other images, it has a configuration item which is a list of the layer digests that are to be incorporated as part of the image, and its ID or digest contains a hash of the configuration object. Intermediate images aren't tagged with a name, but, they do have a 'Parent' key, which contains the ID of the parent image.

The purpose of the intermediate images and the reference to parent images, is to facilitate the use of Docker's build cache.

$ docker history jbloggs/my_image:latest 
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT  
26cca5b0c787        52 seconds ago      /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/bin/b   0 B  
97e47fb9e0a6        52 seconds ago      /bin/sh -c apt-get update &&     apt-get inst   16.98 MB  
1742affe03b5        13 days ago         /bin/sh -c #(nop) CMD ["/bin/bash"]             0 B  
<missing>           13 days ago         /bin/sh -c #(nop) ADD file:5d8521419ad6cfb695   125.1 MB  

In this example, the top two layers are created during the local image build, whilst the bottom layers came from the base image for the build (e.g. Dockerfile instruction FROM debian).

We can use the docker inspect command to review the layer digests associated with the image:

The docker history command shows the image as having four layers, but docker inspect suggests just three layers.
This is because the two CMD instructions produce metadata for the image, don't add any content, and therefore the 'diff' is empty.
The digest 5f70bf18a08a is the SHA256 hash of an empty layer, and is shared by both of the layers in question.

When a locally built image is pushed to a registry, it is only the leaf image that is uploaded along with its constituent layers, and a subsequent pull by another Docker host will not yield any intermediate parent images.

This is because once the image is made available to other potential users on different Docker hosts via a registry, it effectively becomes read-only, and the components that support the build cache are no longer required.
Instead of the image ID, <missing> is inserted into the history output in its place.

Finally:

The digests that Docker uses for layer 'diffs' on a Docker host, contain the sha256 hash of the tar archived content of the diff.
Before the layer is uploaded to a registry as part of a push, it is compressed for bandwidth efficiency. A manifest is also created to describe the contents of the image, and it contains the digests of the compressed layer content. Consequently, the digests for the layers in the manifest are different to those generated in their uncompressed state.

这篇关于Docker 在输出中缺少层 ID的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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