Docker镜像的关键概念

Docker镜像的关键概念

我们尝试解压一个镜像的tar包(demo-1.0.tar.gz)

tar文件目录如下

cbd1cdce753fb2defc9ca899742ebf1a16933189d9111ed69a97fcb7ba631593.json
repositories
manifest.json
1a58e6937db044ef6f2e2962a0dc7bef16a6c33fdfc5a0318c39092612a1bd1a
c12f86d2a60fc27a1d93d555944262fda4ed66e3a3172ac45cd861151a0dc6c1
98867178f60349f16652222772d086159a6d087fcd50bc32b9d75c23cd01ed8d
21c47a73cf2af80d1b2321a7be026939f42b5c8734aa51ecfe1fcc6ca669faeb
        

1. registry

简单想象成类似Git仓库之类的实体

registry由一系列经过命名的repository组成

2. repository

repository 即具有 某个功能的Docker镜像的所有迭代版本构成的 镜像组.

(repository是一个镜像集合,其中包含了多个不同的版本的镜像,使用标签进行版本区分)

repository通过命名规范对用户仓库和顶层仓库进行组织.

用户仓库的命名由用户名和repository名两部分组成,中间以"/"隔开,

即username/repository_name的形式,repository名通常表示镜像所具有的功能

而顶层仓库则只包含repository名的部分.

repositories.json文件内容:

{"cpsdc-platform/middleware-app":
 {"master-59":
  "21c47a73cf2af80d1b2321a7be026939f42b5c8734aa51ecfe1fcc6ca669faeb"
 }
}

3. manifest

manifest 描述文件 主要存在于registry中作为Docker镜像的元数据文件,在pull/push/save/load中

作为镜像结构和基础信息的描述文件.

在镜像被pull/load到Docker宿主机时,manifest被转化为本地的镜像配置文件config.

manifest.json文件内容:

[
    {
        "Config":"cbd1cdce753fb2defc9ca899742ebf1a16933189d9111ed69a97fcb7ba631593.json",
        "RepoTags":[
            "cpsdc-platform/middleware-app:master-59"
        ],
        "Layers":[
            "1a58e6937db044ef6f2e2962a0dc7bef16a6c33fdfc5a0318c39092612a1bd1a/layer.tar",
            "c12f86d2a60fc27a1d93d555944262fda4ed66e3a3172ac45cd861151a0dc6c1/layer.tar",
            "98867178f60349f16652222772d086159a6d087fcd50bc32b9d75c23cd01ed8d/layer.tar",
            "21c47a73cf2af80d1b2321a7be026939f42b5c8734aa51ecfe1fcc6ca669faeb/layer.tar"
        ]
    }
]

4. image和layer(镜像和镜像层)

Docker 内部的image概念是用来存储一组镜像相关的元数据信息,

主要包括:

  • 镜像的架构(如amd64)

  • 镜像默认配置信息

  • 构建镜像的容器配置信息, 容器ID,创建时间,创建该镜像的Docker版本,构建镜像历史

  • 包含所有镜像层信息的rootfs.

Docker利用rootfs中的diff_id计算出内容寻址的索引(chainID)来获取layer相关信息,

进而获取每一个镜像层的文件内容.

image元数据

cbd1cdce753fb2defc9ca899742ebf1a16933189d9111ed69a97fcb7ba631593.json

文件内容如下:

{
    "architecture":"amd64",
    "config":{
        "Hostname":"",
        "Domainname":"",
        "User":"",
        "AttachStdin":false,
        "AttachStdout":false,
        "AttachStderr":false,
        "ExposedPorts":{
            "8080/tcp":{

            }
        },
        "Tty":false,
        "OpenStdin":false,
        "StdinOnce":false,
        "Env":[
            "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/jvm/java-1.8-openjdk/jre/bin:/usr/lib/jvm/java-1.8-openjdk/bin",
            "LANG=C.UTF-8",
            "JAVA_HOME=/usr/lib/jvm/java-1.8-openjdk",
            "JAVA_VERSION=8u212",
            "JAVA_ALPINE_VERSION=8.212.04-r0",
            "JAVA_OPTS="
        ],
        "Cmd":null,
        "ArgsEscaped":true,
        "Image":"sha256:776867d1b220c1a3759f764bc560686fbf1165b5d4aeff4db23a5791075823de",
        "Volumes":{
            "/tmp":{

            },
            "/var/log":{

            }
        },
        "WorkingDir":"",
        "Entrypoint":[
            "/bin/sh",
            "-c",
            "exec java $JAVA_OPTS -jar app.jar"
        ],
        "OnBuild":null,
        "Labels":null
    },
    "container":"38a74d3908c829acb5235fafdc39a8cdd586fce6e4215f65de6f70f342e7be98",
    "container_config":{
        "Hostname":"38a74d3908c8",
        "Domainname":"",
        "User":"",
        "AttachStdin":false,
        "AttachStdout":false,
        "AttachStderr":false,
        "ExposedPorts":{
            "8080/tcp":{

            }
        },
        "Tty":false,
        "OpenStdin":false,
        "StdinOnce":false,
        "Env":[
            "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/jvm/java-1.8-openjdk/jre/bin:/usr/lib/jvm/java-1.8-openjdk/bin",
            "LANG=C.UTF-8",
            "JAVA_HOME=/usr/lib/jvm/java-1.8-openjdk",
            "JAVA_VERSION=8u212",
            "JAVA_ALPINE_VERSION=8.212.04-r0",
            "JAVA_OPTS="
        ],
        "Cmd":[
            "/bin/sh",
            "-c",
            "#(nop) ",
            "EXPOSE 8080"
        ],
        "ArgsEscaped":true,
        "Image":"sha256:776867d1b220c1a3759f764bc560686fbf1165b5d4aeff4db23a5791075823de",
        "Volumes":{
            "/tmp":{

            },
            "/var/log":{

            }
        },
        "WorkingDir":"",
        "Entrypoint":[
            "/bin/sh",
            "-c",
            "exec java $JAVA_OPTS -jar app.jar"
        ],
        "OnBuild":null,
        "Labels":{

        }
    },
    "created":"2021-07-20T11:23:43.475808513Z",
    "docker_version":"18.09.9",
    
    "history":[
        {
            "created":"2019-05-11T00:07:03.358250803Z",
            "created_by":"/bin/sh -c #(nop) ADD file:a86aea1f3a7d68f6ae03397b99ea77f2e9ee901c5c59e59f76f93adbb4035913 in / "
        },
        {
            "created":"2019-05-11T00:07:03.510395965Z",
            "created_by":"/bin/sh -c #(nop)  CMD [\"/bin/sh\"]",
            "empty_layer":true
        },
        {
            "created":"2019-05-11T01:32:11.0323736Z",
            "created_by":"/bin/sh -c #(nop)  ENV LANG=C.UTF-8",
            "empty_layer":true
        },
        {
            "created":"2019-05-11T01:32:12.044405061Z",
            "created_by":"/bin/sh -c { \t\techo '#!/bin/sh'; \t\techo 'set -e'; \t\techo; \t\techo 'dirname \"$(dirname \"$(readlink -f \"$(which javac || which java)\")\")\"'; \t} \u003e /usr/local/bin/docker-java-home \t\u0026\u0026 chmod +x /usr/local/bin/docker-java-home"
        },
        {
            "created":"2019-05-11T01:32:12.271831312Z",
            "created_by":"/bin/sh -c #(nop)  ENV JAVA_HOME=/usr/lib/jvm/java-1.8-openjdk",
            "empty_layer":true
        },
        {
            "created":"2019-05-11T01:32:12.506789049Z",
            "created_by":"/bin/sh -c #(nop)  ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/jvm/java-1.8-openjdk/jre/bin:/usr/lib/jvm/java-1.8-openjdk/bin",
            "empty_layer":true
        },
        {
            "created":"2019-05-11T01:32:12.755877628Z",
            "created_by":"/bin/sh -c #(nop)  ENV JAVA_VERSION=8u212",
            "empty_layer":true
        },
        {
            "created":"2019-05-11T01:32:13.051281176Z",
            "created_by":"/bin/sh -c #(nop)  ENV JAVA_ALPINE_VERSION=8.212.04-r0",
            "empty_layer":true
        },
        {
            "created":"2019-05-11T01:32:17.777332452Z",
            "created_by":"/bin/sh -c set -x \t\u0026\u0026 apk add --no-cache \t\topenjdk8=\"$JAVA_ALPINE_VERSION\" \t\u0026\u0026 [ \"$JAVA_HOME\" = \"$(docker-java-home)\" ]"
        },
        {
            "created":"2021-07-20T11:23:29.98302564Z",
            "created_by":"/bin/sh -c #(nop)  VOLUME [/tmp /var/log]",
            "empty_layer":true
        },
        {
            "created":"2021-07-20T11:23:33.156968333Z",
            "created_by":"/bin/sh -c #(nop) ADD file:13d31caa85b9055e5fceeb2ea1b04861b6f5b162ecb61f53c929a42c77df1fee in app.jar "
        },
        {
            "created":"2021-07-20T11:23:37.765093873Z",
            "created_by":"/bin/sh -c #(nop)  ENV JAVA_OPTS=",
            "empty_layer":true
        },
        {
            "created":"2021-07-20T11:23:40.436505735Z",
            "created_by":"/bin/sh -c #(nop)  ENTRYPOINT [\"/bin/sh\" \"-c\" \"exec java $JAVA_OPTS -jar app.jar\"]",
            "empty_layer":true
        },
        {
            "created":"2021-07-20T11:23:43.475808513Z",
            "created_by":"/bin/sh -c #(nop)  EXPOSE 8080",
            "empty_layer":true
        }
    ],
    "os":"linux",
    "rootfs":{
        "type":"layers",
        "diff_ids":[
            "sha256:f1b5933fe4b5f49bbe8258745cf396afe07e625bdab3168e364daf7c956b6b81",
            "sha256:9b9b7f3d56a01e3d9076874990c62e7a516cc4032f784f421574d06b18ef9aa4",
            "sha256:ceaf9e1ebef5f9eaa707a838848a3c13800fcf32d7757be10d4b08fb85f1bc8a",
            "sha256:f149ec39d98314f3ad56fcce4505642a19293d8c72b7ad491935eb472c624489"
        ]
    }
}

layer (镜像层) 是一个Docker用来管理镜像层的中间概念, 镜像是由镜像层组成的,而单个镜像层可能被多个镜像共享,

所以Docker将layer和image的概念分离.

Docker镜像管理中layer主要存放了镜像层的diff_id,size,cache-id和parent等内容,

实际文件内容则是由存储驱动来管理,并可以通过cache-id在本地索引找到.

5. Dockerfile

Dockerfile是通过docker build命令构建自己的Docker镜像时需要使用到的定义文件.

Docker存储管理

Docker 镜像在设计上将镜像元数据与镜像文件的存储完全隔离开了.

Docker 在管理镜像层元数据时,采用的也正是从上至下repository,image,layer三个层次.

1.repository元数据

由于Docker以分层的形式存储镜像,所以repository与image这两类元数据并无物理上的镜像文件与之对应,

而layer这种元数据存在物理上的镜像层文件与之对应.

repositories.json文件存储了所有repository的名字

{"cpsdc-platform/middleware-app":
 {"master-59":
  "21c47a73cf2af80d1b2321a7be026939f42b5c8734aa51ecfe1fcc6ca669faeb"
 }
}

2. image元数据

Docker 内部的image概念是用来存储一组镜像相关的元数据信息,

主要包括:

  • 镜像的架构(如amd64)

  • 镜像默认配置信息

  • 构建镜像的容器配置信息, 容器ID,创建时间,创建该镜像的Docker版本,构建镜像历史

  • 包含所有镜像层信息的rootfs.

其中构建镜像的历史信息和rootfs组成部分除了具有描述镜像的作用外,

还将镜像和构建该镜像的镜像层关联了起来.

Docker会根据历史信息和rootfs中的diff_ids计算出构建该镜像的镜像层的存储索引chainID.

这也是Docker1.10 镜像存储中基于内容寻址的核心技术.

3. layer元数据

Docker 1.10 之后,镜像层只包含一个具体的镜像层文件包.

在layer的所有属性中,diffId采用SHA256算法,基于镜像层文件包的内容计算得到.

而chainID是基于内容存储的索引,它是根据当前层与所有祖先镜像层diffID计算出来的.

chainID算法如下:

  • 如果该镜像层是最底层(没有父镜像层),该层的diffID便是chainID.

  • 该镜像层的chainID计算公式为 chainID(n) = SHA(chain(n-1) diffID(n))

    即 根据父镜像层的chainID加上一个空格和当前层diffID,再计算出SHA256校验码.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值