【问题标题】:Docker missing layer IDs in outputDocker 在输出中缺少层 ID
【发布时间】:2016-02-10 08:36:02
【问题描述】:

我刚刚使用官方指南在 Ubuntu 上全新安装了 Docker:https://docs.docker.com/engine/installation/linux/ubuntulinux/

当我使用“sudo docker pull ubuntu”和“sudo docker history ubuntu”拉取图像时,它会在列中返回缺失的层 ID。使用文档示例(https://docs.docker.com/engine/reference/commandline/history/)我的输出是:

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

等等。仅显示基础层 ID,其余“缺失”。我尝试在连接到不同网络的另一台 Ubuntu 机器上安装,但我下载的任何图像都有相同的问题。

有人知道是什么原因造成的或能帮我解决吗?我依赖这个图层 ID,因为我正在收集一些关于图层可重用性的统计数据,所以我需要这个 ID 才能正确显示。

【问题讨论】:

    标签: ubuntu docker


    【解决方案1】:

    正如您在issue 20131 中提到的,这可能是新的docker 1.10 content addressability migration 的结果

    来自Docker blog post

    从 v1.10 开始,我们彻底改变了 Docker 寻址磁盘上图像数据的方式。
    以前,每个图像和图层都使用随机分配的 UUID。
    在 1.10 中,我们使用 ID 实现了内容寻址方法,基于图像和图层数据的安全哈希。

    这就是为什么thaJeztah cmets:

    我认为这是意料之中的;内容寻址存储不再使用“父”图像将图像层链接在一起。
    新拉取的​​图像也不再显示中间图像(这些“丢失”的图像只会显示在主机上存在但已迁移到新存储的图像)


    2016 年 6 月更新(3 个月后)

    Nigel Brown 有一篇关于那些“丢失”图像的详细文章。

    Explaining Docker Image IDs

    在 Docker 映像构建过程中创建一个层或“差异”,并在容器中运行命令时产生结果,这些命令会生成新的或修改的文件和目录。
    这些新的或修改的文件和目录被“提交”为一个新层。

    从历史上看(Docker v1.10 之前),每次由于提交操作而创建新层时,Docker 也会创建相应的镜像,该镜像由随机生成的 256 位 UUID 标识,通常称为图像 ID

    改变的一大驱动力来自于缺乏检测图像内容在向注册表推送或从注册表拉取期间是否被篡改的方法,例如@987654328 @。这导致了整个社区的 robust criticism,并导致了一系列变化,最终形成了内容可寻址 ID。

    从 Docker v1.10 开始,图像和图层通常不再是同义词
    取而代之的是,图像直接引用一个或多个层,这些层最终有助于派生容器的文件系统。

    层现在由摘要标识,其形式为 algorithm:hex;

    Docker 映像现在包含一个配置对象,该对象(除其他外)包含层摘要的有序列表,这使 Docker 引擎能够参考层摘要而不是父映像来组装容器的文件系统。

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

    $ 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  
    

    IMAGE 字段中的 &lt;missing&gt; 值用于除图像的一层之外的所有图层,具有误导性且有点令人遗憾。它传达了错误的建议,但没有错误,因为图层不再与相应的图像和 ID 同义
    我认为离开会更合适字段空白

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

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

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

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

    中间图像和对父图像的引用的目的是方便使用Docker的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  
    

    在此示例中,顶部两层是在本地映像构建期间创建的,而底部层来自构建的基础映像(例如 Dockerfile instruction FROM debian)。

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

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

    当本地构建的镜像被推送到注册表时,只有叶子镜像连同其组成层一起上传,随后由另一个 Docker 主机拉取不会产生任何中间父镜像.

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

    最后:

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

    【讨论】:

    • 谢谢,这至少证实了问题出在哪里。您是否碰巧知道任何允许我检查图层是否被其他 docker 映像重用的解决方法?我想我现在必须比较每一层的数据?
    • @Piet 我还不知道:我现在正在 1.10 中迁移我自己的图像!
    • 感谢详细的文章,内容丰富!你知道是否有办法让 Docker 的构建缓存识别并利用从远程注册表中拉下的叶映像中的层?我从注册表中提取了一个图像,正如您所描述的,除了最后一层之外,所有层都有一个 注释,表明这些层不是中间图像。但是在本地重建(从同一个 Dockerfile)似乎没有使用我从远程注册表中提取的图像中包含的任何层。
    • @dm03514 不确定,但首先,我们在谈论什么 docker 版本?镜像是用 1.10 之前的 docker 构建的吗?
    • 有没有办法在不推送图像的情况下重现压缩?是否可以在本地构建映像并计算其分发(压缩)摘要而不实际将其推送到注册表?
    猜你喜欢
    • 2017-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-24
    相关资源
    最近更新 更多