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

Kubernetes 1.22:伺服器端套用功能移至 GA

伺服器端套用 (SSA) 已在 Kubernetes v1.22 版本中升級為 GA。GA 里程碑表示您可以依賴此功能及其 API,而無需擔心未來不相容的變更。GA 功能受到 Kubernetes 棄用政策的保護。

什麼是伺服器端套用?

伺服器端套用透過宣告式組態協助使用者和控制器管理其資源。伺服器端套用取代了「kubectl apply」實作的用戶端套用功能,並允許 kubectl 以外的工具/用戶端使用。伺服器端套用是一種新的合併演算法,以及欄位所有權追蹤,在 Kubernetes api-server 上執行。伺服器端套用啟用了衝突偵測等新功能,因此系統知道何時有兩個參與者嘗試編輯相同的欄位。請參閱伺服器端套用文件Beta 2 版本公告以取得更多資訊。

自 Beta 版以來的新功能?

Beta 2 版本以來,已新增子資源支援,且 client-go 和 Kubebuilder 都已新增對伺服器端套用的完整支援。這完成了控制器開發實務上所需的伺服器端套用功能。

子資源支援

伺服器端套用現在完全支援子資源,例如 statusscale。這對於控制器尤其重要,控制器通常負責寫入子資源。

client-go 中的伺服器端套用支援

先前,伺服器端套用只能從 client-go 類型用戶端使用 Patch 函數呼叫,且 PatchType 設定為 ApplyPatchType。現在,用戶端中包含 Apply 函數,以允許更直接且類型安全的方式呼叫伺服器端套用。每個 Apply 函數都採用「套用組態」類型作為引數,這是套用請求的結構化表示法。例如

import (
         ...
         v1ac "k8s.io/client-go/applyconfigurations/autoscaling/v1"
)

hpaApplyConfig := v1ac.HorizontalPodAutoscaler(autoscalerName, ns).
         WithSpec(v1ac.HorizontalPodAutoscalerSpec().
                  WithMinReplicas(0)
         )

return hpav1client.Apply(ctx, hpaApplyConfig, metav1.ApplyOptions{FieldManager: "mycontroller", Force: true})

請注意,在此範例中,HorizontalPodAutoscaler 是從「applyconfigurations」套件匯入的。每個「套用組態」類型都代表與對應 go 結構相同的 Kubernetes 物件種類,但其中所有欄位都是指標,使其成為選用,允許準確表示套用請求。例如,當上述範例中的套用組態封送處理為 YAML 時,會產生

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
    name: myHPA
    namespace: myNamespace
spec:
    minReplicas: 0

為了理解為何需要此功能,v1.HorizontalPodAutoscaler go 結構無法產生上述 YAML。以例如來說

hpa := v1.HorizontalPodAutoscaler{
         TypeMeta: metav1.TypeMeta{
                  APIVersion: "autoscaling/v1",
                  Kind:       "HorizontalPodAutoscaler",
         },
         ObjectMeta: ObjectMeta{
                  Namespace: ns,
                  Name:      autoscalerName,
         },
         Spec: v1.HorizontalPodAutoscalerSpec{
                  MinReplicas: pointer.Int32Ptr(0),
         },
}

上述程式碼嘗試宣告與先前範例中所示相同的套用組態,但封送處理為 YAML 時,會產生

kind: HorizontalPodAutoscaler
apiVersion: autoscaling/v1
metadata
  name: myHPA
  namespace: myNamespace
  creationTimestamp: null
spec:
  scaleTargetRef:
    kind: ""
    name: ""
  minReplicas: 0
  maxReplicas: 0

除其他事項外,其中包含 spec.maxReplicas 設定為 0。這幾乎肯定不是呼叫者的意圖 (預期的套用組態未說明 maxReplicas 欄位),並且可能對生產系統產生嚴重後果:它指示自動調整程式向下調整為零個 Pod。此處的問題源自於 go 結構包含必要欄位,如果未明確設定,則這些欄位為零值。go 結構適用於建立和更新作業,但與套用從根本上不相容,這就是我們引入產生的「套用組態」類型的原因。

「套用組態」也具有便利的 With<FieldName> 函數,可更輕鬆地建置套用請求。這允許開發人員設定欄位,而無需處理「套用組態」類型中的所有欄位都是指標的事實,並且使用 go 設定不方便。例如,MinReplicas: &0 不是合法的 go 程式碼,因此如果沒有 With 函數,開發人員將使用程式庫來解決此問題,例如 MinReplicas: pointer.Int32Ptr(0),但字串列舉 (例如 corev1.Protocol) 仍然是一個問題,因為通用程式庫無法支援它們。除了便利性之外,With 函數還可以將開發人員與底層表示法隔離,這使得底層表示法更安全地變更以支援未來的其他功能。

在控制器中使用伺服器端套用

無論您如何實作控制器,您都可以使用對伺服器端套用的新支援。但是,新的 client-go 支援讓在控制器中使用伺服器端套用變得更容易。

在撰寫新的控制器以使用伺服器端套用時,一個好的方法是讓控制器在每次協調該物件時重新建立物件的套用組態。這確保控制器完全協調其負責的所有欄位。控制器通常應透過在 ApplyOptions 中設定 Force: true 來無條件設定它們擁有的所有欄位。控制器也必須提供 FieldManager 名稱,該名稱對於從中呼叫套用的協調迴圈而言是唯一的。

當升級現有的控制器以使用伺服器端套用時,相同的方法通常也能很好地運作 - 將控制器遷移為在每次協調任何物件時重新建立套用組態。遺憾的是,控制器可能有多個程式碼路徑,這些路徑會根據各種條件更新物件的不同部分。像這樣將控制器遷移到伺服器端套用可能很冒險,因為如果控制器忘記在先前套用請求中包含的套用組態中包含任何欄位,則可能會意外刪除欄位。為了簡化此類型的遷移,client-go 套用支援提供了一種方法,可以將任何執行「讀取/就地修改/更新」(或修補) 工作流程的控制器協調程式碼替換為「擷取/就地修改/套用」工作流程。以下是新工作流程的範例

fieldMgr := "my-field-manager"
deploymentClient := clientset.AppsV1().Deployments("default")

// read, could also be read from a shared informer
deployment, err := deploymentClient.Get(ctx, "example-deployment", metav1.GetOptions{})
if err != nil {
  // handle error
}

// extract
deploymentApplyConfig, err := appsv1ac.ExtractDeployment(deployment, fieldMgr)
if err != nil {
  // handle error
}

// modify-in-place
deploymentApplyConfig.Spec.Template.Spec.WithContainers(corev1ac.Container().
	WithName("modify-slice").
	WithImage("nginx:1.14.2"),
)

// apply
applied, err := deploymentClient.Apply(ctx, deploymentApplyConfig, metav1.ApplyOptions{FieldManager: fieldMgr})

對於使用自訂資源定義 (CRD) 的開發人員,Kubebuilder 套用支援將提供相同的功能。文件將在 Kubebuilder 書籍可用時包含在其中。

伺服器端套用和 CustomResourceDefinitions

強烈建議所有自訂資源定義 (CRD) 都具有結構描述。沒有結構描述的 CRD 會被伺服器端套用視為非結構化資料。索引鍵被視為結構中的欄位,而清單則假設為原子。

指定結構描述的 CRD 能夠在結構描述中指定其他註釋。請參閱關於可用註釋完整清單的文件。

自 Beta 版以來的新註釋

預設值: 應用程式未明確表示感興趣的欄位值應預設為預設值。這可防止應用程式意外擁有預設欄位,而該預設欄位可能會導致與其他應用程式發生衝突。如果未指定,則預設值為 nil 或對應類型的 nil 等效值。

  • 用法:請參閱CRD 預設值文件以取得更多詳細資訊。
  • Golang: +default=<value>
  • OpenAPI 擴充功能:default: <value>

用於對應和結構的原子性

對應: 依預設,對應是細微的。不同的管理員能夠管理每個對應項目。它們也可以設定為原子,以便單一管理員擁有整個對應。

  • 用法:請參閱合併策略以取得更詳細的概述
  • Golang: +mapType=granular/atomic
  • OpenAPI 擴充功能:x-kubernetes-map-type: granular/atomic

結構: 依預設,結構是細微的,且個別應用程式可以擁有每個欄位。對於某些種類的結構,可能需要原子性。這在小型座標類結構中最為常見,例如欄位/物件/命名空間選取器、物件參考、RGB 值、端點 (通訊協定/連接埠配對) 等。

  • 用法:請參閱合併策略以取得更詳細的概述
  • Golang: +structType=granular/atomic
  • OpenAPI 擴充功能:x-kubernetes-map-type:atomic/granular

下一步?

在伺服器端套用之後,API Expression 工作群組的下一個重點是改善已發布 Kubernetes API 結構描述的表達性和大小。若要查看我們正在處理的完整項目清單,請加入我們的工作群組並參閱工作項目文件。

如何參與?

套用的工作群組是 wg-api-expression。它可在 slack 上透過 #wg-api-expression、透過郵寄清單取得,我們也會在每隔週的星期二上午 9:30 (PT) 在 Zoom 上開會。

我們也想藉此機會感謝所有參與將此升級為 GA 的貢獻者的辛勤工作

  • Andrea Nodari
  • Antoine Pelisse
  • Daniel Smith
  • Jeffrey Ying
  • Jenny Buckley
  • Joe Betz
  • Julian Modesto
  • Kevin Delgado
  • Kevin Wiesmüller
  • Maria Ntalla