本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。

使用 Kubernetes Device Plugins 和 RuntimeClass 在 Ingress 控制器中实现硬件加速的 SSL/TLS 终止

摘要

Kubernetes Ingress 是一种将集群服务连接到集群外部世界的方式。为了正确地将流量路由到服务后端,集群需要一个 Ingress 控制器。Ingress 控制器负责根据 Ingress API 对象的 S信息为后端设置正确的目的地。实际流量通过代理服务器路由,代理服务器负责负载均衡和 SSL/TLS 终止(下文“SSL”指 SSL 或 TLS)。由于涉及加密操作,SSL 终止是 CPU 密集型操作。为了将一些 CPU 密集型工作从 CPU 中卸载,基于 OpenSSL 的代理服务器可以利用 OpenSSL Engine API 和专用加密硬件。这可以释放 CPU 周期用于其他任务,并提高代理服务器的整体吞吐量。

在这篇博文中,我们将展示如何使用最近创建的一些 Kubernetes 构建块(设备插件框架和 RuntimeClass)轻松地为运行 Ingress 控制器代理的容器提供硬件加速加密。最后,将给出一个使用 HAProxy 기반 Ingress 控制器并使用 Intel® QuickAssist Technology 卡进行加速的参考设置。

关于代理、OpenSSL Engine 和加密硬件

代理服务器在 Kubernetes Ingress Controller 功能中扮演着至关重要的角色。它根据 Ingress 对象的路由将流量代理到后端。在繁重的流量负载下,性能变得至关重要,特别是当代理涉及 CPU 密集型操作(如 SSL 加密)时。

OpenSSL 项目提供了广泛采用的库来实现 SSL 协议。在 Kubernetes Ingress 控制器常用的代理服务器中,Nginx 和 HAProxy 使用 OpenSSL。CNCF 毕业的 Envoy 代理使用 BoringSSL,但社区似乎对将 OpenSSL 作为其替代方案感兴趣,详见此处

OpenSSL SSL 协议库依赖于实现加密功能的 libcrypto。OpenSSL 提供了一个 ENGINE 概念(首次在 0.9.6 版本中引入)已经有一段时间了,它允许将这些加密操作卸载到专用加密加速硬件。后来,一个特殊的 *动态* ENGINE 使加密硬件的特定部分可以在独立的可加载模块中实现,该模块可以在 OpenSSL 代码库之外开发并单独分发。从应用程序的角度来看,这也是理想的,因为它们不需要知道如何使用硬件的细节,并且当硬件可用时,硬件特定的模块可以被加载/使用。

正如所讨论的,基于硬件的加密可以极大地提高云应用程序的性能,因为它在 SSL 操作中实现了硬件加速处理,并且还可以提供其他加密服务,如密钥/随机数生成。云可以使用动态 ENGINE 轻松提供硬件,并且存在多个可加载模块实现,例如 CloudHSMIBMCAQAT Engine

对于云部署,理想的情况是将这些模块作为容器工作负载的一部分进行交付。工作负载将在提供模块所需底层硬件的节点上进行调度。另一方面,无论加密加速硬件是否可用,工作负载都应以相同的方式运行,无需修改代码。OpenSSL 动态引擎实现了这一点。下图 1 使用典型的 Ingress Controller 容器作为示例说明了这两种情况。红色框表示启用加密硬件引擎的容器与“标准”容器之间的差异。值得指出的是,所显示的配置更改不一定需要另一个版本的容器,因为配置可以通过 ConfigMaps 等方式进行管理。

Figure 1. Examples of Ingress controller containers

图 1. Ingress 控制器容器示例

硬件资源和隔离

为了部署具有硬件依赖性的工作负载,Kubernetes 提供了出色的扩展和可配置机制。让我们更深入地了解 Kubernetes 设备插件框架(1.14 中的 Beta 版)和 RuntimeClass(1.14 中的 Beta 版),并了解如何利用它们将加密硬件暴露给工作负载。

设备插件框架最初在 Kubernetes 1.8 中引入,它为硬件供应商提供了一种将节点硬件资源注册和分配给 Kubelet 的方式。插件实现硬件特定的初始化逻辑和资源管理。Pod 可以在其 PodSpec 中请求硬件资源,这也可以保证 Pod 在能够提供这些资源的节点上进行调度。

容器的设备资源分配并非易事。对于处理安全性的应用程序来说,硬件级别隔离至关重要。基于 PCIe 的加密加速设备功能可以通过 I/O 内存管理单元 (IOMMU) 实现 IO 硬件虚拟化,从而提供隔离:设备所属的 *IOMMU 组* 为工作负载提供隔离资源(假设加密卡不与其他设备共享 IOMMU 组)。如果 PCIe 设备支持单根 I/O 虚拟化 (SR-IOV) 规范,则可以进一步增加隔离资源的数量。SR-IOV 允许 PCIe 设备进一步拆分为 *虚拟功能* (VF),这些虚拟功能源自 *物理功能* (PF) 设备,并且每个功能都属于自己的 IOMMU 组。为了将这些 IOMMU 隔离的设备功能暴露给用户空间和容器,主机内核应将它们绑定到特定的设备驱动程序。在 Linux 中,此驱动程序是 vfio-pci,它通过用户空间中的字符设备使每个设备可用。内核 vfio-pci 驱动程序使用一种称为 *PCI 直通* 的机制,为用户空间应用程序提供对 PCIe 设备和功能的直接、IOMMU 支持的访问。该接口可以被用户空间框架(例如数据平面开发套件 (DPDK))利用。此外,虚拟机 (VM) 管理程序可以将这些用户空间设备节点提供给 VM,并将它们作为 PCI 设备暴露给来宾内核。假设来宾内核提供支持,VM 可以获得接近原生性能的直接访问底层主机设备。

为了向 Kubernetes 宣传这些设备资源,我们可以有一个简单的 Kubernetes 设备插件,它运行初始化(即绑定),调用 kubelet 的 `Registration` gRPC 服务,并实现 kubelet 调用以在 Pod 创建时 `Allocate` 资源等的 DevicePlugin gRPC 服务。

设备分配与 Pod 部署

此时,您可能会问容器可以使用 VFIO 设备节点做什么?答案将在我们快速了解 Kubernetes RuntimeClass 之后揭晓。

Kubernetes RuntimeClass 的创建旨在更好地控制和配置集群中各种 *运行时* (早期的博客文章详细介绍了其需求、状态和路线图)。本质上,RuntimeClass 为集群用户提供了更好的工具来选择和使用最适合 Pod 用例的运行时。

OCI 兼容的 Kata 容器运行时为工作负载提供硬件虚拟化隔离层。除了工作负载隔离之外,Kata 容器虚拟机还有一个额外的优势,即设备插件 `Allocate` 的 VFIO 设备可以作为硬件隔离设备直通给容器。唯一的要求是 Kata 容器内核必须启用暴露设备的驱动程序。

这就是为容器工作负载启用硬件加速加密所需要的一切。总结如下:

  1. 集群需要一个设备插件,运行在提供硬件的节点上
  2. 设备插件使用 VFIO 驱动程序将硬件暴露给用户空间
  3. Pod 在 PodSpec 中请求设备资源和 Kata Containers 作为 RuntimeClass
  4. 容器包含硬件适配库和 OpenSSL 引擎模块

图 2 显示了使用前面示例中容器 A 的整体设置。

Figure 2. Deployment overview

图 2. 部署概览

参考设置

最后,我们描述了构建图 2 中功能设置所需的构建块和步骤,该设置使用 Intel® QuickAssist Technology (QAT) PCIe 设备在 Ingress 控制器中实现硬件加速 SSL 终止。需要注意的是,用例不仅限于 Ingress 控制器,任何基于 OpenSSL 的工作负载都可以加速。

集群配置

  • Kubernetes 1.14(已启用 `RuntimeClass` 和 `DevicePlugin` 特性门控(在 1.14 中均为 `true`))
  • RuntimeClass 就绪运行时和 Kata 容器已配置

主机配置

  • 已安装 QAT 设备驱动程序版本,用于主机内核和 Kata 容器内核(或作为可加载模块安装在根文件系统上)
  • QAT 设备插件 DaemonSet 已部署

Ingress 控制器配置和部署

  • HAproxy-ingress Ingress 控制器在一个修改过的容器中,该容器具有
    • QAT 硬件 HAL 用户空间库(Intel® QAT 软件版本的一部分)和
    • 内置的 OpenSSL QAT 引擎
  • Haproxy-ingress ConfigMap 用于启用 QAT 引擎使用
    • ssl-engine=”qat”
    • ssl-mode-async=true
  • Haproxy-ingress 部署 `yaml` 文件用于
    • 请求 `qat.intel.com: n` 资源
    • 请求 `runtimeClassName: kata-containers` (名称值取决于集群配置)
  • (容器中为每个请求的设备资源提供已配置 OpenSSL 引擎的 QAT 设备配置文件)

一旦构建块可用,可以通过遵循 TLS 终止示例步骤来测试硬件加速的 SSL/TLS。为了验证硬件是否被使用,您可以检查主机上的 `/sys/kernel/debug/*/fw_counters` 文件,因为它们会通过 Intel® QAT 固件进行更新。

使用 Haproxy-ingress 和 HAProxy 是因为 HAProxy 可以直接配置为使用 OpenSSL 引擎,只需使用 `ssl-engine [algo ALGOs]` 配置标志,而无需修改全局 openssl 配置文件。此外,HAProxy 可以使用异步调用(通过 `ssl-mode-async`)卸载已配置的算法,以进一步提高性能。

行动呼吁

在这篇博文中,我们展示了如何使用 Kubernetes 设备插件和 RuntimeClass 为 Pod 中的应用程序提供隔离的硬件访问,以将加密操作卸载到硬件加速器。硬件加速器可用于加速加密操作,并为其他任务节省 CPU 周期。我们使用 HAProxy 演示了该设置,HAProxy 已经支持使用 OpenSSL 进行异步加密卸载。

我们团队的下一步工作是为 Envoy 重复同样的操作(使用基于 OpenSSL 的 TLS 传输套接字作为扩展)。此外,我们正在努力增强 Envoy,使其能够将 BoringSSL 异步私钥操作卸载到加密加速硬件。欢迎任何评审反馈或帮助!

当将加密处理卸载到专用加速器时,您的加密应用程序可以为其他任务节省多少 CPU 周期?