目录

    1. 开启 Docker 的 experimental 特性

    这里先开启 Docker 的 experimental 特性,方便下文使用相关命令。

    编辑文件 vim ~/.docker/config.json ,增加如下内容:

    {
      "experimental": "enabled",
      "debug": true
    }
    

    注意,这里不是 /etc/docker/daemon.json 文件,也不需要重启 Docker 。

    2. Docker 镜像

    从 Docker 1.10 、 Registry 2.3 开始,Docker 引入了 manifest 用于描述镜像的元数据。

    2.1 Dockerfile 如何转换成镜像

    如上图,Dockerfile 中的每行命令,在构建镜像时都会关联一个 layer 。layer 是对镜像层的简单包装。这些镜像层在存储时,会得到复用,也就是说多个镜像使用到一个镜像层时,仅存储一份。这里面还有一些概念上的细节,可以暂时忽略。

    2.2 Docker 与 Registry 如何传输镜像

    镜像的元数据信息包括 size 、digest、layers 等信息。

    Docker 与 Registry 推拉镜像时,首先会传输 manifest 信息,仅当镜像层在当前环境中不存在时,才会进行网络传输,否则直接复用本地镜像层。

    2.3 manifest 的文件结构

    直接查看镜像的 manifest

    • 查看 manifest
    docker manifest inspect jenkins/jnlp-slave
    
    {
        "schemaVersion": 2,
        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
        "config": {
            "mediaType": "application/vnd.docker.container.image.v1+json",
            "size": 12327,
            "digest": "sha256:9b5976169d3504ea796a4af75f8648db9a500e8b9351ee19276031108c59f429"
        },
        "layers": [
            {
                "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                "size": 50382041,
                "digest": "sha256:f15005b0235fa8bd31cc6988c4f2758016fe412d696e81aecf73e52be079f19e"
            },
            {
                "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                "size": 7812166,
                "digest": "sha256:41ebfd3d2fd0de99b1c63aa36a507bf5555481d06e571d84ed84440d30671494"
            },
            ...
      ]
    }
    
    • 查看多架构 manifest

    通过 manifest.list 这个 mediaType ,可以将多个镜像整合为一个。在不同的 architecture 和 os 条件下,Docker 会自动拉取适配当前环境的镜像。

    docker manifest inspect maven
    
    {
       "schemaVersion": 2,
       "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
       "manifests": [
          {
             "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
             "size": 1579,
             "digest": "sha256:3c5d1c8795c96b775723cf912b297850feb1fc8f4b98ec2eda4303f3a6277310",
             "platform": {
                "architecture": "amd64",
                "os": "linux"
             }
          }
       ]
    }
    

    3. 常见的几种多架构镜像的组织方式

    不同的 OS 和 CPU 能运行的镜像会有差别。OS 层面,主要可以分为 Windows 和 类 Linux 的镜像。CPU 层面,主要有 amd64 、 arm 、ppc64le 、 s390x 等架构的镜像。amd64 也就是 x86-64 ,通常作为默认的架构,不用特意指明 amd64 和 linux 。

    3.1 通过 namespace 区分不同架构

    格式 namespaces-{ARCH}-{OS}/image:tag

    • amd64
    shaowenchen-amd64/coredns:latest
    
    shaowenchen-arm/coredns:latest
    

    3.2 通过 image name 区分不同架构

    格式 namespaces/image-{ARCH}-{OS}:tag

    • amd64
    shaowenchen/coredns-amd64:latest
    
    • arm
    shaowenchen/coredns-arm:latest
    

    3.3 通过 tag name 区分不同架构

    格式 namespaces/image:tag-{ARCH}-{OS}

    • amd64
    shaowenchen/coredns:latest-amd64
    
    • arm
    shaowenchen/coredns:latest-arm
    

    4. manifest list 管理多架构镜像

    manifest list 是一个镜像清单列表,用来存放不同架构的镜像信息。简单点说,就是新建了一个拉取镜像的入口,关联了不同架构的镜像,没有任何新的镜像层生成。

    • 首先推送镜像
    docker push shaowenchen/coredns:coredns-amd64
    docker push shaowenchen/coredns:coredns-arm
    docker push shaowenchen/coredns:coredns-arm64
    

    否则,下面的步骤会报错 no such manifest: docker.io/shaowenchen/coredns:coredns-amd64

    • 创建多架构的 manifest list
    docker manifest create shaowenchen/coredns:latest \
        shaowenchen/coredns:coredns-amd64 \
        shaowenchen/coredns:coredns-arm \
        shaowenchen/coredns:coredns-arm64 --amend
    
    Created manifest list docker.io/shaowenchen/coredns:latest
    
    • [可选]更新相关架构的信息
    docker manifest annotate shaowenchen/coredns:latest shaowenchen/coredns:coredns-arm --arch arm
    
    • 查看 manifest list
    docker manifest inspect shaowenchen/coredns:latest
    
    {
       "schemaVersion": 2,
       "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
       "manifests": [
          {
             "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
             "size": 739,
             "digest": "sha256:242d440e3192ffbcecd40e9536891f4d9be46a650363f3a004497c2070f96f5a",
             "platform": {
                "architecture": "amd64",
                "os": "linux"
             }
          },
          {
             "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
             "size": 739,
             "digest": "sha256:e9e08bce9d74a48723518a476f67ada25d00ed69dd3719c3fde41b10d390b0d0",
             "platform": {
                "architecture": "arm",
                "os": "linux"
             }
          },
          {
             "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
             "size": 739,
             "digest": "sha256:969a21696cff473cb4d36854b15118885fd414394d09444cfd111213fabcd982",
             "platform": {
                "architecture": "amd64",
                "os": "linux"
             }
          }
       ]
    }
    
    
    • 推送到 DockerHub
    docker manifest push shaowenchen/coredns:latest
    
    sha256:bcdaff4935b922edd8f415323e04d3a77374f5ddabe0a59d649fd0b6be4ad5ef
    
    • 在 DockerHub 页面查看推送的镜像

    在各种架构下,都可以使用同一条命令,拉取镜像:

    docker pull shaowenchen/coredns:latest
    

    这给部署带来了极大的便利,不需要给镜像拼接 architecture 和 os 信息。不同架构下,可以使用同一套部署程序。

    5. 参考