摘要:使用Multi-Architecture鏡像,可以讓docker根據系統架構去拉取對應的鏡像,服務的部署腳本等可以在不同架構的系統間使用相同的配置,減化服務配置,提高了服務在不同系統架構間的一致性。
背景
由於Kubernetes集群支持amd64和arm64架構的系統,容器部署時兩種類型的節點都可能被集群調度到;所以容器在打包推送到鏡像倉庫時需要考慮支持多架構,防止調度到不支持的架構節點導致運行失敗。
簡介
- Docker register: v2.3.0開始支持Multi-Architecture鏡像
- Docker CLI
- v1.11開始支持Multi-Architecture鏡像拉取
- v18.03開始支持Multi-Architecture鏡像制作
參考資料:
- Manifest標准:https://docs.docker.com/registry/spec/manifest-v2-1/
- Manifest命令:https://docs.docker.com/engine/reference/commandline/manifest/
- Registry:https://github.com/docker/distribution/releases/tag/v2.3.0
制作說明
雖然Multi-Architecture標准很早就有,但是官方的Docker CLI直到v18.03版本才開始支持Multi-Architecture鏡像的制作;或者可以考慮使用第三方工具,參考:構建多CPU架構支持的Docker鏡像
后續Multi-Architecture鏡像的制作使用Docker v18.09版本進行說明。
設置Docker
Docker使用manifest命令來設置MANIFEST_LIST從而支持Multi-Architecture。到Docker v18.09版本為止,manifest命令還是實驗性的,所以要配置Docker使能實驗性功能。
Docker daemon
修改配置文件/etc/docker/daemon.json,添加配置"experimental": true:
$ sudo cat /etc/docker/daemon.json [sudo] password for zhangsan: { "data-root": "/home/common/docker", "experimental": true, <- 使能docker daemon實驗性功能 "storage-driver": "overlay2", "log-driver": "json-file", "log-opts": { "max-file": "10", "max-size": "100m" }, "insecure-registries": [ "docker-hub.***.com" ] }
Docker Cli
修改當前用戶home目錄的配置文件~/.docker/config.json,添加配置"experimental": "enabled":
$ cat ~/.docker/config.json { "experimental": "enabled", <- 使能docker cli實驗性功能 "proxies": { "default": { "httpProxy": "http://127.0.0.1:3128", "httpsProxy": "http://127.0.0.1:3128", "ftpProxy": "http://127.0.0.1:3128" } } }
驗證配置
重啟docker服務,手工運行docker manifest,出現如下信息說明配置成功:
$ docker manifest Usage: docker manifest COMMAND Manage Docker image manifests and manifest lists Commands: annotate Add additional information to a local image manifest create Create a local manifest list for annotating and pushing to a registry inspect Display an image manifest, or manifest list push Push a manifest list to a repository Run 'docker manifest COMMAND --help' for more information on a command.
鏡像打包
示例程序stop是一個go程序,啟動后暫停不做任何操作,編譯到amd64和arm64平台,在amd64平台分別運行如下:
$ ll -hR .: total 8.0K drwxrwxr-x 2 zhangsan zhangsan 4.0K Jun 3 17:21 amd64 drwxrwxr-x 2 zhangsan zhangsan 4.0K Jun 3 17:21 arm64 ./amd64: total 240K -rw-rw-r-- 1 zhangsan zhangsan 51 Jun 3 17:21 Dockerfile -rwxrwxr-x 1 zhangsan zhangsan 235K Jul 19 2014 stop ./arm64: total 656K -rw-rw-r-- 1 zhangsan zhangsan 51 Jun 3 17:21 Dockerfile -rwxr-xr-x 1 zhangsan zhangsan 651K May 22 14:38 stop $ amd64/stop ^C% $ arm64/stop zsh: exec format error: arm64/stop
使用相同的Dockerfile:
$ cat Dockerfile FROM scratch COPY stop /stop ENTRYPOINT ["/stop"]
amd64版本
$ cd amd64 $ ls Dockerfile stop # 使用tag標注平台信息。 $ docker build -t docker-hub.***.com/zhangsan/stop:1.0-amd64 . Sending build context to Docker daemon 242.7kB Step 1/3 : FROM scratch ---> Step 2/3 : COPY stop /stop ---> ffb0d366bb8c Step 3/3 : ENTRYPOINT ["/stop"] ---> Running in 715d1fbcf450 Removing intermediate container 715d1fbcf450 ---> 0584fe60ca3d Successfully built 0584fe60ca3d Successfully tagged docker-hub.***.com/zhangsan/stop:1.0-amd64 $ docker images | grep stop REPOSITORY TAG IMAGE ID CREATED SIZE docker-hub.***.com/zhangsan/stop 1.0-amd64 0584fe60ca3d 3 seconds ago 240kB $ docker push docker-hub.***.com/zhangsan/stop:1.0-amd64 The push refers to repository [docker-hub.***.com/zhangsan/stop] 9e352dcc98ab: Pushed 1.0-amd64: digest: sha256:e5b6263b7e45840f139f1bf40b774294712c95df1b43d41598b736f07110341f size: 526 # 可以用manifest的子命令inspect查看鏡像的manifest信息,由於是私有倉庫,需要使用--insecure參數。 $ docker manifest inspect -v --insecure docker-hub.***.com/zhangsan/stop:1.0-amd64 { "Ref": "docker-hub.***.com/zhangsan/stop:1.0-amd64", "Descriptor": { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "digest": "sha256:e5b6263b7e45840f139f1bf40b774294712c95df1b43d41598b736f07110341f", "size": 526, "platform": { "architecture": "amd64", "os": "linux" } }, "SchemaV2Manifest": { "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "config": { "mediaType": "application/vnd.docker.container.image.v1+json", "size": 1489, "digest": "sha256:0584fe60ca3dbff4c746d376855e89b72b022a4198373b3c8d4c41b97b8b4faf" }, "layers": [ { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 71322, "digest": "sha256:7797d3b3ba41f7abc6a914250f793cf2d69a3e7c0bcc787a596eab4836554552" } ] } }
arm64版本
$ cd arm64 $ ls Dockerfile stop $ docker build -t docker-hub.***.com/zhangsan/stop:1.0-arm64 . Sending build context to Docker daemon 669.2kB Step 1/3 : FROM scratch ---> Step 2/3 : COPY stop /stop ---> e02dd9cc9ffa Step 3/3 : ENTRYPOINT ["/stop"] ---> Running in 9b574680691a Removing intermediate container 9b574680691a ---> 1fc97e49b088 Successfully built 1fc97e49b088 Successfully tagged docker-hub.***.com/zhangsan/stop:1.0-arm64 $ docker images | grep stop docker-hub.***.com/zhangsan/stop 1.0-arm64 1fc97e49b088 8 seconds ago 666kB docker-hub.***.com/zhangsan/stop 1.0-amd64 0584fe60ca3d 3 minutes ago 240kB $ docker push docker-hub.***.com/zhangsan/stop:1.0-arm64 The push refers to repository [docker-hub.***.com/zhangsan/stop] a0c07ccfc4ae: Pushed 1.0-arm64: digest: sha256:089798dc96fcc3d2bf4da3ec4243adcc2507d2ae0c5ba77c5582af626702b3d6 size: 527 # 由於打包鏡像的機器是amd64架構,所以arm64的應用鏡像中architecture為amd64,后面可以修改,或者直接在arm64機器上打包。 $ docker manifest inspect -v --insecure docker-hub.***.com/zhangsan/stop:1.0-arm64 { "Ref": "docker-hub.***.com/zhangsan/stop:1.0-arm64", "Descriptor": { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "digest": "sha256:089798dc96fcc3d2bf4da3ec4243adcc2507d2ae0c5ba77c5582af626702b3d6", "size": 527, "platform": { "architecture": "amd64", "os": "linux" } }, "SchemaV2Manifest": { "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "config": { "mediaType": "application/vnd.docker.container.image.v1+json", "size": 1488, "digest": "sha256:1fc97e49b0883f59e1e894404785ea1867b9e557d55bdac92f2da09c92b659e7" }, "layers": [ { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 318698, "digest": "sha256:4397808817371da0348eb097ca181996165a9836d629aa1fb97b0d3824ffe2e2" } ] } }
驗證鏡像
$ docker images | grep stop docker-hub.***.com/zhangsan/stop 1.0-arm64 1fc97e49b088 21 hours ago 666kB docker-hub.***.com/zhangsan/stop 1.0-amd64 0584fe60ca3d 21 hours ago 240kB $ docker run docker-hub.***.com/zhangsan/stop:1.0-amd64 ^C% $ docker run docker-hub.***.com/zhangsan/stop:1.0-arm64 standard_init_linux.go:207: exec user process caused "exec format error"
創建MANIFEST_LIST
創建一個MANIFEST_LIST引用之前兩個不同平台的鏡像。
$ docker manifest inspect -v --insecure docker-hub.***.com/zhangsan/stop:1.0 no such manifest: docker-hub.***.com/zhangsan/stop:1.0 $ docker manifest create --insecure docker-hub.***.com/zhangsan/stop:1.0 docker-hub.***.com/zhangsan/stop:1.0-amd64 docker-hub.***.com/zhangsan/stop:1.0-arm64 Created manifest list docker-hub.***.com/zhangsan/stop:1.0 $ docker manifest inspect -v --insecure docker-hub.***.com/zhangsan/stop:1.0 [ { "Ref": "docker-hub.***.com/zhangsan/stop:1.0-amd64", "Descriptor": { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "digest": "sha256:e5b6263b7e45840f139f1bf40b774294712c95df1b43d41598b736f07110341f", "size": 526, "platform": { "architecture": "amd64", "os": "linux" } }, "SchemaV2Manifest": { "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "config": { "mediaType": "application/vnd.docker.container.image.v1+json", "size": 1489, "digest": "sha256:0584fe60ca3dbff4c746d376855e89b72b022a4198373b3c8d4c41b97b8b4faf" }, "layers": [ { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 71322, "digest": "sha256:7797d3b3ba41f7abc6a914250f793cf2d69a3e7c0bcc787a596eab4836554552" } ] } }, { "Ref": "docker-hub.***.com/zhangsan/stop:1.0-arm64", "Descriptor": { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "digest": "sha256:089798dc96fcc3d2bf4da3ec4243adcc2507d2ae0c5ba77c5582af626702b3d6", "size": 527, "platform": { "architecture": "amd64", "os": "linux" } }, "SchemaV2Manifest": { "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "config": { "mediaType": "application/vnd.docker.container.image.v1+json", "size": 1488, "digest": "sha256:1fc97e49b0883f59e1e894404785ea1867b9e557d55bdac92f2da09c92b659e7" }, "layers": [ { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 318698, "digest": "sha256:4397808817371da0348eb097ca181996165a9836d629aa1fb97b0d3824ffe2e2" } ] } } ]
修改MANIFEST_LIST
修改剛創建的MANIFEST_LIST,使鏡像和架構對應。
$ docker manifest annotate docker-hub.***.com/zhangsan/stop:1.0 docker-hub.***.com/zhangsan/stop:1.0-arm64 --arch arm64 [ { "Ref": "docker-hub.***.com/zhangsan/stop:1.0-amd64", "Descriptor": { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "digest": "sha256:e5b6263b7e45840f139f1bf40b774294712c95df1b43d41598b736f07110341f", "size": 526, "platform": { "architecture": "amd64", "os": "linux" } }, "SchemaV2Manifest": { "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "config": { "mediaType": "application/vnd.docker.container.image.v1+json", "size": 1489, "digest": "sha256:0584fe60ca3dbff4c746d376855e89b72b022a4198373b3c8d4c41b97b8b4faf" }, "layers": [ { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 71322, "digest": "sha256:7797d3b3ba41f7abc6a914250f793cf2d69a3e7c0bcc787a596eab4836554552" } ] } }, { "Ref": "docker-hub.***.com/zhangsan/stop:1.0-arm64", "Descriptor": { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "digest": "sha256:089798dc96fcc3d2bf4da3ec4243adcc2507d2ae0c5ba77c5582af626702b3d6", "size": 527, "platform": { "architecture": "arm64", "os": "linux" } }, "SchemaV2Manifest": { "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "config": { "mediaType": "application/vnd.docker.container.image.v1+json", "size": 1488, "digest": "sha256:1fc97e49b0883f59e1e894404785ea1867b9e557d55bdac92f2da09c92b659e7" }, "layers": [ { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 318698, "digest": "sha256:4397808817371da0348eb097ca181996165a9836d629aa1fb97b0d3824ffe2e2" } ] } } ]
推送MANIFEST_LIST到鏡像倉庫
創建的MANIFEST_LIST會保存在本地目錄~/.docker/manifests,在push時可以使用-p(--purge)參數刪除本地數據:
$ ll -R ~/.docker/manifests /home/zhangsan/.docker/manifests: total 4 drwxr-xr-x 2 zhangsan zhangsan 4096 Jun 3 17:57 docker-hub.***.com_zhangsan_stop-1.0 /home/zhangsan/.docker/manifests/docker-hub.***.com_zhangsan_stop-1.0: total 8 -rw-r--r-- 1 zhangsan zhangsan 733 Jun 3 17:57 docker-hub.***.com_zhangsan_stop-1.0-amd64 -rw-r--r-- 1 zhangsan zhangsan 734 Jun 3 18:01 docker-hub.***.com_zhangsan_stop-1.0-arm64 $ sudo docker manifest push -p --insecure docker-hub.***.com/zhangsan/stop:1.0 [sudo] password for zhangsan: sha256:401767ef0864a65578bef86e3baed2e1e0be905d08d88b57cdeb299850400ece
驗證
$ docker images | grep stop docker-hub.***.com/zhangsan/stop 1.0-arm64 1fc97e49b088 16 hours ago 666kB docker-hub.***.com/zhangsan/stop 1.0-amd64 0584fe60ca3d 16 hours ago 240kB # 在amd64架構的系統下拉取不帶架構信息的鏡像 $ uname -a Linux SZX1000514415 4.4.0-87-generic #110-Ubuntu SMP Tue Jul 18 12:55:35 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux $ docker pull docker-hub.***.com/zhangsan/stop:1.0 1.0: Pulling from zhangsan/stop Digest: sha256:401767ef0864a65578bef86e3baed2e1e0be905d08d88b57cdeb299850400ece Status: Downloaded newer image for docker-hub.***.com/zhangsan/stop:1.0 $ docker images | grep stop docker-hub.***.com/zhangsan/stop 1.0-arm64 1fc97e49b088 16 hours ago 666kB docker-hub.***.com/zhangsan/stop 1.0 0584fe60ca3d 16 hours ago 240kB docker-hub.***.com/zhangsan/stop 1.0-amd64 0584fe60ca3d 16 hours ago 240kB # 可正常運行 $ docker run docker-hub.***.com/zhangsan/stop:1.0 ^C% # 在arm64架構的系統下拉取不帶架構信息的鏡像 [root@kwephicprc09532 ~]# uname -a Linux kwephicprc09532 4.1.44-06.160.vhulk1711.1.1.aarch64 #1 SMP Tue Oct 16 18:45:06 UTC 2018 aarch64 aarch64 aarch64 GNU/Linux [root@kwephicprc09532 ~]# docker images | grep stop [root@kwephicprc09532 ~]# docker pull docker-hub.***.com/zhangsan/stop:1.0 1.0: Pulling from zhangsan/stop 439780881737: Pull complete Digest: sha256:401767ef0864a65578bef86e3baed2e1e0be905d08d88b57cdeb299850400ece Status: Downloaded newer image for docker-hub.***.com/zhangsan/stop:1.0 [root@kwephicprc09532 ~]# docker images | grep stop docker-hub.***.com/zhangsan/stop 1.0 1fc97e49b088 16 hours ago 666.5 kB # 可正常運行 [root@kwephicprc09532 ~]# docker run docker-hub.***.com/zhangsan/stop:1.0 ^CShutting down, got signal: Interrupt
升級MANIFEST_LIST
后期升級MANIFEST_LIST方法與創建類似,如:docker-hub.***.com/zhangsan/stop:1.0-amd64鏡像升級或docker-hub.***.com/zhangsan/stop:1.0這個MANIFEST_LIST要關聯其它鏡像時,都需要升級MANIFEST_LIST。需要注意幾點:
- manifest create時使用參數-a(--amend)
- 升級后沒有關聯到期望的鏡像可以先手工刪除本地保存的manifest再嘗試
使用Multi-Architecture鏡像的好處
使用Multi-Architecture鏡像,可以讓docker根據系統架構去拉取對應的鏡像,服務的部署腳本等可以在不同架構的系統間使用相同的配置,減化服務配置,提高了服務在不同系統架構間的一致性。
本文分享自華為雲社區《叮!快收好這份Multi-Architecture鏡像制作指南》,原文作者:Thirteenmans 。