InfoQ 研究中心诚意出品,一份报告带你走进中国 2000 万开发者 了解详情
写点什么

基于 kubernetes 的 VM 解决方案探讨

  • 2019-08-21
  • 本文字数:4732 字

    阅读完需:约 16 分钟

基于kubernetes的VM解决方案探讨

一、背景

eBay 从 2015 年就开始适配 kubernetes 平台并逐渐部署各个团队的产品。然而 eBay 仍然部署着很大规模的 OpenStack 集群。同时管理 kubernetes 集群和 OpenStack 集群需要耗费更多的人力和物力。但由于 eBay 内部还有一部分业务无法迁移到容器,我们能否用一套控制平面(control plane)同时管理容器和虚拟机呢


二、已有的方案

在几年的时间里,kubernetes 不断发展壮大,各个功能逐渐完善,越来越多的公司基于 kubernetes 构建云平台。在 eBay 内部,越来越多的产品基于 kubernetes 构建,因此用 kubernetes 来统一云平台是大势所趋,我们需要一种方案来基于 kubernetes 管理虚拟机


现在社区有两套相对成熟的基于 kubernetes 来管理虚拟机的方案,分别是 kubevirt 和 virtlet


1. Kubevirt

Kubevirt 是 redhat 发起的项目,它使用 CRD 去描述一个 VM(Virtual Machine,虚拟机),通过它的控制器(controller)去把 CRD 转换成一个 POD。由于它使用的是 CRD 而不是 POD,导致需要额外的控制器来实现 kubernetes 里**原生的部署和服务(deployment,service)这些功能。VM 的实例运行在容器(container)**里,一个 VM 有对应的 libvirt 来管理。Kubevirt 的社区比较活跃,但版本还在较早的阶段。


2. Virtlet

Virtlet 来自于 Mirantis,跟 kubevirt 的不同之处在于它使用 POD 来描述一个 VM。因为 kubelet 是通过 CRI 接口跟下面的运行时交互的,virtlet 实现了一套 VM 的 CRI。因为 POD 是 kubernetes 的一等公民,任何现有的 kubernetes 功能都可以用于 virtlet 管理的 VM,且不需要额外的控制器,比如服务、部署等等,这样几乎不需要额外的学习和维护成本。但因为一些 VM 特定的信息无法完全用 POD 来描述,virtlet 借助了 POD 的注解(annotation)来表达更多 VM 的信息。


三、我们的选择

根据我们的评估以及 eBay 现有的架构,选择了 virtlet 来作为 kube VM 方案。首先 kube VM 入口是基于 AZ(Availability Zone,可用区域)的,已经有了一套 CRD 来描述现有的 kubernetes 节点,只需要加一个 provider(提供者)就可以重用现有 AZ 的各种控制器。其次,需要各种定制来达到跟 OpenStack VM 同样的功能和性能。Virtlet 因为有一套单独的 CRI 实现,可以更容易地加入各种定制。


1. Virtlet 概览

图 1 是来自 virtlet 社区的架构图。一个节点上 virtlet POD 包含三个容器


  • virtlet:接收 CRI 调用,管理 VM

  • libvirt:接收 virtlet 的请求创建、停止或销毁 VM

  • VMs:所有 virtlet 管理的 VM 都会在这个容器的命名空间里



图 1(点击可查看大图)


2. 运行时



图 2(点击可查看大图)


01 CRIProxy

如图 2 所示,因为 virtlet 有单独的 CRI 实现,如果在一个节点上既需要支持 VM 又要支持容器,就需要有一个 proxy 来分发 CRI 调用


  • 镜像:CRIProxy 通过区分一个可配置的前缀来区分是一个容器镜像还是一个 VM 镜像。

  • 运行时:CRIProxy 通过特定的注解来区分容器或 VM。


默认情况下所有的调用会分发给容器运行时。


02 改进

因为引入了 CRIProxy,多了一层中间调用,使这个架构看起来不够统一,多了一层可能的出错点,增加了出问题的几率以及调试的难度。所以我们下阶段计划开发一个 VM shim,如图 3 所示。它满足 containerd 的 shim 规范。这样单个节点的运行时看起来更统一和干净。



图 3(点击可查看大图)


四、模型

刚有提到,操作 VM 的入口是在 AZ 层,而且已经有了 CRD 来描述一个节点。同一个 AZ 管理着一个或者多个 kubernetes 集群



图 4(点击可查看大图)


这里的 provider virtlet,专门管理 VM 的生命周期。如图 4 所示,它主要的任务是根据 ComputeNode,首先挑选一个 kubernetes 集群,然后在这个集群里创建一个对应 VM 的 POD,同步他们之间的状态。对于用户而言,下面的 POD 是不可见的,用户通过创建或者删除 ComputeNode 来管理 VM


五、定制

Virtlet 已经有了大部分所需要的功能,但还不能完全满足需求,我们对以下方面做了定制和改进


  • VM 网络

  • NUMA Pin

  • VM 的重启、停止

  • OpenStack 镜像兼容

  • Virtlet 的可靠性


1. VM 网络

01 Virtlet 网络管理

对于现有的 eBay VM,都是桥接(bridge)网络,只需要在 libvirt domain 指定目标桥接器,libvirt 就会在启动 VM 的时候创建一个 TAP 接口,并把这个接口连接到指定的桥接器。


然而对于 kubernetes 的 VM,网络接口是调用 CNI 插件先配置好,然后才会创建和启动 VM。Virtlet 引入了 vmwrapper,它是所有 VM 启动的入口,virtlet 会把 vmwapper 设置成 libvirt domain 的入口(emulator)



图 5(点击可查看大图)


从图 5 可见,启动一个 libvirt 实例后,vmwrapper 会被首先执行


  • Virtlet 侦听在一个 unix domain socket 上,并且 virtlet 已经打开了相应 VM 的 TAP 接口。

  • vmwrapper 发起连接跟 virtlet 通信,拿到 TAP 接口的文件描述符(FD)

  • vmwrapper 填写好网络相关的参数,最后启动真正的 qemu 进程


qemu 网络参数举例如下



这里涉及到了进程间传递描述符(FD),virtlet 使用的是 Linux 的 SCM(Socket level control messages)方式


02 网络改进

每一次 CNI 插件配置网络,都会建一个新的网络命名空间(network namespace),一般需要有一对 veth pair 来连接主机的网络和新建的网络空间。Virtlet 默认 VM 网络如图 6:



图 6(点击可查看大图)


连通一个 VM,需要建一个 bridge,一对 veth pair,这样网络的性能会有一定的影响。


VM 本身有强隔离性,我们又有自己的 CNI 插件实现,为了减少网络的路径,创建 VM 的网络不需要新的网络命名空间。最终一个节点的网络结构如图 7 所示:



图 7(点击可查看大图)


03 Vhost net

Virtlet 不支持 vhost net,而 eBay OpenStack 上使用 virtio 的 VM 都有 vhost net。增加这个功能,对每一个 TAP 接口,都需要有一个 vhost net 的描述符,这个描述符是通过打开/dev/vhost-net 而来的。描述符的传递跟前面提到过的 TAP 描述符传递类似。


04 支持 TSO(TCP Segment Offload)

在对 virtlet 的 VM 进行网络性能测试的时候,网络吞吐量只有 OpenStack VM 的一半,在 VM 里面,soft IRQ 负载很高,最终发现 virtlet VM 的网络没有打开 TSO 和 TX/RX 校验


无论是 Open Stack 的 VM 还是 virtlet 的 VM,都没有显示配置这个选项,但为什么 OpenStack 的 VM 默认是打开的呢?


前面提到,常规 VM 的网络接口是 libvirt 创建和删除的,而 virtlet 的 VM 网络接口是由 CNI 创建、virtlet 管理的。通过阅读 libvirt 和 qemu 的源代码,libvirt 在打开 TAP 接口的时候会加一个 IFF_VNET_HDR 的选项,qemu 检查到这个选项后, VM 实例的网络接口就会默认打开 TSO。通过这个小小的改动,virtlet VM 的网络吞吐量跟 OpenStack 的 VM 旗鼓相当


2. NUMA Pin

eBay 数据中心的服务器都有 2 个或以上的 NUMA 节点,在这些节点上运行的 VM,需要把他们尽量固定在 NUMA 节点上,否则跨 NUMA 节点的访问会带来性能问题。Kubernetes 有 CPU manager 这个功能,CPU 的分配也顾及到了机器上的 NUMA 节点,但不能完全满足要求,原因如下


  • CPU 是独占的。也就是一个 CPU 被分配给一个 POD 后,其它任何 POD 就不能再分配到这个 CPU 了,这样不能做到超售。

  • CPU 的分配可能会跨 NUMA 节点,但并不平衡。比如一个 POD 需要 8 个 CPU,那就有可能 2 个 CPU 分配在一个 NUMA 节点,另外的 6 个 CPU 分配在另一个 NUMA 节点,导致了不平衡。


基于以上原因,我们没有使用 CPU manager 这个功能,而是在 virtlet 里增加了一个模块来管理 NUMA 节点的分配和释放(这也是 virtlet 有自己的 CRI 实现的好处之一)


  • 固定 VM 所运行的 NUMA 节点,但不固定 VM 运行在 NUMA 节点对应的 CPU。比如一台机器有 2 个 NUMA 节点,CPU 0-15 NUMA 0CPU 16-31 NUMA 1,如果申请一个 4 核的 VM,那这个 VM 只会运行在其中的一个 NUMA 节点上,但 VM 能用到的 CPU 可以是这个 NUMA 节点上所有的 CPU(当然这只是标准的 VM,对于有高性能要求的 VM,既要有 NUMA 固定也需要有 CPU 固定)。

  • 对于 NUMA 的分配,采取的是 CPU、内存最平衡的方式,也就是在一个 NUMA 节点上,在分配量不超过某个阈值的前提下,计算已经分配的 CPU 和内存,加上将要被分配的 VM 需要的 CPU 和内存,CPU 分配量和内存分配量差值的绝对值哪个最小,哪个优先级就最高


3. VM 的重启和停止

Virtlet 没有提供 VM 重启(reset)和停止(stop),但 eBay 有些团队需要这样的功能。前面提到,virtlet 的 VM 就是一个普通的 POD,在 kubernetes 里如果一个 POD 不是在运行(running)状态,kubernetes 就会不断重试,去把 POD 带回到运行状态。因此需要一个单独的模块来管理 VM 的状态


  • 综合当前 VM 的实际状态和用户所期望的状态,做到最后状态一致。

  • 增加一个 POD 的注解,里面包含所**需要(request)的状态和实际(status)**状态。

  • 在给 kubelet 汇报 VM 状态的时候,如果用户显示的是该 VM 已停止,仍然要向 kubelet 汇报是运行状态,这样 kubelet 就不会反复地调用启动的接口。


4. OpenStack 镜像兼容

eBay 运行着很大规模的 OpenStack 集群,有许多已有的 VM 镜像,virtlet 必须能无缝地使用这些已有的镜像。


在 eBay,绝大部分 OpenStack VM 的网络信息是通过 configdrive 静态注入的方式,由 cloutinit 来完成网络的配置的,虽然 virtlet 的文档里声称支持 configdrive,但他们使用的是不同的 configdirve 的版本,大部分的现有镜像都不能正确拿到 configdrive 所注入的信息。


因此需要实现另一个版本的 configdrive,甚至还能兼容 Windows VM。满足这两个需求,有两个关键的地方


  • Configdrive 盘必须有 config-2 的标签。

  • Configdrive 必须是 vfat 格式的(虽然 configdrive 可以是 vfat 或者 iso,但某些 Windows 的 cloudinit 不能识别 ISO 格式)。


六、可靠性

尽管 VM 的生命周期用 kubernetes 来管理,但 VM 和容器还是有不同的地方:在 VM 的生命周期之内,不管是 POD 重启、virtlet 重启以及节点重启,VM 的所有数据不能有任何丢失;而容器在重启之后数据就会消失(不包括 host path)


Virtlet 要能用在生产环境,必须做到数据不丢失。还有节点上的 VM 能够脱离 virtlet 运行良好,这样才能给 virtlet 升级。从一开始,我们就非常关注 virtlet 的可靠性,也找到了 virtlet 可靠性所存在的一些问题


  • 升级 virtlet 本身,所有的 VM 也莫名其妙地消失了。

  • 重启节点,VM 所有的数据丢失。

  • 停止 VM 和 virtlet,然后再启动 virtlet 和 VM,VM 再也不能启动。


如果以上的问题不能解决,virtlet 就不能用在生产环境,需要用其它方案甚至重新开发一套来代替。幸运的是通过积极阅读代码和调试,我们解决了上面的问题,社区也接受了这些补丁


对于基于 virtlet 的一些改进和定制,需要保证每次改动不影响已有的功能,从一开始我们就开发了集成测试端到端测试来保证可靠性


七、性能

有了可靠的保障,性能也必须达标,参照物就是已有的 OpenStack VM


  • 我们使用各种基准测试工具对相同 CPU、内存以及磁盘的 virtlet VM 和 OpenStack VM 进行测试。

  • 使用生产环境的镜像流量来比较两者的 CPU 和内存使用率,以及在每秒时间内能够处理的事务(TPS Transaction Per Second)


比较下来的结果是两者没有差距,达到了我们的预期和要求


八、结语

Kubernetes 愈来愈受各家公司重视,这是未来几年甚至数十年云平台的趋势。但是从老的平台过渡到新的平台需要时间,一刀切的方式会带来无法遇见的风险和额外的耗时,特别是像 eBay 这样有多样产品和大体量的云平台公司。用 kubernetes 来管理 VM 使这种过渡成为了可能,既不需要同时维护两套平台,也减少了新老交替带来的风险


本文转载自公众号 eBay 技术荟(ID:eBayTechRecruiting)


原文链接


https://mp.weixin.qq.com/s/CZzD1qf9QSGW9F5rsg13-Q


2019-08-21 08:004826

评论 2 条评论

发布
用户头像
现在还是看好kubevirt
2021-03-25 11:29
回复
用户头像
可惜 virtlet 已经木有人维护了...
2020-11-24 15:53
回复
没有更多了
发现更多内容

百度单测生成技术如何召回线上服务的异常问题?

百度Geek说

c c++

Linux 文件搜索神器 find 实战详解,建议收藏!

鞋子特大号

Linux find

CDN加速原理的那些事

阿里Java面试脑图遭公开,GitHub上已获赞79.6K

Java架构师迁哥

数据主权,才是业务在线化的核心

boshi

数据 数字资产 七日更

加班

IT蜗壳-Tango

七日更 2月春节不断更

有用的信息安全资质查询网站大全

石君

信息安全 28天写作

业务流程和产品文档

让我思考一会儿

ThreadLocal 类以及应用技巧

武哥聊编程

Java 多线程 ThreadLocal 28天写作

开发质量系列:系统运营必须派人常驻机房吗?

罗小龙

最佳实践 方法论 28天写作 2月春节不断更

怎么一本正经地秀技

codevald

Java jdk

黑客练手入门| pwnable.kr—幼儿瓶—02:collision

BigYoung

安全 CTF PWN 28天写作 2月春节不断更

下不了的开人的手

Ian哥

28天写作

“嗖”一下28 天过去啦,我们都在交作业!

李忠良

28天写作

5G专网是个大西瓜(三):合成之难

脑极体

2021最新最全面“Java知识总结+⾯试指南”强烈推荐!

比伯

Java 编程 架构 面试 技术宅

深入Linux内核之自旋锁spinlock_t机制

赖猫

c++ Linux内核

28天瞎写的第二百三十八天:这一年干了啥?

树上

28天写作

MyBatis入门

小马哥

Java mybatis 七日更 2月春节不断更

机器学习笔记之:Matrix Vector Multiplication

Nydia

Linux Lab 进阶: Linux 内核

贾献华

Linux Linux Kenel 内核

产品训练营第二周作业-利益相关者

mayue

产品 产品经理训练营

【Linux系统】一个常驻进程问题的再次分析

程序员架构进阶

Linux 七日更 28天写作 2月春节不断更 共享内存

乌云下,种因时:vivo的平凡之路

脑极体

产品经理第四周

克比

写在“28天坚持写作活动”的最后一天

JiangX

28天写作

《我们一起学集合》-LinkedList

蚊子

Java 数据结构 面试 集合 linkedlist

管理笔记[8]:管理中的聚势、借力与计划

俊毅

28天写作

lidaobing

28天写作

【LeetCode】子数组的最大平均数

Albert

算法 LeetCode 2月春节不断更

如果非要在多线程中使用ArrayList会发生什么?

看山

线程安全

基于kubernetes的VM解决方案探讨_云计算_eBay技术荟_InfoQ精选文章