本文已發布超過一年。較舊的文章可能包含過時的內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

Kubernetes 1.26:用於動態資源分配的 Alpha API

動態資源配置是一種用於請求資源的新 API。它是用於通用資源的持久卷 API 的泛化,使其能夠

  • 在不同的 Pod 和容器中存取相同的資源實例,
  • 將任意約束附加到資源請求,以獲得您正在尋找的確切資源,
  • 根據使用者提供的參數初始化資源。

第三方資源驅動程式負責解釋這些參數,以及追蹤和分配傳入請求的資源。

動態資源配置是一項Alpha 功能,僅在啟用 DynamicResourceAllocation 功能閘道resource.k8s.io/v1alpha1 API 群組 時啟用。有關詳細資訊,請參閱 --feature-gates--runtime-config kube-apiserver 參數。kube-scheduler、kube-controller-manager 和 kubelet 组件也都需要啟用功能閘道。

如果且僅當功能閘道啟用時,kube-scheduler 的預設配置才會啟用 DynamicResources 外掛程式。可能需要修改自訂配置以包含它。

一旦啟用動態資源配置,就可以安裝資源驅動程式來管理某些類型的硬體。Kubernetes 有一個用於端對端測試的測試驅動程式,但也可以手動運行。有關逐步說明,請參閱下方

API

新的 resource.k8s.io/v1alpha1 API 群組 提供了四種新類型

ResourceClass
定義哪個資源驅動程式處理某種類型的資源,並為其提供通用參數。ResourceClass 由叢集管理員在安裝資源驅動程式時建立。
ResourceClaim
定義工作負載所需的特定資源實例。由使用者建立(生命週期手動管理,可以在不同的 Pod 之間共享),或由控制平面根據 ResourceClaimTemplate 為個別 Pod 建立(自動生命週期,通常僅由一個 Pod 使用)。
ResourceClaimTemplate
定義用於建立 ResourceClaim 的規範和一些元資料。由使用者在部署工作負載時建立。
PodScheduling
由控制平面和資源驅動程式在為 Pod 分配 ResourceClaim 時在內部使用,以協調 Pod 排程。

ResourceClass 和 ResourceClaim 的參數儲存在單獨的物件中,通常使用安裝資源驅動程式時建立的 CRD 定義的類型。

啟用此 Alpha 功能後,Pod 的 spec 定義了 Pod 運行所需的 ResourceClaim:此資訊進入新的 resourceClaims 欄位。該列表中的條目引用 ResourceClaim 或 ResourceClaimTemplate。當引用 ResourceClaim 時,使用此 .spec 的所有 Pod(例如,在 Deployment 或 StatefulSet 內部)共享相同的 ResourceClaim 實例。當引用 ResourceClaimTemplate 時,每個 Pod 都會獲得自己的 ResourceClaim 實例。

對於在 Pod 內定義的容器,resources.claims 列表定義了該容器是否可以存取這些資源實例,這使得在同一 Pod 內部的一個或多個容器之間共享資源成為可能。例如,初始化容器可以在應用程式使用資源之前設定資源。

以下是虛構資源驅動程式的範例。將為此 Pod 建立兩個 ResourceClaim 物件,並且每個容器都可以存取其中一個。

假設安裝了名為 resource-driver.example.com 的資源驅動程式以及以下資源類別

apiVersion: resource.k8s.io/v1alpha1
kind: ResourceClass
name: resource.example.com
driverName: resource-driver.example.com

然後,終端使用者可以按如下方式分配兩個特定類型的 resource.example.com 資源

---
apiVersion: cats.resource.example.com/v1
kind: ClaimParameters
name: large-black-cats
spec:
  color: black
  size: large
---
apiVersion: resource.k8s.io/v1alpha1
kind: ResourceClaimTemplate
metadata:
  name: large-black-cats
spec:
  spec:
    resourceClassName: resource.example.com
    parametersRef:
      apiGroup: cats.resource.example.com
      kind: ClaimParameters
      name: large-black-cats
–--
apiVersion: v1
kind: Pod
metadata:
  name: pod-with-cats
spec:
  containers: # two example containers; each container claims one cat resource
  - name: first-example
    image: ubuntu:22.04
    command: ["sleep", "9999"]
    resources:
      claims:
      - name: cat-0
  - name: second-example
    image: ubuntu:22.04
    command: ["sleep", "9999"]
    resources:
      claims:
      - name: cat-1
  resourceClaims:
  - name: cat-0
    source:
      resourceClaimTemplateName: large-black-cats
  - name: cat-1
    source:
      resourceClaimTemplateName: large-black-cats

排程

與原生資源(例如 CPU 或 RAM)和 擴展資源(由裝置外掛程式管理,由 kubelet 宣告)相比,排程器不知道叢集中有哪些動態資源可用,也不知道如何將它們拆分以滿足特定 ResourceClaim 的需求。資源驅動程式負責處理此問題。驅動程式在為 ResourceClaim 保留資源後,將 ResourceClaim 標記為已分配。這也會告訴排程器叢集中實際可用的聲明資源在哪裡。

ResourceClaim 可以在建立 ResourceClaim 後立即分配資源(立即分配),而無需考慮哪些 Pod 將使用該資源。預設值(等待第一個消費者)是延遲分配,直到依賴 ResourceClaim 的 Pod 符合排程資格。具有兩種分配選項的這種設計與 Kubernetes 如何使用 PersistentVolume 和 PersistentVolumeClaim 處理儲存佈建類似。

在等待第一個消費者模式下,排程器會檢查 Pod 所需的所有 ResourceClaim。如果 Pod 有任何 ResourceClaim,排程器會建立 PodScheduling(一個特殊物件,代表 Pod 請求排程詳細資訊)。PodScheduling 與 Pod 具有相同的名稱和命名空間,並且 Pod 作為其所有者。排程器使用其 PodScheduling,將排程器認為適合 Pod 的節點告知負責這些 ResourceClaim 的資源驅動程式。資源驅動程式透過排除沒有足夠驅動程式資源的節點來回應。

一旦排程器獲得該資源資訊,它就會選擇一個節點並將該選擇儲存在 PodScheduling 物件中。然後,資源驅動程式根據相關的 ResourceClaim 分配資源,以便資源在選定的節點上可用。一旦資源分配完成,排程器就會嘗試將 Pod 排程到合適的節點。排程仍然可能在此時失敗;例如,同時可能有不同的 Pod 排程到同一個節點。如果發生這種情況,則可能會取消分配已分配的 ResourceClaim,以便能夠排程到不同的節點。

作為此過程的一部分,ResourceClaim 也會為 Pod 保留。目前,ResourceClaim 可以由單個 Pod 獨佔使用,也可以由無限數量的 Pod 使用。

一個關鍵功能是,除非 Pod 的所有資源都已分配和保留,否則 Pod 不會排程到節點。這避免了 Pod 排程到一個節點然後無法在那裡運行的情況,這種情況很糟糕,因為這種擱置中的 Pod 也會阻止所有其他為其預留的資源,例如 RAM 或 CPU。

限制

排程器外掛程式必須參與排程使用 ResourceClaim 的 Pod。透過設定 nodeName 欄位繞過排程器會導致 kubelet 拒絕啟動的 Pod,因為 ResourceClaim 未保留甚至未分配。未來可能會消除此限制

編寫資源驅動程式

動態資源分配驅動程式通常由兩個獨立但協調的組件組成:一個集中式控制器和一個節點本地 kubelet 外掛程式的 DaemonSet。集中式控制器與排程器協調所需的大部分工作可以由樣板程式碼處理。只需要自訂實際針對外掛程式擁有的 ResourceClass 分配 ResourceClaim 所需的業務邏輯。因此,Kubernetes 提供了以下套件,包括用於調用此樣板程式碼的 API 以及您可以實作以提供其自訂業務邏輯的 Driver 介面

同樣,樣板程式碼可以用於向 kubelet 註冊節點本地外掛程式,以及啟動 gRPC 伺服器以實作 kubelet 外掛程式 API。對於以 Go 撰寫的驅動程式,建議使用以下套件

驅動程式開發人員可以自行決定這兩個組件如何通訊。KEP 概述了一種使用 CRD 的方法

在 SIG Node 內部,我們也計劃提供一個完整的範例驅動程式,可以作為其他驅動程式的範本。

運行測試驅動程式

以下步驟直接從 Kubernetes 原始程式碼啟動本機單節點叢集。作為先決條件,您的叢集必須具有具有容器執行時的節點,該執行時支援容器裝置介面 (CDI)。例如,您可以運行 CRI-O v1.23.2 或更高版本。一旦 containerd v1.7.0 發布,我們預計您可以運行該版本或任何更高版本。在下面的範例中,我們使用 CRI-O。

首先,複製 Kubernetes 原始程式碼。在該目錄中,運行

$ hack/install-etcd.sh
...

$ RUNTIME_CONFIG=resource.k8s.io/v1alpha1 \
  FEATURE_GATES=DynamicResourceAllocation=true \
  DNS_ADDON="coredns" \
  CGROUP_DRIVER=systemd \
  CONTAINER_RUNTIME_ENDPOINT=unix:///var/run/crio/crio.sock \
  LOG_LEVEL=6 \
  ENABLE_CSI_SNAPSHOTTER=false \
  API_SECURE_PORT=6444 \
  ALLOW_PRIVILEGED=1 \
  PATH=$(pwd)/third_party/etcd:$PATH \
  ./hack/local-up-cluster.sh -O
...

要開始使用您的叢集,您可以打開另一個終端機/標籤並運行

$ export KUBECONFIG=/var/run/kubernetes/admin.kubeconfig

叢集啟動後,在另一個終端機中運行測試驅動程式控制器。必須為以下所有命令設定 KUBECONFIG

$ go run ./test/e2e/dra/test-driver --feature-gates ContextualLogging=true -v=5 controller

在另一個終端機中,運行 kubelet 外掛程式

$ sudo mkdir -p /var/run/cdi && \
  sudo chmod a+rwx /var/run/cdi /var/lib/kubelet/plugins_registry /var/lib/kubelet/plugins/
$ go run ./test/e2e/dra/test-driver --feature-gates ContextualLogging=true -v=6 kubelet-plugin

更改目錄的權限使得可以以普通使用者身份運行(以及在使用 delve 時)調試 kubelet 外掛程式,這很方便,因為它使用已經填充的 Go 快取。完成後,請記住使用 sudo chmod go-w 還原權限。或者,您也可以建置二進位檔案並以 root 身份運行。

現在叢集已準備好建立物件

$ kubectl create -f test/e2e/dra/test-driver/deploy/example/resourceclass.yaml
resourceclass.resource.k8s.io/example created

$ kubectl create -f test/e2e/dra/test-driver/deploy/example/pod-inline.yaml
configmap/test-inline-claim-parameters created
resourceclaimtemplate.resource.k8s.io/test-inline-claim-template created
pod/test-inline-claim created

$ kubectl get resourceclaims
NAME                         RESOURCECLASSNAME   ALLOCATIONMODE         STATE                AGE
test-inline-claim-resource   example             WaitForFirstConsumer   allocated,reserved   8s

$ kubectl get pods
NAME                READY   STATUS      RESTARTS   AGE
test-inline-claim   0/2     Completed   0          21s

測試驅動程式沒有做太多事情,它只設定 ConfigMap 中定義的環境變數。測試 Pod 轉儲環境,因此可以檢查日誌以驗證一切是否正常運作

$ kubectl logs test-inline-claim with-resource | grep user_a
user_a='b'

下一步

  • 有關設計的更多資訊,請參閱動態資源分配 KEP。
  • 閱讀官方 Kubernetes 文件中的動態資源分配
  • 您可以參與SIG Node 和/或 CNCF 容器協調裝置工作組
  • 您可以查看或評論動態資源分配的專案看板
  • 為了將此功能推向 Beta 版,我們需要硬體供應商的回饋,因此這裡呼籲採取行動:試用此功能,考慮它如何幫助解決您的使用者遇到的問題,並編寫資源驅動程式……