本文已超过一年。较旧的文章可能包含过时内容。请检查页面中的信息自发布以来是否已不再准确。

Kubernetes 1.28: Node podresources API 晋升至正式可用 (GA)

podresources API 是 kubelet 在节点本地提供的一个 API,它暴露了专门分配给容器的计算资源。随着 Kubernetes 1.28 版本的发布,该 API 现已正式发布(Generally Available)。

它解决了什么问题?

kubelet 可以为容器分配专属资源,例如 CPU,授予对完整核心的独占访问权限,或 内存,无论是区域还是大页。需要高性能或低延迟(或两者兼备)的工作负载会利用这些特性。kubelet 还可以将 设备分配给容器。总的来说,这些实现专属分配的功能被称为“资源管理器”。

如果没有 podresources 这样的 API,了解资源分配的唯一可能方式是读取资源管理器使用的状态文件。虽然这是出于必要而为之,但这种方法的问题在于,这些文件的路径和格式都是内部实现细节。尽管这些细节非常稳定,但项目保留了随意更改它们的权利。因此,消费状态文件内容的方法既脆弱又不被支持,建议正在这样做的项目考虑迁移到 podresources API 或其他受支持的 API。

API 概述

podresources API 最初被提议用于启用设备监控。为了启用监控代理,一个关键的前提是能够对设备分配进行自省(introspection),这由 kubelet 执行。满足这一目的是该 API 的最初目标。该 API 的第一个迭代版本只实现了一个函数,即 List,用于返回有关设备分配给容器的信息。该 API 被 multus CNIGPU 监控工具使用。

自诞生以来,podresources API 的范围有所增加,除了设备管理器外,还涵盖了其他资源管理器。从 Kubernetes 1.20 开始,List API 也报告 CPU 核心和内存区域(包括大页);该 API 还报告设备的 NUMA 本地性(locality),而 CPU 和内存的本地性可以从系统中推断出来。

在 Kubernetes 1.21 中,该 API 增加了 GetAllocatableResources 函数。这个新的 API 补充了现有的 List API,并使监控代理能够确定未分配的资源,从而支持基于 podresources API 构建的新功能,例如 NUMA 感知调度器插件

最后,在 Kubernetes 1.27 中,引入了另一个函数 Get,以便更友好地与 CNI meta-plugins 交互,从而更容易地访问分配给特定 Pod 的资源,而不必筛选节点上所有 Pod 的资源。Get 函数目前处于 Alpha 级别。

使用 API

podresources API 由 kubelet 在运行它的同一节点上本地提供服务。在 Unix 类系统上,端点通过 Unix 域套接字提供;默认路径是 /var/lib/kubelet/pod-resources/kubelet.sock。在 Windows 上,端点通过命名管道提供;默认路径是 npipe://\\.\pipe\kubelet-pod-resources

为了让容器化的监控应用消费该 API,应将套接字挂载到容器内部。一个好的做法是挂载 podresources 套接字端点所在的目录,而不是直接挂载套接字文件。这将确保在 kubelet 重启后,容器化监控应用能够重新连接到套接字。

一个假设的监控代理消费 podresources API 并作为 DaemonSet 部署的示例清单如下:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: podresources-monitoring-app
  namespace: monitoring
spec:
  selector:
    matchLabels:
      name: podresources-monitoring
  template:
    metadata:
      labels:
        name: podresources-monitoring
    spec:
      containers:
      - args:
        - --podresources-socket=unix:///host-podresources/kubelet.sock
        command:
        - /bin/podresources-monitor
        image: podresources-monitor:latest  # just for an example
        volumeMounts:
        - mountPath: /host-podresources
          name: host-podresources
      serviceAccountName: podresources-monitor
      volumes:
      - hostPath:
          path: /var/lib/kubelet/pod-resources
          type: Directory
        name: host-podresources

我希望您发现以编程方式使用 podresources API 很直接。kubelet API 包提供了协议文件和 Go 类型定义;然而,项目目前尚未提供客户端包,并且现有代码不应直接使用。建议 的方法是在您的项目中重新实现客户端,复制代码中的相关函数,例如 multus 项目正在这样做

在操作消费 podresources API 的容器化监控应用时,有几点值得强调,以防止出现“陷阱”时刻:

  • 即使该 API 按设计仅暴露数据,并且不允许客户端修改 kubelet 状态,但 gRPC 请求/响应模型要求对 podresources API 套接字具有读写访问权限。换句话说,不可能将容器挂载限制为 ReadOnly
  • 允许多个客户端连接到 podresources 套接字并消费该 API,因为它是一个无状态的 API。
  • kubelet 具有 内置的速率限制,以减轻来自行为不当或恶意消费者的本地拒绝服务攻击。API 的消费者必须容忍服务器返回的速率限制错误。目前的速率限制是硬编码且全局的,因此行为不当的客户端可能会消耗所有配额,并可能饿死正常行为的客户端。

未来增强功能

出于历史原因,podresources API 的规范不如典型的 Kubernetes API(例如 Kubernetes HTTP API 或容器运行时接口)精确。这导致在某些极端情况下行为不明确。目前正在 努力纠正这种状况,并制定更精确的规范。

动态资源分配 (DRA) 基础设施是对资源管理的重大改革。与 podresources API 的集成 正在进行中。

目前正在 努力 推荐或创建一个可供使用的参考客户端包。

参与其中

此功能由 SIG Node 推动。请加入我们,与社区联系,并分享您对上述功能及其他方面的想法和反馈。我们期待您的来信!