这篇文章已经一年多了,较旧的文章可能包含过时的内容。请检查从发表以来,页面中的信息是否变得不正确。

Kubernetes 1.28:节点 podresources API 正式发布

作者:Francesco Romani (Red Hat)

译者:Wilson Wu (DaoCloud)

podresources API 是由 kubelet 提供的节点本地 API,它用于公开专门分配给容器的计算资源。随着 Kubernetes 1.28 的发布,该 API 现已正式发布。

它解决了什么问题?

kubelet 可以向容器分配独占资源,例如CPU,授予对完整核心的独占访问权限内存,包括内存区域或巨页。需要高性能或低延迟(或者两者都需要)的工作负载可以利用这些特性。kubelet 还可以将设备分配给容器。总的来说,这些支持独占分配的特性被称为“资源管理器(Resource Managers)”。

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

API 概述

podresources API 最初被提出是为了实现设备监控。为了支持监控代理,一个关键的先决条件是启用由 kubelet 执行的设备分配自省(Introspection)。API 的最初目标就是服务于此目的。API 的第一次迭代仅实现了一个函数 List,用于返回有关设备分配给容器的信息。该 API 由 multus CNIGPU 监控工具使用。

自推出以来,podresources API 扩大了其范围,涵盖了设备管理器之外的其他资源管理器。从 Kubernetes 1.20 开始,List API 还报告 CPU 核心和内存区域(包括巨页);在能够从系统中推断 CPU 和内存的位置时,API 还报告设备的 NUMA 位置。

在 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 提供,位于 kubelet 运行所在的同一节点上。在 Unix 风格的系统上,通过 Unix 域套接字提供端点;默认路径是 /var/lib/kubelet/pod-resources/kubelet.sock。在 Windows 上,通过命名管道提供端点;默认路径是 npipe://\\.\pipe\kubelet-pod-resources

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

在下面的 DaemonSet 示例清单中,包含一个假想的使用 podresources API 的监控代理:

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  # 仅作为样例
        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 驱动。请加入我们,与社区建立联系,并分享你对上述功能及其他功能的想法和反馈。我们期待你的回音!