超详细的ARM架构适配介绍!

本文主要介绍云联壹云平台如何适配ARM,并运行在ARM CPU架构的机器上。
背景介绍
1、平台服务运行架构
云联壹云平台采用容器化,分布式的架构运行在 Kubernetes(K8s)之上。下面是平台服务运行的架构图:
超详细的ARM架构适配介绍!
文章图片

在多个节点之上,我们会构建Kubernetes的集群 ,它是一个容器管理的平台。
在Kubernetes的平台之上,后端服务都是容器化的,是以容器的方式去分布式运行。
通过K8s去做调度的管理,然后将服务自动地打散到多个节点上运行,总结两点是服务容器化,并依靠K8s来提供容器分布式运行的环境。
另外,底层的节点是有类型的,控制层面的服务运行在控制节点,平台内置了一个私有云,提供了完整的私有云功能。
若要使用私用云这个功能,则还需要一些计算节点,计算节点上会跑虚拟化相关的软件,提供私有云虚拟化的功能,总结来说就是计算节点运行私有云的虚拟机。
2、CPU架构简介
大家熟悉的服务器或者台式机都是X86架构的CPU,X86架构的CPU特点是性能高,并且软件的兼容性很好。
大家平常工作中使用的大部分是英特尔等提供的X86架构的CPU,对于英特尔和AMD大家都不陌生,这两家厂商专门生产X86架构CPU。
【超详细的ARM架构适配介绍!】另外X86 64位这种架构的CPU存在别名,例如x86_64或者amd64都代表X86架构的64位CPU。
超详细的ARM架构适配介绍!
文章图片

与X86不同的是还有另一种称为ARM的架构,这是本文的主题,那么ARM架构的CPU和X86架构的CPU相比有何不同?
它的制造成本更低,ARM架构的芯片的功耗也很低,代表性的厂商和使用者是苹果和华为。
苹果将生产的ARM芯片用到笔记本或IMAC上,ARM架构的CPU越来越普及。
国内的华为会生产基于ARM架构的服务器,64位ARM架构CPU也有别名,例如arm64、aarch64,这两种叫法表达同一个意思。
3、为什么适配ARM
因为ARM的CPU普及是大环境下的发展趋势,例如在国际上,苹果将ARM架构的CPU投入到笔记本和台式机上,在国产化方面,国内有鲲鹏和飞腾CPU,国产的基于ARM架构的服务器,现在市场上主流的是鲲鹏和飞腾。 在国产化上,使用ARM架构也是一个趋势。
另外是适配了ARM架构能够提升产品的竞争力,竞争力体现在能够支持管理基于ARM64位和X86_64架构的虚拟化混合部署。
超详细的ARM架构适配介绍!
文章图片

这种混合部署的意思是可以同时把服务运行在ARM和X86的服务器上,同时运行各自的虚拟化,可以通过我们平台统一部署和管理。
如何适配ARM64?
超详细的ARM架构适配介绍!
文章图片

1、需要解决的关键问题
第一个方面是怎样把服务运行在64位的ARM架构上?
还有一方面是因为我们内置了一个私有云,上层的私有云业务如何支持64位的ARM架构?
通过架构图可以了解到服务是容器化运行在K8s之上的,再由K8s帮我们将服务分布式地运行在各个节点上,所以第一步是要部署异构CPU架构的K8s集群,异构CPU架构的意思是K8s集群要运行在X86和ARM架构的机器上。
具体而言就是要选择一个支持ARM架构的Linux的发行版。
K8s节点上的操作系统是Linux,首先要选择支持ARM架构的Linux操作系统,操作系统同时能够安装K8s必要的软件(比如docker-ce、kubelet等)
当我们把K8s集群给部署起来之后,就要将不同架构的容器镜像统一制作出来。
统一容器镜像的意思是一个容器镜像中要包含X86和ARM架构,相当于同一个镜像名称中有两种架构的镜像。
第二个大的方面是上层私有云业务怎样支持ARM64。
主要是分为两个问题,第一个问题是要支持ARM的虚拟机镜像,同时上层的私有云业务能够标记宿主机,宿主机就是运行虚拟机的服务器。
要能够标记这种宿主机是什么架构,同时要在这个宿主机上运行ARM的虚拟化软件。
平台使用的虚拟化软件基于qemu/kvm,网络方面依赖openvswitch组件,要求这些组件也要能够在ARM架构上运行。
这就是要介绍的一些关键问题,解决好这些关键问题,不管是底层的业务还是上层的私有云业务,都能在ARM上运行。
2、Linux发行版选择
我们选择的发行版是Debian 10(开源)和统信UOS(国产系统)。
超详细的ARM架构适配介绍!
文章图片

选择这两个发行版的第一个原因是客户业务上要求在ARM64服务器上运行“统信UOS”。
要适配的话也是首先适配国产统信UOS,在适配过程中,UOS中的内核和打包工具与Debian基本一致。
适配UOS之后,发现其工作基本相同,所以又选择了Debian 10(开源)进行适配。
如此无论是对于开源用户还是其他客户,如果不选择UOS,也可以选择Debian 10的发型版运行此平台,Debian系列对ARM64位的支持很好,
Debian发行版的官方软件仓库中已经制作好了很多ARM64的包,如果要安装docker和K8s的软件包,Debian中已经做好,直接下载安装即可。
为什么不在ARM架构上面再选择CentOS7发行版?
原因在于CentOS7官方即将停止维护,所以选择了Debian系列的发行版。
3、统信UOS适配认证
对统信UOS适配过后,经过其官方测试,为我们颁发了认证证书。
超详细的ARM架构适配介绍!
文章图片

4、统一软件依赖—包管理工具
选择好发行版后?怎样统一安装这些软件?
我们能够使用不同发行版的包管理工具去安装相同的软件,例如在X86的CentOS上安装docker和K8s这些包时调用yum,在Debian上调用apt install 等同样的包名即可。
超详细的ARM架构适配介绍!
文章图片

上游的软件仓库中已经把包做好,只需直接安装,软件直接下载即可使用。
在底层软件方面,ARM和X86的管理,只要发行版是主流的,验证Debian和X86的包没有区别,已经将底层的包安装部署好。
5、部署kubernetes集群
另外一个话题是部署kubernetes集群,如何在ARM上部署K8s集群?
超详细的ARM架构适配介绍!
文章图片

首先,我们写了名称为ocboot的部署工具,它的底层原理是调用ansible实现部署ARM64+X86_64的多节点Kubernetes,这个截图的意思是通过这个工具部署过后的混布的就是异构的K8s集群的节点的资源。
从截图中可以发现,第一个节点是centos-x86-64,发行版名称是centos7,内核是3.10,K8s会通过打标签的方式标记这个节点,它是amd64。
amd64代表它是X86架构的一个节点,另外一个节点是uos-arm64,它的发行版是uos,内核是4.19.0-arm64的内核。K8s会通过打标签标记它是ARM64的一个节点,这就代表是一个同时基于X86和ARM64的节点构建的K8s集群。
使用K8s集群的好处是K8s 集群提供了不同CPU架构节点的统一管理,通过一个API能够把所有架构的节点拿到,能够基于这些节点提供容器服务的运行。
6、服务统一镜像运行
部署好K8s集群之后如何运行云联壹云的服务?
超详细的ARM架构适配介绍!
文章图片

例如K8s中有daemonset的资源,这种资源表示在每一个K8s节点上都会运行pod容器。
它要求在这个资源中写好服务容器镜像的地址,即红框中所标记的。
只要按照这样的格式写,写好之后创建到k8s集群中,K8s就会将提供的镜像以容器化的方式运行到各个节点上。
从图中可以了解到,在centos X86的节点上和UOS ARM架构的节点上都同时运行host的服务,这是如何做到的呢?
这就要求统一服务的进项,要在host:v3.6.10的镜像中包含两种架构的镜像格式,它的底层同时将X86和ARM的格式捆绑到一起,在实际运行过程中,在不同的架构的节点上,docker会根据当前节点的架构拉取镜像中不同架构的格式的镜像运行。
7、私有云业务如何支持ARM64?

  • 宿主机 列表
超详细的ARM架构适配介绍!
文章图片

在运行虚拟机的宿主机上去标记宿主机的架构类别,云平台的前端界面可以看到,给宿主机列表上面加了CPU架构的属性,ARM架构服务器的宿主机,会给它一个称为aarch64的CPU架构来标记,X86则会标记x86_64的CPU架构属性 。
若要运行虚拟机,则需要先提供虚拟机的镜像,我们在虚拟机的镜像中也使用了CPU架构的属性来标记虚拟机镜像是X86架构还是ARM 64位的架构。
超详细的ARM架构适配介绍!
文章图片

提供宿主机和虚拟镜像过后,即可创建虚拟机,在创建虚拟机的表单中,会让用户去选择是要创建ARM架构的虚拟机还是X86架构的虚拟机。
超详细的ARM架构适配介绍!
文章图片

创建好虚拟机过后,平台负责将这些虚拟机根据所提供的CPU架构调入到不同架构的宿主机上,这是一个在平台同时创建的X86和ARM的虚拟机列表界面。
超详细的ARM架构适配介绍!
文章图片

在此列表中通过CPU架构的字段了解虚拟机的架构类型,这就是在私有云这个业务做的改造并支持ARM64位架构。
技术细节
如何制作统一的容器镜像(支持X86_64和ARM64)?
  • docker buildx方案
docker原生支持的多架构镜像制作方案
  • 使用交叉编译然后打包
分别编译打包出x86_64和arm64的容器镜像,然后捆绑到一起。
1、统一容器镜像—docker buildx
  • 编写适用buildx的 Dockerfile
超详细的ARM架构适配介绍!
文章图片

docker通过读取file中的语句,制作出镜像,Dockerfile先基于一个称golang:alpine的镜像,把它作为一个build容器。
同时,其中会传两个参数,分别是TARGETPLATFORM 和BUILDPLATFORM。
TARGETPLATFORM的意思是制作出的镜像架构,BUILDPLATFORM 是当前制作镜像机器的架构 ,这里RUN的命令会读取这两个环境变量,然后将他们的值打到名称为log的文件中。
第二步,FROM alpine 的语句是找到alpine这个镜像,基于这个容器镜像将build容器中的log文件拷贝出来。
使用buildx 同时制作x86_64和arm64架构的镜像。
超详细的ARM架构适配介绍!
文章图片

-t的意思是build出的镜像的名称,push代表要push到docker镜像仓库中,platform参数代表制作出来的镜像同时代表两个架构,分别是x86 64位架构和arm64位架构。
运行此命令,docker buildx就会基于dockerfile的步骤,同时拉取ARM架构和X86架构的基础镜像。
超详细的ARM架构适配介绍!
文章图片

基于基础镜像运行里面相同的语句,例如红色标记的地方,它同时运行两个架构的指令,相当于同时拉取了amd64和arm64的alpine 镜像。
去build时,同一条build语句也在amd64和arm64这两个架构上运行。
通过build出的结果即可发现RUN的这个命令,是在X86架构的机器上制作的镜像build出的结果,例如第一条是build出了arm64的镜像,第二条是build出X86 64位的镜像。
build完镜像过后,把它push到镜像仓库中,即可通过docker manifest 这个命令去查询这个镜像里面的一些元数据,查看刚才制作的镜像,manifest 中有两种格式,第一种格式是amd64,表示X86_64架构,第二种格式是ARM64,是能够运行在ARM上的镜像,这些都是buildx做好的,我们只需要写dockerfile。
超详细的ARM架构适配介绍!
文章图片

它默认帮我们制作出来一个多架构的容器镜像。
buildx 如何在 x86_64的机器上制作arm64的镜像?
通过binfmt_misc模拟arm64硬件的用户空间,然后调用qemu的用户态模式编译程序。
超详细的ARM架构适配介绍!
文章图片

最终结果是调用buildx的命令过后,编译进程后,会运行qemu-aarch64 工具,相当于模拟出arm64的硬件环境,然后调用ARM的工具做编译,截图中,后端服务都是用Golang编写,都需要做编译。
2、统一容器镜像-交叉编译
交叉编译:直接在x86_64开发机上编译arm64二进制。
超详细的ARM架构适配介绍!
文章图片

图中的Go代码,其中写了main的函数,在X86的机器上直接编译,调go build工具,然后把它编译成一个叫做t_x86_64的二进制可执行文件。
然后在操作系统上调用file去看可执行文件的内容,通过信息可知这是一个64位的可执行文件,并且是x86-64架构。
Go中的交叉变异很简单,指定GOARCH的环境变量,然后把它设置为arm64,然后再运行相同的gobuild的命令,即可使用交叉编译,编译出ARM可执行的文件。
编译出来之后,再去看t_arm64的二进制文件,即可发现它也是64位的执行文件,但其架构为ARM,此即为交叉编译的简单的示例。 相当于在X86的开发机上使用交叉编译工具编译出ARM执行文件。
3、如何将不同架构镜像打包
将交叉编译后的x86_64和arm64容器镜像组合到一起。
超详细的ARM架构适配介绍!
文章图片

例如已经有名称为service:v1_x86_64的容器镜像和service:v1_arm64的镜像,如何将其组合为service:v1 = service:v1_x86_64 + service:v1_arm64 的容器镜像?
首先创建 service:v1 的 manifest 镜像,然后将x86_64的镜像和arm64的镜像捆绑到一起,然后调用docker manifest标记镜像 service:v1_arm64 的架构为 arm64 ,标记镜像 service:v1_x86_64 的架构为 amd64 ,再调用docker push将service:v1 镜像上传到镜像仓库即可,如此制作出来的一个镜像中即可包含两个架构。
4、buildx与交叉编译打包对比
超详细的ARM架构适配介绍!
文章图片

如果使用buildx+binfmt_misc的方式,速度很慢,在本地x86机器上运行,复杂度很低。
如有ARM服务器,可以通知buildx ssh到远程的ARM机器,会把编译arm的部分交给远端的ARM机器,速度很快,环境要求为本地x86+远端arm64机器,因为一般不会给每个开发人员提供ARM服务器,所以未采用此种方式。
最后是交叉编译+manifest打包的方式,速度很快,因为编译器中做了交叉编译的优化,能够直接编译出ARM架构的二进制,此种方式只依赖本地的开发环境,此种方式复杂度较高。
现阶段使用的方式是同时使用buildx + binfmt_misc和交叉编译 + manifest 打包的方式。
前端不需要编译的服务:使用buildx + binfmt_misc后端编译型的服务:使用交叉编译然后打包
5、私有云管理—虚拟化软件
私有云上层业务支持X86和ARM虚拟化混合管理,要做混布支持,首先要让虚拟化软件能够运行在ARM架构上,主要运行虚拟机的软件是通过名称为qemu的虚拟化软件工具,通过交叉编译的方式运行在ARM架构上。
超详细的ARM架构适配介绍!
文章图片

在做编译之前,只需要配置好目标的架构是aarch64即可。
qemu在实际生产使用中要结合KVM虚拟化加速工具,debian 10 4.19.0 aarch64 内核原生支持。
openvswitch 网络虚拟交换机可以直接在debian 中安装使用。
6、私有云管理—业务支持
例如在宿主机的资源中加上属性,标记宿主机是ARM架构还是X86架构,还有在平台虚拟机镜像中加上架构的属性,同时调度器的服务也要做改造,保证用户创建一台ARM架构的虚拟机,能够调度到ARM的宿主机上。
超详细的ARM架构适配介绍!
文章图片

大家可以根据图中列出的 PR详细地址了解业务支持详情。

    推荐阅读