【云原生】安全容器 Kata Containers

1. Kata containers Overview

出于对传统容器安全性的担忧,Intel 在 2015 年启动了它们以虚拟机为基础的容器技术:Clear Container。Clear Container 依赖 Intel VT 的硬件虚拟化技术以及高度定制的 QEMU-KVM(qemu-lite)来提供高性能的基于虚拟机的容器。在 2017 年,Clear container 项目加入了 Hyper RunV,这是一个基于 hypervisor 的 OCI 运行时,从而启动了 Kata 容器项目

Kata containers的核心思路是:

  1. 操作系统本身的容器机制没办法解决安全性问题,需要一个隔离层;
  2. 虚拟机是一个现成的隔离层,云服务已经让全世界相信,对户来说,“secure of VM” 是可以满足需求的;
  3. 虚机里面只要有个内核,就可以支持 OCI 规范的语义,在内核上跑个 Linux 应用这并不太难实现;
  4. 虚机可能不够快,阻碍了它在容器环境的应用,那么可不可以拥有 “speed of container” 呢?

所以,Kata containers核心之一是把VM变得轻快稳,使之能满足容器高密弹性的需求。同时,作为一个容器运行时,必须深度融入生态,支持相关规范。

在这里插入图片描述

Kata containers 最大的特点是它专注于实现一个开放的符合OCI标准的安全容器runtime实现,对于对接什么样的虚拟化方案,它抽象了一套hypervisor接口,如今已经对接了多种虚拟化实现,比如qemu、nemu、firecracker、cloud-hypervisor等。

Kata Containers 安全容器的诞生解决了许多普通容器场景无法解决的问题:

1. 多租户安全保障。 云原生多租户场景下,安全容器可以防止恶意租户对 host 内核的直接攻击并大幅减少机器上其他租户的风险,从而让公有云服务变得更稳定。

2. 不同 SLO 混部容器混合部署。 安全容器的强隔离性减少了容器之间的性能影响,使得不同 SLO 优先级实例混部有了更稳定的技术方案,对延时敏感的在线业务用 runC 解决方案,大数据类对资源诉求比较高且有明显峰谷差异的离线业务用安全容器解决方案,防止离线业务突发流量影响到在线业务,通过在线离线业务同时混部进一步减少计算资源的浪费和成本消耗。

3. 可信&不可信容器混合部署。 可信代码运行在 runC 容器中,不可信代码运行在安全容器中,两者在同一台宿主机上混部,降低不可信容器产生危害的可能性。

2019年,Kata containers有个非常重要的技术进步,和containerd社区共同制定了shimv2接口规范,并率先在Kata containers支持了该规范。通过containerd-shim-v2和vsock技术,kata精简了大量的组件,配合轻量级hypervisor和精简内核,kata可以大幅降低内存开销和容器启动时间。更关键的是,降低系统部署复杂度还大幅提高了稳定性,特别是在系统重载情况下的稳定性。从实际使用体感看,阿里云沙箱容器1.0从shimv1升级到shimv2后,稳定性得到大幅提升,缺陷数量大幅下降。一个技术,同时服务于**“轻”、“快”、“稳”**三个目标,当之无愧重要的技术进步!

在这里插入图片描述

从2019年8月开始,阿里云、蚂蚁和intel三方共同推动Kata containers 2.0架构定义及设计,核心是进一步提升多租隔离能力及可观测性。

Kata Containers和runC不是替代与被替代,而是青出于蓝而胜于蓝。Kata Containers把runC一层基于OS虚拟化的隔离机制扩展为三层隔离:Guest OS 虚拟化(等效于runC),硬件虚拟化和Host OS虚拟化。所以Kata Containers通过引入更多的间接层来提升系统的隔离能力,但是需要付出“更多间接层”的代价。

在这里插入图片描述

将容器的概念映射到虚拟机技术

Kata为了k8s中的部署实现了CRI接口,在每个节点中,Kubelet会与一个CRI的实现者(例如containerd、CRI-O)进行交互,后者反过来与Kata Containers进行交互。如k8s CRI-API repo中定义的CRI API那样,为了支持CRI的全部API,Kata必须提供以下结构

在这里插入图片描述

这些结构可以被继续映射到与虚拟机交互所需的设备

在这里插入图片描述

最终,这些概念映射到特定的半虚拟化设备或虚拟化技术。

在这里插入图片描述

每个虚拟机管理程序或 VMM 的处理方式或是否处理这些都各不相同。

5. Kata 3.0

为了解决由于云原生带来的高密、高并发等技术难题,阿里云内部用多年的时间锤炼了一套袋鼠云原生底层系统。袋鼠中的安全容器解决方案便是基于 Kata Containers 项目打造,并将其向更极致的方向深度优化,袋鼠做的优化诸如使用 Rust 重写了 Kata Container 2.0 的 go runtime 来进一步降低容器运行时的内存开销,并且为 Kata Container 专门开发了一个针对容器场景深度优化的轻量级虚拟机管理器Dragonball,通过容器运行时以及虚拟机一体的设计将 Kata 的整体体验带上了新的高度。

在云原生场景下,业界对容器启动速度、资源消耗、稳定性的要求越来越高,而这些也是安全容器相对普通容器会面临的挑战。仿若多年前 runV 和 Clear Containers 的交互诞生了 Kata Containers 这个顶级项目,多年之后的今天袋鼠与 Kata 之间彼此碰撞,袋鼠会将其基于 Kata 社区历经线上生产环境考验的内部系统开源到 Kata 社区,助力 Kata 社区架构升级至 3.0 版本,让 Kata 整体的使用体验、资源消耗、启动速度、稳定性都得到提升。

总结而言,在 Kata 3.0 版本中,新增加了以下设计:

  • 为了减少复杂的流程来和不同 VMM 适配,获得开箱即用的安全容器体验,我们提供了内置基于容器场景深度优化的 Dragonball 沙箱。Dragonball 将提供 Kata 安全容器生态下的虚拟化最优解。

(当然,Kata 3.0 的可扩展架构也支持用户通过配置选项使用其他 VMM,做出符合实际需求的决策。)

  • 为了实现高性能、低资源利用、内存安全,以及高并发的目标,我们实现了 Async Rust Runtime 的新技术。
  • 为了支持不同 Service、 Runtime 和 Hypervisor,以及增加机密容器的相关支持,为 Wasm 等未来方向留下空间,我们在 Runtime 内提供了可扩展框架来实现这一目标。
  • 为了容器和沙箱资源生命周期统一管理机制,我们提供了 Resource Manager 机制来实现这一目标。

架构设计图:

在这里插入图片描述

内置VMM Dragonball

在 Kata2.x 之前 Runtime 和 VMM 是独立的进程。Runtime 进程会 fork VMM 进程并通过 RPC 进行交互。通常,进程之间的交互比进程内的交互会消耗更多的资源,从而会导致相对较低的效率。同时还要考虑资源运维成本,例如,在异常情况下进行资源回收时,任何进程的异常都必须被其他组件检测到,并激活相应的资源回收进程。如果有额外的过程存在,恢复变得更加困难。

并且,不同版本的 Kata 还需要考虑和不同版本的 VMM 的适配问题,可能 VMM 版本的落后或升级都会导致 Kata 适配上出现问题,需要用户花费额外的精力来做版本和配置上的调整。

最后,即使安全容器已经成为了业界多 SLO 混部/公有云多租户问题的标准解决方案,现在仍没有任何一款 VMM 是定位于支持安全容器生态的。其他 VMM 都有各自不同领域的定位,例如 QEMU 能力全面但代码已早早超越百万行,整体启动速度与消耗资源都偏大;Firecracker 虽然做到了极致轻薄但许多虚拟化能力都为了轻薄而做了减法,无法撑起安全容器复杂多变的场景需求。

不同于kata 2.x的设计,3.0提供了内置的VMM,kata通过Dragonball沙盒将VMM的方法结合到Rust库中来使用内置的VMM。通过该库可以使用VMM相关的方法。因为kata container 3.0 运行时和VMM在同一个进程中,在消息处理速度和API同步方面有着更大的优势。同样也能保证运行时和VMM生命周期的一致性,减少资源恢复和异常处理的维护。

在这里插入图片描述

可拓展框架

Rust 版本的 kata-runtime 为 Service、Runtime 和 Hypervisor 提供了可扩展框架,还包括了针对不同场景的配置逻辑。

  • 在 API 层面,Service 提供了插件注册的机制来支持多种容器相关的原生服务。除了对容器进程进行管理的 task service, 后续还会增加 image 服务, 以及可以支持运维监控的其他服务。
  • 支持不同类型的 Runtime 。包括基于虚拟化技术的 VirtContainer,基于可信计算硬件的机密容器。后面还会根据 kata 社区和行业需求考虑支持 WasmContainer 以及 LinuxContainer。
  • 对于 VirtContainer 支持的 Hypervisor,除了内置的 Dragonball, 也可以插件式的去配置 Dragonball、Qemu、Acrn 以及 Firecracker。

在这里插入图片描述

资源管理

在我们的案例中,会有各种资源,每个资源都有相应的子类型。特别是对于 Virt-Container,每个子类型的资源都有不同的操作。并且可能存在依赖关系,例如 share-fs rootfs 和 share-fs volume 将使用 share-fs 资源将文件共享到 VM。目前,network 和 share-fs 被视为沙箱资源,而 rootfs、 volume 和 cgroup 被视为容器资源。因此,我们为每个资源抽象了一个公共接口,并使用子类操作来对应不同子类型之间的差异。

在这里插入图片描述

Rust Async Runtime

相对于 Go 语言, Rust 在性能和资源消耗方面更胜一筹,在某些特定的场景下效率甚至优于 C++。同时, Rust 还能避免空指针,野指针,内存泄露,内存越界等一些列内存安全问题, 从而大幅减少了程序崩溃的频率,这些能力对于 Kata 这种偏底层的系统尤为重要。然而 ,Go 语言的优势在于内置的机制和库来支持编写并发程序,比如 goroutine,以此显著降低 CPU 和内存开销,尤其是对于具有大量 I/O 密集型任务的工作负载。我们为了既兼顾 Go 语言的并发和异步优势,又获得 Rust 的安全性和低开销特点,开发了 Async Rust Runtime。

如何支持 Async?

kata-runtime 由 TOKIO_RUNTIME_WORKER_THREADS 控制运行 OS 线程,默认为 2 个线程。对于TTRPC 和容器相关线程统一运行在 tokio 线程中,相关依赖需要切换到 Async,比如 Timer、File、Netlink 等。借助 Async 我们可以轻松支持 non-block io 和计时器。目前,我们仅将 Async 用于 kata-runtime。内置的 VMM 保留了 OS 线程, 这样可以确保线程是可控的。

参考文章

迈向kata 3.0(刘奖)

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐