云联壹云平台采用容器化,分布式的架构运行在 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详细地址了解业务支持详情。

GitHub: github.com/yunionio/cl…

官网地址: www.yunion.cn/

作者:云联壹云
链接:https://juejin.cn/post/7055624332524912677
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1. 编译参数 arm 平台不支持“-m32"和“-m64"这样的编译参数。取而代之用 “-mabi=ilp32“ 和 “-mabi=lp64” 代替。还可以在指定 cpu的 架构 版本,如: bazel build --cxxopt="-march= arm v8-a" --cpu aarch64 ... 2. 内存对齐 arm 平台默认的内存pagesize 和 x86平台不一致。
平板霸主 ARM 架构 面临兼容性分歧   根据市场研究机构 DIGITIMES Research 在 COMPUTEX 2011 期间的观察,平板系统已经成为各大手机、IT厂主打的重点经营项目;当然,为了抢进、或者是巩固既有的平台市场版图,各处理器供货商也都使出浑身解数,不论是在软硬件开发、兼容性、性能、功耗,都强调各自的优势所在。   DIGITIMES Research 分析师林宗辉分析,从C
上月下旬通信芯片厂商MACOM达成最终协议以约7.7亿美元收购Applied Micro,日前则已决定只留下后者的高速载波和数据中心连网芯片业务分拆它的 ARM 架构 服务器 芯片业务,这对 ARM 服务器 芯片市场造成了重击,对于Intel来说则是重大喜讯。   为何说是对 ARM 的重击 ARM 已在移动市场占据垄断性的市场地位,Intel的X86 架构 进军移动市场基...
文章目录苹果 Arm 芯片 适配 开发 (Apple Silicon)Apple Silicon 苹果 Arm 芯片 适配 开发 (Apple Silicon) Apple Silicon 构建原生运行在Apple silicon上的应用程序、库、框架、插件和其他可执行代码。当您在Apple框架和技术之上构建可执行文件时,您可能需要采取的唯一重要步骤是为 arm 64 架构 重新编译代码。如果您依赖于特定硬件的细节,或者假设底层特性,那么根据需要修改您的代码以支持Apple silicon。 要想在Apple silicon上获
#### 获取适合 ARM 架构 的Qt版本 对于 ARM 架构 下的树莓派来说,直接获取预编译好的二进制文件是最简便的方法之一。可以从官方渠道获得适用于特定硬件平台的Qt版本[^2]。 ```bash wget https://download.qt.io/official_releases/qt/5.15/5.15.2/single/qt-everywhere-src-5.15.2.tar.xz tar xf qt-everywhere-src-5.15.2.tar.xz cd qt-everywhere-src-5.15.2 #### 配置交叉编译环境 考虑到目标平台为 ARM 架构 ,可能需要设置交叉编译链来构建 适配 于该 架构 的应用程序。这一步骤涉及到调整`./configure`命令参数以适应不同的处理器体系结构[^1]。 ```bash sudo apt-get install build-essential libgl1-mesa-dev export QTDIR=$PWD export PATH=$QTDIR/bin:$PATH ./configure -release -opengl es2 -device linux-rasp-pi-g++ \ -device-option CROSS_COMPILE= arm -linux-gnueabihf- \ -sysroot /path/to/sysroot -prefix /usr/local/qt5pi \ -make libs -nomake examples -no-vulkan -qt-xcb make -j$(nproc) make install 请注意替换上述命令中的`/path/to/sysroot`为你实际的sysroot路径。 #### 编写简单的测试应用验证安装成果 完成以上操作之后,可以通过编写一段简单代码来进行初步的功能检测,以此证明Qt已经成功部署到树莓派之上。 ```cpp #include <QApplication> #include <QPushButton> int main(int argc, char *argv[]) { QApplication app(argc, argv); QPushButton button("Hello Qt on Raspberry Pi ! "); button.resize(200, 80); button.show(); return app.exec(); 保存这段代码至`.cpp`文件,并利用刚刚建立起来的Qt环境对其进行编译运行。 #### 注意事项 在整个过程中需要注意几个方面的问题: - **依赖关系管理**:确保所有必需的外部库都已经被正确安装; - **权限问题**:某些情况下可能会遇到由于权限不足而导致的操作失败,这时应当考虑使用超级用户权限执行相应指令; - **资源消耗评估**:鉴于嵌入式系统的特殊性质,务必提前做好关于CPU占用率、内存利用率等方面的考量[^4]。

用简单有趣的表述、生动鲜活的图表、严谨而不枯燥的逻辑让你瞬间懂得Apple开发中(侧重于SwiftUI以及调试)的痛点、难点问题。 拒绝原封不动的抄袭!所有分析过程和解决方案都经笔者亲自验证,并及时更新,保证有理有据、真实可靠、你值得拥有 ;) 侯佩的秒懂百科,让编程如此简单!