裝置外掛
Kubernetes v1.26 [stable]
Kubernetes 提供了一個裝置外掛框架,你可以使用它向 Kubelet 宣告系統硬體資源。
供應商可以實現一個裝置外掛,你可以手動部署或作為 DaemonSet 部署,而不是自定義 Kubernetes 程式碼本身。目標裝置包括 GPU、高效能 NIC、FPGA、InfiniBand 介面卡以及其他可能需要供應商特定初始化和設定的類似計算資源。
裝置外掛註冊
kubelet 匯出 Registration
gRPC 服務
service Registration {
rpc Register(RegisterRequest) returns (Empty) {}
}
裝置外掛可以透過此 gRPC 服務向 kubelet 註冊自己。在註冊期間,裝置外掛需要傳送
- 其 Unix 套接字名稱。
- 其構建所針對的裝置外掛 API 版本。
- 它想要宣告的
ResourceName
。這裡的ResourceName
需要遵循 擴充套件資源命名方案,格式為vendor-domain/resourcetype
。(例如,NVIDIA GPU 被宣告為nvidia.com/gpu
。)
成功註冊後,裝置外掛會將它所管理的裝置列表傳送給 kubelet,然後 kubelet 負責將這些資源作為 kubelet 節點狀態更新的一部分,通告給 API 伺服器。例如,當裝置外掛向 kubelet 註冊 hardware-vendor.example/foo
並報告節點上有兩個健康的裝置後,節點狀態會更新,宣告該節點安裝並提供 2 個 “Foo” 裝置。
然後,使用者可以在 Pod 規約中請求裝置(參見 container
)。請求擴充套件資源的方式與管理其他資源的請求和限制類似,但有以下區別:
- 擴充套件資源僅支援整數資源,並且不能超額分配。
- 裝置不能在容器之間共享。
示例
假設一個 Kubernetes 叢集正在執行一個裝置外掛,該外掛在某些節點上通告資源 hardware-vendor.example/foo
。下面是一個 Pod 請求此資源來執行演示工作負載的示例:
---
apiVersion: v1
kind: Pod
metadata:
name: demo-pod
spec:
containers:
- name: demo-container-1
image: registry.k8s.io/pause:3.8
resources:
limits:
hardware-vendor.example/foo: 2
#
# This Pod needs 2 of the hardware-vendor.example/foo devices
# and can only schedule onto a Node that's able to satisfy
# that need.
#
# If the Node has more than 2 of those devices available, the
# remainder would be available for other Pods to use.
裝置外掛實現
裝置外掛的一般工作流程包括以下步驟:
初始化。在此階段,裝置外掛執行供應商特定的初始化和設定,以確保裝置處於就緒狀態。
該外掛啟動一個 gRPC 服務,該服務在主機路徑
/var/lib/kubelet/device-plugins/
下的 Unix 套接字上,實現了以下介面:service DevicePlugin { // GetDevicePluginOptions returns options to be communicated with Device Manager. rpc GetDevicePluginOptions(Empty) returns (DevicePluginOptions) {} // ListAndWatch returns a stream of List of Devices // Whenever a Device state change or a Device disappears, ListAndWatch // returns the new list rpc ListAndWatch(Empty) returns (stream ListAndWatchResponse) {} // Allocate is called during container creation so that the Device // Plugin can run device specific operations and instruct Kubelet // of the steps to make the Device available in the container rpc Allocate(AllocateRequest) returns (AllocateResponse) {} // GetPreferredAllocation returns a preferred set of devices to allocate // from a list of available ones. The resulting preferred allocation is not // guaranteed to be the allocation ultimately performed by the // devicemanager. It is only designed to help the devicemanager make a more // informed allocation decision when possible. rpc GetPreferredAllocation(PreferredAllocationRequest) returns (PreferredAllocationResponse) {} // PreStartContainer is called, if indicated by Device Plugin during registration phase, // before each container start. Device plugin can run device specific operations // such as resetting the device before making devices available to the container. rpc PreStartContainer(PreStartContainerRequest) returns (PreStartContainerResponse) {} }
注意
外掛無需為GetPreferredAllocation()
或PreStartContainer()
提供有用的實現。如果這些呼叫可用,則應在呼叫GetDevicePluginOptions()
返回的DevicePluginOptions
訊息中設定指示這些呼叫可用的標誌。kubelet
將始終在直接呼叫任何可選函式之前呼叫GetDevicePluginOptions()
以檢視哪些可選函式可用。外掛透過主機路徑
/var/lib/kubelet/device-plugins/kubelet.sock
上的 Unix 套接字向 kubelet 註冊自己。注意
工作流程的順序很重要。外掛必須在向 kubelet 註冊之前啟動 gRPC 服務,才能成功註冊。成功註冊後,裝置外掛以服務模式執行,在此期間它會持續監控裝置健康狀況並在任何裝置狀態變化時向 kubelet 報告。它還負責處理
Allocate
gRPC 請求。在Allocate
期間,裝置外掛可能會進行裝置特定的準備工作;例如,GPU 清理或 QRNG 初始化。如果操作成功,裝置外掛會返回一個AllocateResponse
,其中包含用於訪問已分配裝置的容器執行時配置。kubelet 會將此資訊傳遞給容器執行時。AllocateResponse
包含零個或多個ContainerAllocateResponse
物件。在這些物件中,裝置外掛定義了必須對容器定義進行的修改,以提供對裝置的訪問。這些修改包括:- 註解
- 裝置節點
- 環境變數
- 掛載點
- 完全限定的 CDI 裝置名稱
注意
裝置管理器處理完全限定的 CDI 裝置名稱要求為 kubelet 和 kube-apiserver 均啟用DevicePluginCDIDevices
功能門控。這在 Kubernetes v1.28 中作為 Alpha 功能新增,在 v1.29 中升級為 Beta,並在 v1.31 中升級為 GA。
處理 kubelet 重啟
裝置外掛應檢測 kubelet 重啟,並重新向新的 kubelet 例項註冊自己。新的 kubelet 例項在啟動時會刪除 /var/lib/kubelet/device-plugins
下所有現有的 Unix 套接字。裝置外掛可以監控其 Unix 套接字的刪除,並在發生此類事件時重新註冊自己。
裝置外掛和不健康的裝置
有時裝置會發生故障或關閉。在這種情況下,裝置外掛的責任是使用 ListAndWatchResponse
API 通知 kubelet 情況。
一旦裝置被標記為不健康,kubelet 將減少節點上該資源的可分配數量,以反映可用於排程新 Pod 的裝置數量。資源的容量數量不會改變。
分配給故障裝置的 Pod 將繼續分配給該裝置。通常情況下,依賴於該裝置的程式碼將開始失敗,如果 Pod 的 restartPolicy
不是 Always
,Pod 可能會進入 Failed 階段,否則會進入崩潰迴圈。
在 Kubernetes v1.31 之前,瞭解 Pod 是否與故障裝置關聯的方法是使用 PodResources API。
Kubernetes v1.31 [alpha]
(預設啟用:false)透過啟用功能門控 ResourceHealthStatus
,.status
中每個 Pod 的每個容器狀態都會新增 allocatedResourcesStatus
欄位。allocatedResourcesStatus
欄位報告分配給容器的每個裝置的健康資訊。
對於失敗的 Pod,或者你懷疑有故障的 Pod,你可以使用此狀態來了解 Pod 行為是否可能與裝置故障有關。例如,如果加速器報告過溫事件,allocatedResourcesStatus
欄位可能能夠報告此情況。
裝置外掛部署
你可以將裝置外掛部署為 DaemonSet、作為節點作業系統的包,或者手動部署。
規範目錄 /var/lib/kubelet/device-plugins
需要特權訪問,因此裝置外掛必須在特權安全上下文中執行。如果你將裝置外掛部署為 DaemonSet,/var/lib/kubelet/device-plugins
必須作為 卷 掛載到外掛的 PodSpec 中。
如果你選擇 DaemonSet 方式,你可以依賴 Kubernetes 來:將裝置外掛的 Pod 放置到節點上,在故障後重新啟動守護程序 Pod,並幫助自動化升級。
API 相容性
以前,版本控制方案要求裝置外掛的 API 版本與 Kubelet 的版本完全匹配。自此功能在 v1.12 升級到 Beta 版後,這不再是硬性要求。該 API 已版本化,並且自此功能升級到 Beta 版後一直保持穩定。因此,kubelet 升級應該無縫進行,但在穩定之前 API 可能仍然會發生變化,導致升級無法保證不中斷。
注意
儘管 Kubernetes 的裝置管理器元件是一個普遍可用的功能,但**裝置外掛 API** 並不穩定。有關裝置外掛 API 和版本相容性的資訊,請閱讀 裝置外掛 API 版本。作為專案,Kubernetes 建議裝置外掛開發人員:
- 關注未來版本中裝置外掛 API 的變化。
- 支援多個裝置外掛 API 版本以實現向後/向前相容性。
要在需要升級到具有更新裝置外掛 API 版本的 Kubernetes 版本的節點上執行裝置外掛,請在升級這些節點之前升級你的裝置外掛以支援這兩個版本。採用這種方法將確保在升級期間裝置分配的持續執行。
監控裝置外掛資源
Kubernetes v1.28 [stable]
為了監控裝置外掛提供的資源,監控代理需要能夠發現節點上正在使用的裝置集合,並獲取元資料以描述指標應與哪個容器關聯。Prometheus 監控代理暴露的指標應遵循 Kubernetes 觀測指導原則,使用 pod
、namespace
和 container
prometheus 標籤來識別容器。
kubelet 提供一個 gRPC 服務,用於發現正在使用的裝置並提供這些裝置的元資料。
// PodResourcesLister is a service provided by the kubelet that provides information about the
// node resources consumed by pods and containers on the node
service PodResourcesLister {
rpc List(ListPodResourcesRequest) returns (ListPodResourcesResponse) {}
rpc GetAllocatableResources(AllocatableResourcesRequest) returns (AllocatableResourcesResponse) {}
rpc Get(GetPodResourcesRequest) returns (GetPodResourcesResponse) {}
}
List
gRPC 端點
List
端點提供執行中的 Pod 資源的詳細資訊,例如獨佔分配的 CPU ID、裝置外掛報告的裝置 ID 以及這些裝置分配到的 NUMA 節點 ID。此外,對於基於 NUMA 的機器,它還包含為容器預留的記憶體和 Hugepages 資訊。
從 Kubernetes v1.27 開始,List
端點可以提供由 DynamicResourceAllocation
API 在 ResourceClaims
中分配的執行中 Pod 資源的資訊。從 Kubernetes v1.34 開始,此功能預設啟用。要停用此功能,必須使用以下標誌啟動 kubelet
:
--feature-gates=KubeletPodResourcesDynamicResources=false
// ListPodResourcesResponse is the response returned by List function
message ListPodResourcesResponse {
repeated PodResources pod_resources = 1;
}
// PodResources contains information about the node resources assigned to a pod
message PodResources {
string name = 1;
string namespace = 2;
repeated ContainerResources containers = 3;
}
// ContainerResources contains information about the resources assigned to a container
message ContainerResources {
string name = 1;
repeated ContainerDevices devices = 2;
repeated int64 cpu_ids = 3;
repeated ContainerMemory memory = 4;
repeated DynamicResource dynamic_resources = 5;
}
// ContainerMemory contains information about memory and hugepages assigned to a container
message ContainerMemory {
string memory_type = 1;
uint64 size = 2;
TopologyInfo topology = 3;
}
// Topology describes hardware topology of the resource
message TopologyInfo {
repeated NUMANode nodes = 1;
}
// NUMA representation of NUMA node
message NUMANode {
int64 ID = 1;
}
// ContainerDevices contains information about the devices assigned to a container
message ContainerDevices {
string resource_name = 1;
repeated string device_ids = 2;
TopologyInfo topology = 3;
}
// DynamicResource contains information about the devices assigned to a container by Dynamic Resource Allocation
message DynamicResource {
string class_name = 1;
string claim_name = 2;
string claim_namespace = 3;
repeated ClaimResource claim_resources = 4;
}
// ClaimResource contains per-plugin resource information
message ClaimResource {
repeated CDIDevice cdi_devices = 1 [(gogoproto.customname) = "CDIDevices"];
}
// CDIDevice specifies a CDI device information
message CDIDevice {
// Fully qualified CDI device name
// for example: vendor.com/gpu=gpudevice1
// see more details in the CDI specification:
// https://github.com/container-orchestrated-devices/container-device-interface/blob/main/SPEC.md
string name = 1;
}
注意
List
端點中 ContainerResources
中的 cpu_ids
對應於分配給特定容器的獨佔 CPU。如果目標是評估屬於共享池的 CPU,則 List
端點需要與 GetAllocatableResources
端點結合使用,如下所述:
- 呼叫
GetAllocatableResources
獲取所有可分配 CPU 的列表。 - 在系統中所有
ContainerResources
上呼叫GetCpuIds
。 - 從
GetAllocatableResources
呼叫中減去所有GetCpuIds
呼叫中的 CPU。
GetAllocatableResources
gRPC 端點
Kubernetes v1.28 [stable]
GetAllocatableResources 提供工作節點上最初可用資源的資訊。它比 kubelet 匯出到 APIServer 的資訊更多。
注意
GetAllocatableResources
僅應用於評估節點上的可分配資源。如果目標是評估空閒/未分配資源,則應與 List() 端點結合使用。GetAllocatableResources
獲得的結果將保持不變,除非暴露給 kubelet 的底層資源發生變化。這種情況很少發生,但當發生時(例如:熱插拔/熱拔插,裝置健康狀況變化),客戶端應呼叫 GetAlloctableResources
端點。
但是,在 CPU 和/或記憶體更新的情況下,呼叫 GetAllocatableResources
端點是不夠的,需要重新啟動 Kubelet 才能反映正確的資源容量和可分配性。
// AllocatableResourcesResponses contains information about all the devices known by the kubelet
message AllocatableResourcesResponse {
repeated ContainerDevices devices = 1;
repeated int64 cpu_ids = 2;
repeated ContainerMemory memory = 3;
}
ContainerDevices
暴露拓撲資訊,宣告裝置與哪些 NUMA 單元相關聯。NUMA 單元使用不透明的整數 ID 進行標識,該值與裝置外掛向 kubelet 註冊時報告的值一致。
gRPC 服務透過 Unix 套接字 /var/lib/kubelet/pod-resources/kubelet.sock
提供。裝置外掛資源的監控代理可以作為守護程序部署,也可以作為 DaemonSet 部署。規範目錄 /var/lib/kubelet/pod-resources
需要特權訪問,因此監控代理必須在特權安全上下文中執行。如果裝置監控代理作為 DaemonSet 執行,/var/lib/kubelet/pod-resources
必須作為 卷 掛載到裝置監控代理的 PodSpec 中。
注意
當從 DaemonSet 或任何其他作為容器部署在主機上的應用程式訪問 /var/lib/kubelet/pod-resources/kubelet.sock
並將套接字掛載為卷時,最好掛載目錄 /var/lib/kubelet/pod-resources/
而不是 /var/lib/kubelet/pod-resources/kubelet.sock
。這將確保在 kubelet 重啟後,容器能夠重新連線到此套接字。
容器掛載由引用套接字或目錄的 inode 管理,具體取決於掛載的內容。當 kubelet 重啟時,套接字被刪除並建立一個新套接字,而目錄保持不變。因此,套接字的原始 inode 變得不可用。目錄的 inode 將繼續工作。
Get
gRPC 端點
Kubernetes v1.34 [beta]
Get
端點提供有關正在執行的 Pod 資源的資訊。它暴露的資訊與 List
端點中描述的資訊類似。Get
端點需要正在執行的 Pod 的 PodName
和 PodNamespace
。
// GetPodResourcesRequest contains information about the pod
message GetPodResourcesRequest {
string pod_name = 1;
string pod_namespace = 2;
}
要停用此功能,你必須使用以下標誌啟動 kubelet 服務:
--feature-gates=KubeletPodResourcesGet=false
Get
端點可以提供與動態資源分配 API 分配的動態資源相關的 Pod 資訊。從 Kubernetes v1.34 開始,此功能預設啟用。要停用此功能,kubelet
必須使用以下標誌啟動:
--feature-gates=KubeletPodResourcesDynamicResources=false
裝置外掛與拓撲管理器整合
Kubernetes v1.27 [穩定]
拓撲管理器是 Kubelet 的一個元件,它允許以拓撲對齊的方式協調資源。為此,裝置外掛 API 已擴充套件為包含 TopologyInfo
結構。
message TopologyInfo {
repeated NUMANode nodes = 1;
}
message NUMANode {
int64 ID = 1;
}
希望利用拓撲管理器的裝置外掛可以在設備註冊時,連同裝置 ID 和裝置健康狀況一起,返回填充好的 TopologyInfo
結構。然後,裝置管理器將使用此資訊與拓撲管理器協商並做出資源分配決策。
TopologyInfo
支援將 nodes
欄位設定為 nil
或 NUMA 節點列表。這允許裝置外掛通告跨多個 NUMA 節點的裝置。
將 TopologyInfo
設定為 nil
或為給定裝置提供空的 NUMA 節點列表,表示裝置外掛對該裝置沒有 NUMA 親和性偏好。
裝置外掛為裝置填充的 TopologyInfo
結構示例
pluginapi.Device{ID: "25102017", Health: pluginapi.Healthy, Topology:&pluginapi.TopologyInfo{Nodes: []*pluginapi.NUMANode{&pluginapi.NUMANode{ID: 0,},}}}
裝置外掛示例
以下是一些裝置外掛實現的示例:
- Akri,讓你輕鬆暴露異構葉裝置(如 IP 攝像頭和 USB 裝置)。
- AMD GPU 裝置外掛
- 適用於通用 Linux 裝置和 USB 裝置的通用裝置外掛
- HAMi,用於異構 AI 計算虛擬化中介軟體(例如,NVIDIA、寒武紀、海光、天數、MThreads、昇騰、Metax)
- Intel 裝置外掛,用於 Intel GPU、FPGA、QAT、VPU、SGX、DSA、DLB 和 IAA 裝置
- 用於硬體輔助虛擬化的KubeVirt 裝置外掛
- NVIDIA GPU 裝置外掛,NVIDIA 官方裝置外掛,用於暴露 NVIDIA GPU 並監控 GPU 健康狀況
- 用於容器最佳化型作業系統 (Container-Optimized OS) 的NVIDIA GPU 裝置外掛
- RDMA 裝置外掛
- SocketCAN 裝置外掛
- Solarflare 裝置外掛
- SR-IOV 網路裝置外掛
- 用於 Xilinx FPGA 裝置的Xilinx FPGA 裝置外掛
下一步
- 瞭解如何使用裝置外掛排程 GPU 資源
- 瞭解如何在節點上宣告擴充套件資源
- 瞭解拓撲管理器
- 閱讀有關使用 Kubernetes 裝置外掛和 RuntimeClass 實現 TLS 入口硬體加速的資訊
- 閱讀更多關於 DRA 擴充套件資源分配的資訊
此頁面上的專案是指提供 Kubernetes 所需功能的第三方產品或專案。Kubernetes 專案的作者不對這些第三方產品或專案負責。有關更多詳細資訊,請參閱 CNCF 網站指南。
在提議新增額外第三方連結的更改之前,你應該閱讀內容指南。