本文已发表一年多。较早的文章可能包含过时内容。请核实页面中的信息自发布以来是否已发生变化或不再正确。
使用 Kubernetes 设备插件和 RuntimeClass 在 Ingress Controller 中实现硬件加速 SSL/TLS 终止
摘要
Kubernetes Ingress 是一种将集群服务连接到集群外部世界的方式。为了正确地将流量路由到服务后端,集群需要一个 Ingress controller。Ingress controller 负责根据 Ingress API 对象的信息设置后端目标。实际流量通过一个代理服务器路由,该服务器负责负载均衡和 SSL/TLS(下文“SSL”指代 SSL 或 TLS)终止等任务。SSL 终止是一项 CPU 密集型操作,因为它涉及加密操作。为了将一些 CPU 密集型工作从 CPU 卸载出去,基于 OpenSSL 的代理服务器可以利用 OpenSSL Engine API 和专用加密硬件。这可以释放 CPU 周期用于其他任务,并提高代理服务器的整体吞吐量。
在这篇博客文章中,我们将展示使用最近创建的一些 Kubernetes 构建块(设备插件框架和 RuntimeClass)为运行 Ingress controller 代理的容器提供硬件加速加密是多么容易。最后,我们将提供一个参考设置,该设置使用基于 HAproxy 的 Ingress controller,并通过 Intel® QuickAssist Technology 卡进行加速。
关于代理、OpenSSL Engine 和加密硬件
代理服务器在 Kubernetes Ingress Controller 功能中起着至关重要的作用。它根据 Ingress 对象定义的路由将流量代理到后端。在高流量负载下,性能变得至关重要,特别是当代理涉及像 SSL 加密这样的 CPU 密集型操作时。
OpenSSL 项目提供了广泛采用的用于实现 SSL 协议的库。在 Kubernetes Ingress controller 常用的知名代理服务器中,Nginx 和 HAproxy 使用 OpenSSL。CNCF 毕业项目 Envoy 代理使用 BoringSSL,但似乎社区对将其作为 OpenSSL 的替代方案感兴趣。
OpenSSL SSL 协议库依赖于实现加密功能的 libcrypto。很长一段时间以来(首次引入于 0.9.6 版本),OpenSSL 提供了一个ENGINE 概念,允许将这些加密操作卸载到专用的加密加速硬件。后来,一个特殊的动态 ENGINE 使得加密硬件特定的部分可以实现为一个独立的加载模块,该模块可以在 OpenSSL 代码库之外开发并单独分发。从应用程序的角度来看,这也很理想,因为它们不需要知道如何使用硬件的细节,并且当硬件可用时可以加载/使用硬件特定的模块。
正如之前讨论的,基于硬件的加密可以通过在 SSL 操作中进行硬件加速处理来显著提高云应用程序的性能,并且可以提供其他加密服务,如密钥/随机数生成。云可以使用动态 ENGINE 轻松地使硬件可用,并且存在多个可加载模块实现,例如 CloudHSM、IBMCA 或 QAT Engine。
对于云部署来说,理想的情况是将这些模块作为容器工作负载的一部分进行分发。工作负载将被调度到一个提供模块所需底层硬件的节点上。另一方面,无论加密加速硬件是否可用,工作负载都应该以相同的方式运行,并且无需修改代码。OpenSSL 动态 engine 实现了这一点。下面的图 1 以典型的 Ingress Controller 容器为例说明了这两种场景。红色的框表示启用加密硬件 engine 的容器与“标准”容器之间的区别。值得指出的是,显示的配置更改不一定需要容器的另一个版本,因为配置可以通过例如 ConfigMaps 进行管理。

图 1. Ingress controller 容器示例
硬件资源与隔离
为了能够部署依赖硬件的工作负载,Kubernetes 提供了出色的扩展和配置机制。让我们深入了解 Kubernetes 的设备插件框架(1.14 中为 Beta)和 RuntimeClass(1.14 中为 Beta),并学习如何利用它们向工作负载暴露加密硬件。
设备插件框架于 Kubernetes 1.8 中首次引入,它为硬件供应商提供了一种向 Kubelets 注册和分配节点硬件资源的方式。插件实现了特定于硬件的初始化逻辑和资源管理。Pod 可以在其 PodSpec 中请求硬件资源,这也能保证 Pod 被调度到能够提供这些资源的节点上。
容器的设备资源分配并非易事。对于涉及安全的应用程序,硬件级别的隔离至关重要。基于 PCIe 的加密加速设备功能可以受益于 IO 硬件虚拟化,通过 I/O 内存管理单元 (IOMMU) 来提供隔离:设备所属的 IOMMU group 为工作负载提供隔离的资源(假设加密卡不与其他设备共享 IOMMU group)。如果 PCIe 设备支持单根 I/O 虚拟化 (SR-IOV) 规范,隔离资源的数量可以进一步增加。SR-IOV 允许 PCIe 设备进一步分割成虚拟功能 (VF),这些功能源自物理功能 (PF) 设备,并且每个功能都属于自己的 IOMMU group。为了将这些通过 IOMMU 隔离的设备功能暴露给用户空间和容器,宿主机内核应该将它们绑定到特定的设备驱动程序。在 Linux 中,该驱动程序是 vfio-pci,它通过用户空间中的字符设备使每个设备可用。内核 vfio-pci 驱动程序使用一种称为 PCI passthrough 的机制,为用户空间应用程序提供了对 PCIe 设备和功能的直接、由 IOMMU 支持的访问。用户空间框架,如数据平面开发工具包 (DPDK),可以利用此接口。此外,虚拟机 (VM) 管理程序可以将这些用户空间设备节点提供给 VM,并将它们作为 PCI 设备暴露给客户机内核。假定客户机内核的支持,VM 可以获得接近原生的对底层宿主机设备的直接高性能访问。
为了向 Kubernetes 宣传这些设备资源,我们可以有一个简单的 Kubernetes 设备插件,它运行初始化(即绑定),调用 kubelet 的 Registration
gRPC 服务,并实现 kubelet 调用的 DevicePlugin gRPC 服务,例如,在 Pod 创建时 Allocate
资源。
设备分配与 Pod 部署
此时,您可能会问容器可以使用 VFIO 设备节点做什么?答案将在我们首先快速了解 Kubernetes RuntimeClass 后揭晓。
创建 Kubernetes RuntimeClass 是为了更好地控制和配置集群中提供的各种运行时(一篇较早的博客文章详细介绍了其需求、状态和路线图)。本质上,RuntimeClass 为集群用户提供了更好的工具,以选择和使用最适合 Pod 用例的运行时。
OCI 兼容的 Kata Containers 运行时为工作负载提供了硬件虚拟化的隔离层。除了工作负载隔离外,Kata Containers 虚拟机还有一个额外的好处是,由设备插件 `Allocate` 分配的 VFIO 设备可以作为硬件隔离的设备直通给容器。唯一的要求是 Kata Containers 内核启用了对暴露设备的驱动支持。
这就是为容器工作负载启用硬件加速加密所需的全部内容。总结一下:
- 集群需要在提供硬件的节点上运行一个设备插件
- 设备插件使用 VFIO 驱动将硬件暴露给用户空间
- Pod 在 PodSpec 中请求设备资源并指定 Kata Containers 作为 RuntimeClass
- 容器包含硬件适配库和 OpenSSL engine 模块
图 2 展示了使用前面所示的容器 A 的整体设置。

图 2. 部署概览
参考设置
最后,我们描述了必要的构建块和步骤,用于构建图 2 中描述的功能性设置,该设置使用 Intel® QuickAssist Technology (QAT) PCIe 设备,能够在 Ingress Controller 中启用硬件加速的 SSL 终止。需要注意的是,用例不限于 Ingress Controller,而是任何基于 OpenSSL 的工作负载都可以被加速。
集群配置
- Kubernetes 1.14 (`RuntimeClass` 和 `DevicePlugin` 特性门控已启用 (在 1.14 中都为 `true`))
- 支持 RuntimeClass 的运行时并已配置 Kata Containers
主机配置
- 已安装 Intel® QAT 驱动版本及其内核驱动,适用于主机内核和 Kata Containers 内核(或作为可加载模块安装在根文件系统上)
- QAT 设备插件 DaemonSet 已部署
Ingress Controller 配置与部署
- HAproxy-ingress Ingress Controller 在一个修改过的容器中,该容器包含
- QAT HW HAL 用户空间库(Intel® QAT 软件版本的一部分)和
- 内置的 OpenSSL QAT Engine
- 用于启用 QAT engine 的 Haproxy-ingress ConfigMap
ssl-engine=”qat”
ssl-mode-async=true
- Haproxy-ingress 部署 `.yaml` 文件,用于
- 请求 `qat.intel.com: n` 资源
- 请求 `runtimeClassName: kata-containers`(名称值取决于集群配置)
- (为每个请求的设备资源准备 QAT 设备配置文件,并在容器中提供已配置 OpenSSL engine 的文件)
构建块准备就绪后,可以按照TLS 终止示例中的步骤,测试硬件加速的 SSL/TLS。为了验证硬件是否被使用,您可以检查主机上的 `/sys/kernel/debug/*/fw_counters` 文件,因为这些文件会随 Intel® QAT 固件更新而变化。
使用 Haproxy-ingress 和 HAproxy 是因为 HAproxy 可以直接配置使用 OpenSSL engine,使用 `ssl-engine
总结与展望
在这篇博客文章中,我们展示了如何使用 Kubernetes Device Plugins 和 RuntimeClass 为 Pod 中的应用程序提供隔离的硬件访问,以将加密操作卸载到硬件加速器。硬件加速器可用于加速加密操作,并为其他任务节省 CPU 周期。我们使用 HAproxy 演示了此设置,HAproxy 已支持使用 OpenSSL 进行异步加密卸载。
我们团队的下一步是为 Envoy 重复相同的过程(使用基于 OpenSSL 并构建为扩展的 TLS 传输套接字)。此外,我们正在努力增强 Envoy,使其能够将 BoringSSL 异步私钥操作卸载到加密加速硬件。欢迎任何审查反馈或帮助!
当将加密处理卸载到专用加速器时,您的加密应用程序可以为其他任务节省多少 CPU 周期?