本文次要介绍云联壹云平台如何适配 ARM,并运行在 ARM CPU 架构的机器上。
背景介绍
1、平台服务运行架构
云联壹云平台采纳容器化,分布式的架构运行在 Kubernetes(K8s)之上。上面是平台服务运行的架构图:
在多个节点之上,咱们会构建 Kubernetes 的集群,它是一个容器治理的平台。
在 Kubernetes 的平台之上,后端服务都是容器化的,是以容器的形式去分布式运行。
通过 K8s 去做调度的治理,而后将服务主动地打散到多个节点上运行,总结两点是服务容器化,并依附 K8s 来提供容器分布式运行的环境。
另外,底层的节点是有类型的,管制层面的服务运行在管制节点,平台内置了一个公有云,提供了残缺的公有云性能。
若要应用私用云这个性能,则还须要一些计算节点,计算节点上会跑虚拟化相干的软件,提供公有云虚拟化的性能,总结来说就是计算节点运行公有云的虚拟机。
2、CPU 架构简介
大家相熟的服务器或者台式机都是 X86 架构的 CPU,X86 架构的 CPU 特点是性能高,并且软件的兼容性很好。
大家平时工作中应用的大部分是英特尔等提供的 X86 架构的 CPU,对于英特尔和 AMD 大家都不生疏,这两家厂商专门生产 X86 架构 CPU。
另外 X86 64 位这种架构的 CPU 存在别名,例如 x86_64 或者 amd64 都代表 X86 架构的 64 位 CPU。
与 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 和 X86 的服务器上,同时运行各自的虚拟化,能够通过咱们平台对立部署和治理。
如何适配 ARM64?
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(国产零碎)。
抉择这两个发行版的第一个起因是客户业务上要求在 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 适配过后,通过其官网测试,为咱们颁发了认证证书。
4、对立软件依赖—包管理工具
抉择好发行版后?怎么对立装置这些软件?
咱们可能应用不同发行版的包管理工具去装置雷同的软件,例如在 X86 的 CentOS 上装置 docker 和 K8s 这些包时调用 yum,在 Debian 上调用 apt install 等同样的包名即可。
上游的软件仓库中曾经把包做好,只需间接装置,软件间接下载即可应用。
在底层软件方面,ARM 和 X86 的治理,只有发行版是支流的,验证 Debian 和 X86 的包没有区别,曾经将底层的包装置部署好。
5、部署 kubernetes 集群
另外一个话题是部署 kubernetes 集群,如何在 ARM 上部署 K8s 集群?
首先,咱们写了名称为 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 集群之后如何运行云联壹云的服务?
例如 K8s 中有 daemonset 的资源,这种资源示意在每一个 K8s 节点上都会运行 pod 容器。
它要求在这个资源中写好服务容器镜像的地址,即红框中所标记的。
只有依照这样的格局写,写好之后创立到 k8s 集群中,K8s 就会将提供的镜像以容器化的形式运行到各个节点上。
从图中能够理解到,在 centos X86 的节点上和 UOS ARM 架构的节点上都同时运行 host 的服务,这是如何做到的呢?
这就要求对立服务的出项,要在 host:v3.6.10 的镜像中蕴含两种架构的镜像格局,它的底层同时将 X86 和 ARM 的格局捆绑到一起,在理论运行过程中,在不同的架构的节点上,docker 会依据以后节点的架构拉取镜像中不同架构的格局的镜像运行。
7、公有云业务如何反对 ARM64?
- 宿主机 列表
在运行虚拟机的宿主机下来标记宿主机的架构类别,云平台的前端界面能够看到,给宿主机列表下面加了 CPU 架构的属性,ARM 架构服务器的宿主机,会给它一个称为 aarch64 的 CPU 架构来标记,X86 则会标记 x86_64 的 CPU 架构属性。
若要运行虚拟机,则须要先提供虚拟机的镜像,咱们在虚拟机的镜像中也应用了 CPU 架构的属性来标记虚拟机镜像是 X86 架构还是 ARM 64 位的架构。
提供宿主机和虚构镜像过后,即可创立虚拟机,在创立虚拟机的表单中,会让用户去抉择是要创立 ARM 架构的虚拟机还是 X86 架构的虚拟机。
创立好虚拟机过后,平台负责将这些虚拟机依据所提供的 CPU 架构调入到不同架构的宿主机上,这是一个在平台同时创立的 X86 和 ARM 的虚拟机列表界面。
在此列表中通过 CPU 架构的字段理解虚拟机的架构类型,这就是在公有云这个业务做的革新并反对 ARM64 位架构。
技术细节
如何制作对立的容器镜像(反对 X86_64 和 ARM64)?
- docker buildx 计划
docker 原生反对的多架构镜像制作计划
- 应用穿插编译而后打包
别离编译打包出 x86_64 和 arm64 的容器镜像,而后捆绑到一起。
1、对立容器镜像—docker buildx
- 编写实用 buildx 的 Dockerfile
docker 通过读取 file 中的语句,制作出镜像,Dockerfile 先基于一个称 golang:alpine 的镜像,把它作为一个 build 容器。
同时,其中会传两个参数,别离是 TARGETPLATFORM 和 BUILDPLATFORM。
TARGETPLATFORM 的意思是制作出的镜像架构,BUILDPLATFORM 是以后制作镜像机器的架构,这里 RUN 的命令会读取这两个环境变量,而后将他们的值打到名称为 log 的文件中。
第二步,FROM alpine 的语句是找到 alpine 这个镜像,基于这个容器镜像将 build 容器中的 log 文件拷贝进去。
应用 buildx 同时制作 x86_64 和 arm64 架构的镜像。
- t 的意思是 build 出的镜像的名称,push 代表要 push 到 docker 镜像仓库中,platform 参数代表制作进去的镜像同时代表两个架构,别离是 x86 64 位架构和 arm64 位架构。
运行此命令,docker buildx 就会基于 dockerfile 的步骤,同时拉取 ARM 架构和 X86 架构的根底镜像。
基于根底镜像运行外面雷同的语句,例如红色标记的中央,它同时运行两个架构的指令,相当于同时拉取了 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。
它默认帮咱们制作进去一个多架构的容器镜像。
buildx 如何在 x86_64 的机器上制作 arm64 的镜像?
通过 binfmt_misc 模仿 arm64 硬件的用户空间,而后调用 qemu 的用户态模式编译程序。
最终后果是调用 buildx 的命令过后,编译过程后,会运行 qemu-aarch64 工具,相当于模拟出 arm64 的硬件环境,而后调用 ARM 的工具做编译,截图中,后端服务都是用 Golang 编写,都须要做编译。
2、对立容器镜像 - 穿插编译
穿插编译:间接在 x86_64 开发机上编译 arm64 二进制。
图中的 Go 代码,其中写了 main 的函数,在 X86 的机器上间接编译,调 go build 工具,而后把它编译成一个叫做 t_x86_64 的二进制可执行文件。
而后在操作系统上调用 file 去看可执行文件的内容,通过信息可知这是一个 64 位的可执行文件,并且是 x86-64 架构。
Go 中的穿插变异很简略,指定 GOARCH 的环境变量,而后把它设置为 arm64,而后再运行雷同的 go build 的命令,即可应用穿插编译,编译出 ARM 可执行的文件。
编译进去之后,再去看 t_arm64 的二进制文件,即可发现它也是 64 位的执行文件,但其架构为 ARM,此即为穿插编译的简略的示例。相当于在 X86 的开发机上应用穿插编译工具编译出 ARM 执行文件。
3、如何将不同架构镜像打包
将穿插编译后的 x86_64 和 arm64 容器镜像组合到一起。
例如曾经有名称为 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 与穿插编译打包比照
如果应用 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 架构上。
在做编译之前,只须要配置好指标的架构是 aarch64 即可。
qemu 在理论生产应用中要联合 KVM 虚拟化减速工具,debian 10 4.19.0 aarch64 内核原生反对。
openvswitch 网络虚构交换机能够间接在 debian 中装置应用。
6、公有云治理—业务反对
例如在宿主机的资源中加上属性,标记宿主机是 ARM 架构还是 X86 架构,还有在平台虚拟机镜像中加上架构的属性,同时调度器的服务也要做革新,保障用户创立一台 ARM 架构的虚拟机,可能调度到 ARM 的宿主机上。
大家能够依据图中列出的 PR 具体地址理解业务反对详情。