构建多CPU架构支持的Docker镜像

原创 2018年01月23日 13:01:24

作者简介:
胡晓亮目前就职于IBM Platform Computing 系统科技部云计算部门,担任云计算开发部工程师。自2013年8月开始参与OpenStack,然后又转战Spark,目前工作在K8S相关领域。
责编:钱曙光(qianshg@csdn.net)
声明:本篇为原创内容,CSDN独家发布,禁止未经授权的任何形式转载。

Docker简介

由于基于Hypervisor虚拟化技术仍然存在一些性能和资源使用效率方面的问题,近3年来容器技术席卷了整个互联网应用乃至IT界的技术革新,成为一种被大家广泛认可的服务器资源共享技术。它从根本上变革了应用程序的开发和发布方式,经过爆炸式的成长,容积技术的翘楚Docker实际上已经成为了容器格式和运行时的标准,大量流行的开源应用程序都宣布支持容器化,并且一些企业级的应用程序也开始往容器上迁移, Docker容器世界欣欣向荣。

Multi architecture Docker镜像

Multi architecture Docker镜像的支持让Docker向自己宣称的口号 “Build, Ship, and Run Any App, Anywhere” 更近了一大步。 那什么是Multi architecture Docker镜像呢?我们可以通过一个例子来说明。我们知道JAVA语言编写的应用程序是 “Write once, run anywhere”,它体现了JAVA跨平台的特性,但是JAVA程序的运行环境JVM(JAVA 虚拟机)却不是跨平台的,它是JAVA应用程序和OS平台之间的一个桥梁,不同的类型的OS和CPU架构机器需要安装相应的JVM才能运行JAVA程序。而 Docker image也是一样的,它也是依赖运行平台的,我们不能把一个httpd的ppc64le/linux架构的Docker镜像运行在amd64/linux 架构的环境中,我们也不能把一个Windows镜像运行在Linux平台上,否则你会遇到 “exec format error”。早期Docker镜像存储的设计没有充分考虑到镜像Multi architecture的支持,而是简单的使用镜像存储库的前缀来区分相同应用的不同平台,并建议开发者将不同平台的镜像应该push到相对应的Docker hub的镜像仓库中,而这种糟糕的设计依然保留在最新的Docker设计文档中如下:

例如运行busybox在多个平台上,按照Docker社区的方法如下:

x86-64:     docker run -it --rm busybox or docker run -it --rm amd64/busybox
ppc64le:   docker run -it --rm ppc64le/busybox 
s390x:      docker run -it --rm s390x/busybox 

基于Docker社区的做法,对于我们自己的应用程序Docker镜像多平台支持,我们还可以采取类似方法:

1. 基于tag

x86-64:    docker run -it --rm myapp:x86-64
ppc64le:  docker run -it --rm myapp:ppc64le
s390x:      docker run -it --rm myapp:s390x

2. 基于image 名称的后缀

x86-64:    docker run -it --rm myapp_x86-64
ppc64le:  docker run -it --rm myapp_ppc64le
s390x:      docker run -it --rm myapp_s390x

不管是基于镜像存储库的前缀,或者是基于tag或image名称后缀来区分不同的运行平台来pull相应的Docker镜像都不是好的设计,而好的设计是应该用户只要执行docker pull myapp就行了而不用关心容器的运行平台,Docker engine根据运行环境来pull相关的镜像,真正的做到 “Run Any App, Anywhere”。Docker社区已经注意到了这个问题,通过重新定义 v2.2 Image specification format(PR #1068)并在 Implement schema2 manifest formats(PR #1281)实现了Multi architecture Docker镜像功能。从Docker registry v2.3和Docker 1.10 开始,Docker hub就可以pull multi architecture Docker镜像了.

例如有2个Linux host,一个host(kvm-014009)arch是x86_64,另一个host(power807l )arch是ppc64le,我们分别在两个host 上运行 busybox 容器并且打印容器中基础镜像的arch, 看看是不是pull相同的镜像但是可以打印出与平台相关的输出。

x86_64 host :

[root@kvm-014009 ~]# docker run -it --rm busybox arch

Unable to find image 'busybox:latest' locally

latest: Pulling from library/busybox

67a0688b88df: Pull complete 

Digest: sha256:ac2fc418f3348815e68e266a5aa1b60bc522581c96964912560a0baacc4f5c06

Status: Downloaded newer image for busybox:latest

x86_64
ppc64le host:

[root@power807l ~]# docker run -it --rm busybox arch

Unable to find image 'busybox:latest' locally

latest: Pulling from library/busybox

219992aaea40: Pull complete 

Digest: sha256:ac2fc418f3348815e68e266a5aa1b60bc522581c96964912560a0baacc4f5c06

Status: Downloaded newer image for busybox:latest

ppc64le

我们run了相同的命令 “docker run -it –rm busybox arch” 在不同CPU architecture的host都得到了正确的运行结果,这是用户体验的一个极大的提升,用户根本不用关心 image的CPU arch 和OS的类型了。除了busybox镜像,httpd,nginx, tomcat和etcd等主流开源应用都有了Multi architecture Docker镜像支持,大家快快试试吧。

原理分析

如上文我们提到的自从Docker registry v2.3和Docker 1.10开始,Docker通过支持新的image Media 类型 manifest list 实现了Multi architecture Docker镜像功能:

1. 一个image manifest list 包含指向已经存在镜像的manifest对象列表

这里写图片描述

2. 一个image manifest list包含已经存在镜像的manifest对象的平台特性(CPU arch和OS类型)特征

这里写图片描述

根据manifest list对象定义,我们可以通过下面的流程了解Docker是如何支持Multi architecture Docker镜像的:

这里写图片描述

动手实验

制作一个multi architecture Docker镜像最重要的是定义image的manifest list,虽然image manifest list的标准已经确定也实现了,可是客户端如何push这个image的manifest list到Docker registry依然在Docker社区争论不休,有兴趣的同学可以看一下ticket Add manifest command了解一下细节。虽然还没有Docker official的客户端工具支持,但是广大的开源爱好者们还是自己根据 v2.2 Image specification format中的定义实现一些小工具可以帮助我们制作multi architecture Docker镜像。首先给大家介绍两个小工具,他们都可以push Docker image的manifest list到Docker registry中。

1. Enhanced Docker CLI

这是加强版的Docker CLI,他的code base 是基于社区的Docker CLI,并且marge了 Docker官方的Add manifest command这个pull request,它很好的集成了现有的Docker CLI, 并且增加了docker manifest的sub command 支持。

2. Manifest-tool

这是一个独立的小工具,它也实现了v2.2 Image specification format,并且支持查看,创建和push manifests list 对象到Docker registry,并且更加方便易用,因为它可以使用yaml文件定义image manifest list对象。

实验机器

Host CPU arch OS Docker version
kvm-014009 x86_64 Linux rhel 7.3 Server: 17.03.2-ce
power807l ppc64le Linux rhel 7.4 Server: 17.05.0-ce

先决条件

  1. 从source code编译出两个小工具的可执行文件 docker 和 manifest-tool,我们可以参考两个小工具github中提供的步骤,或者直接使用我编译好的x86_64平台的可执行文件
  2. 有一个可用的Docker hub 账号用来push镜像,假设这个账户是huxl,并且已经docker login成功

实验目的

假设有一个叫myapp是跨平台的应用,支持x86_64和ppc64le CPU arch 和Linux, 为了简单,在假设myapp就是一个文本文件,里面只有一句话:I am x86_64 application (for x86_64) 或者 I am ppc64le application (for ppc64le), Dockerfile也很简单如下,用户可以使用一致的命令run这个myapp应用在不同的平台上。

FROM alpine

WORKDIR /opt

COPY myapp .

实验步骤:

  • 使用Enhanced Docker CLI构建multi architecture Docker镜像

a. 构建myapp的x86_64镜像,并且push到Docker hub上

            [root@kvm-014314 muti-arch]# docker build -t huxl/myapp-x86_64:v1 .

            Sending build context to Docker daemon 3.072 kB

            Step 1/3 : FROM alpine

            latest: Pulling from library/alpine

            ff3a5c916c92: Pull complete 

            Digest: sha256:7df6db5aa61ae9480f52f0b3a06a140ab98d427f86d8d5de0bedab9b8df6b1c0

            Status: Downloaded newer image for alpine:latest

             ---> 3fd9065eaf02

            Step 2/3 : WORKDIR /opt

             ---> 204fec0aa91b

            Removing intermediate container 49747c6124e8

            Step 3/3 : COPY myapp .

             ---> d89721162bd0

            Removing intermediate container b63c71aebd49

            Successfully built d89721162bd0

            [root@kvm-014314 muti-arch]# docker push huxl/myapp-x86_64:v1 

            The push refers to a repository [docker.io/huxl/myapp-x86_64]

            723ba289c543: Pushed 

            7b2f1ea92884: Pushed 

            cd7100a72410: Mounted from library/alpine 

            v1: digest: sha256:ffac5d9918844da37c707e5b8690ce6f75563611bb6326daa5620fcb853bb590 size: 941

b. 构建myapp的ppc64le镜像,并且push到Docker hub上

            [root@power807l muti-arch]# docker build -t huxl/myapp-ppc64le:v1 .

            Sending build context to Docker daemon  3.072kB

            Step 1/3 : FROM alpine

            latest: Pulling from library/alpine

            0da653ea85b5: Pull complete 

            9fd90b777cc3: Pull complete 

            Digest: sha256:7df6db5aa61ae9480f52f0b3a06a140ab98d427f86d8d5de0bedab9b8df6b1c0

            Status: Downloaded newer image for alpine:latest

             ---> 5675e84fb0f7

            Step 2/3 : WORKDIR /opt

             ---> fe7e5331969e

            Removing intermediate container 91c27a07b969

            Step 3/3 : COPY myapp .

             ---> e2e2fd0b2abb

            Removing intermediate container c24a46b56e1e

            Successfully built e2e2fd0b2abb

            Successfully tagged huxl/myapp-ppc64le:v1

            [root@power807l muti-arch]# docker push huxl/myapp-ppc64le:v1 

            The push refers to a repository [docker.io/huxl/myapp-ppc64le]

            4abe83ad0ae2: Pushed 

            30b0e74edb8c: Pushed 

            d8f649dc98c5: Pushed 

            22963f19a0a3: Mounted from library/alpine 

            v1: digest: sha256:102f93c9ae146cbf2d5247db82e4429f5964978cfda1df72a9c7e444a4840437 size: 1148

            [root@power807l muti-arch]# 

c. 创建指向myappp的x86_64和ppc64le的镜像的manifests list对象并将它push到docker hub

            [root@kvm-014314 build]# pwd

            /root/cli/build

            [root@kvm-014314 build]# ./docker manifest create huxl/myapp:v1 huxl/myapp-x86_64:v1 huxl/myapp-ppc64le:v1

            Created manifest list docker.io/huxl/myapp:v1

            [root@kvm-014314 build]# ./docker manifest annotate huxl/myapp:v1 huxl/myapp-x86_64:v1 --os linux --arch amd64

            [root@kvm-014314 build]# ./docker manifest annotate huxl/myapp:v1 huxl/myapp-ppc64le:v1 --os linux --arch ppc64le

            [root@kvm-014314 build]# ./docker manifest push huxl/myapp:v1

            Pushed ref docker.io/huxl/myapp@sha256:102f93c9ae146cbf2d5247db82e4429f5964978cfda1df72a9c7e444a4840437 with digest: sha256:102f93c9ae146cbf2d5247db82e4429f5964978cfda1df72a9c7e444a4840437

            Pushed ref docker.io/huxl/myapp@sha256:ffac5d9918844da37c707e5b8690ce6f75563611bb6326daa5620fcb853bb590 with digest: sha256:ffac5d9918844da37c707e5b8690ce6f75563611bb6326daa5620fcb853bb590

            sha256:b1b4c2219f5f514fe5a752d158c76b3aa010fab2b1e1dbfa808755ff0848abfa

            [root@kvm-014314 build]#

d. 验证run myapp 镜像在两个host上,我们得到了不同的结果

            [root@kvm-014314 build]# docker run -it  --rm huxl/myapp:v1 cat /opt/myapp

            Unable to find image 'huxl/myapp:v1' locally

            v1: Pulling from huxl/myapp

            Digest: sha256:b1b4c2219f5f514fe5a752d158c76b3aa010fab2b1e1dbfa808755ff0848abfa

            Status: Downloaded newer image for huxl/myapp:v1

            I am x86_64 application

            [root@kvm-014314 build]# 


            [root@power807l muti-arch]# docker run -it  --rm huxl/myapp:v1 cat /opt/myapp

            Unable to find image 'huxl/myapp:v1' locally

            v1: Pulling from huxl/myapp

            Digest: sha256:b1b4c2219f5f514fe5a752d158c76b3aa010fab2b1e1dbfa808755ff0848abfa

            Status: Downloaded newer image for huxl/myapp:v1

            I am pcc64le application

            [root@power807l muti-arch]#

e. 从Docker hub上删除huxl/myapp:v1,后面我们使用Manifest-tool重新创建它
f. 删除本地huxl/myapp:v1镜像,为了不影响后续的实验

            [root@kvm-014314 manifest-tool]# docker rmi -f huxl/myapp:v1

            Untagged: huxl/myapp:v1

            Untagged: huxl/myapp@sha256:b1b4c2219f5f514fe5a752d158c76b3aa010fab2b1e1dbfa808755ff0848abfa

            [root@kvm-014314 manifest-tool]# 


            [root@power807l ~]# docker rmi -f huxl/myapp:v1

            Untagged: huxl/myapp:v1

            Untagged: huxl/myapp@sha256:b1b4c2219f5f514fe5a752d158c76b3aa010fab2b1e1dbfa808755ff0848abfa

            [root@power807l ~]# 
  • 使用Manifest-tool 构建multi architecture docke的镜像

a. 创建一个yaml文件用来表述支持multi architecture的镜像myapp:v1

            [root@kvm-014314 manifest-tool]# pwd

            /root/manifest-tool

            [root@kvm-014314 manifest-tool]# cat myapp.yaml 

            image: huxl/myapp:v1

            manifests:

              -

                image: huxl/myapp-ppc64le:v1

                platform:

                  architecture: ppc64le

                  os: linux

              -

                image: huxl/myapp-x86_64:v1

                platform:

                  architecture: amd64

                  os: linux

            [root@kvm-014314 manifest-tool]# 

b. push myapp.yaml到docker hub

            [root@kvm-014314 manifest-tool]# pwd

            /root/manifest-tool

            [root@kvm-014314 manifest-tool]# ./manifest-tool push from-spec myapp.yaml  

            Digest: sha256:dcf22c78689691df6d68117d55c4a4ce6b745caa38b1f31e882fc358a742c3c5 744

            [root@kvm-014314 manifest-tool]#

c. 验证run myapp 镜像在两个host上,我们都得到了正确的结果

            [root@kvm-014314 manifest-tool]# docker run -it  --rm huxl/myapp:v1 cat /opt/myapp

            Unable to find image 'huxl/myapp:v1' locally

            v1: Pulling from huxl/myapp

            Digest: sha256:dcf22c78689691df6d68117d55c4a4ce6b745caa38b1f31e882fc358a742c3c5

            Status: Downloaded newer image for huxl/myapp:v1

            I am x86_64 application

            [root@kvm-014314 manifest-tool]# 


            [root@power807l muti-arch]# docker run -it  --rm huxl/myapp:v1 cat /opt/myapp

            Unable to find image 'huxl/myapp:v1' locally

            v1: Pulling from huxl/myapp

            Digest: sha256:dcf22c78689691df6d68117d55c4a4ce6b745caa38b1f31e882fc358a742c3c5

            Status: Downloaded newer image for huxl/myapp:v1

            I am pcc64le application

            [root@power807l muti-arch]#
Note:我们可以使用命令docker manifest inspect huxl/myapp:v1 或者 manifest-tool inspect huxl/mycool-app:v1看到这个multi architecture Docker镜像的manifest list,这里就不在赘述了。

总结

  1. Push multi architecture Docker镜像到Docker registry并不会push image的layers,它只会push一个引用,这个引用指向了已经存在的多个Docker镜像;
  2. 只有multi architecture Docker镜像的创建者才需要知道这个引用背后指向具体的Docker镜像,而对最终的用户是透明的,最终用户只需要知道镜像的名字和tag就足够了;
  3. 有了multi architecture Docker镜像支持,我们再也不用在脚本里面判断OS的类型和CPU的arch而去pull相应的镜像,提高CICD代码的简洁和优雅;
  4. Image manifest list是极好的兼容性设计,它不但支持multi architecture Docker镜像,而且不会影响已经在的simple architecture Docker镜像的使用方式, 用户不用做二选一的艰难的决定。

这里写图片描述

版权声明:本文为博主原创文章,未经博主允许不得转载。

C# WinForm控件之Dock先后顺序调整

C# WinForm控件之Dock顺序调整 最近被.net winform中的控件布局搞困惑了,由于控件都是使用Dock方式的,操作起来也是比较方便,如果最大化,窗口大小调整等,都可以随着窗...
  • postfxj
  • postfxj
  • 2017年04月21日 23:31
  • 1682

Docker教程:镜像构建和自动镜像构建dockerfile

http://blog.csdn.net/pipisorry/article/details/50805379 Docker透过Dockerfile来记录建立Container映象文件的每一个步...
  • pipisorry
  • pipisorry
  • 2016年03月04日 21:05
  • 11401

如何在Ubuntu Core中支持多个CPU架构 (architecture)

在今天的文章中,我们将介绍如何在我们的Ubuntu Core Snap应用中支持多个CPU架构.由于CPU架构的不同,我们的snap应用需要访问不同架构中的和架构名称相关联的lib目录或binary目...
  • UbuntuTouch
  • UbuntuTouch
  • 2016年12月21日 10:04
  • 840

构建多CPU架构支持的Docker镜像

作者简介: 胡晓亮目前就职于IBM Platform Computing 系统科技部云计算部门,担任云计算开发部工程师。自2013年8月开始参与OpenStack,然后又转战Spark,目前工作...
  • dev_csdn
  • dev_csdn
  • 2018年01月23日 13:01
  • 1433

docker构建tomcat镜像

一。docker简介       Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中, 然后发布到任何流行的 Linux 机器上    一个完整的Dock...
  • liaomin416100569
  • liaomin416100569
  • 2017年08月31日 20:24
  • 380

Docker 构建Tomcat镜像

1、首先下载好jre、tomcat server-jre-8u51-linux-x64.gz apache-tomcat-8.0.24.tar.gz 2、新建Dockerfile文件,内容如下:FRO...
  • qq362228416
  • qq362228416
  • 2015年09月19日 01:56
  • 1641

C# 界面布局之Dock,Anchor,容器控件心得

背景 近几个月都用的WPF,结果发现很多代码都是WinFrom的,一直想学下WinForm的,恰好今天要用下。就拿了别人的源码,增加些控件与功能,然后界面不太规范,所以边学边改之,第一天弄WinFo...
  • rentao315
  • rentao315
  • 2015年01月26日 11:25
  • 6649
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:构建多CPU架构支持的Docker镜像
举报原因:
原因补充:

(最多只允许输入30个字)