本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
Kubernetes 1.22:伺服器端應用進入 GA 階段
服務端應用(Server-side Apply,SSA)已在 Kubernetes v1.22 版本中晉升為 GA(正式釋出)。GA 里程碑意味著您可以依賴該功能及其 API,而無需擔心未來不相容的更改。GA 功能受 Kubernetes 棄用策略的保護。
什麼是服務端應用?
服務端應用幫助使用者和控制器透過宣告式配置管理其資源。服務端應用將“kubectl apply”實現的客戶端應用功能替換為服務端實現,允許除 kubectl 之外的工具/客戶端使用。服務端應用是一種新的合併演算法,以及在 Kubernetes api-server 上執行的欄位所有權跟蹤。服務端應用啟用了衝突檢測等新功能,因此係統知道兩個參與者何時嘗試編輯同一欄位。有關更多資訊,請參閱服務端應用文件和Beta 2 釋出公告。
自 Beta 版以來有什麼新功能?
自Beta 2 釋出以來,已添加了對子資源的支援,並且 client-go 和 Kubebuilder 都添加了對服務端應用的全面支援。這完善了控制器開發所需的服務端應用功能。
支援子資源
服務端應用現在完全支援子資源,如status
和scale
。這對於通常負責寫入子資源的控制器來說尤為重要。
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 struct 相同的 Kubernetes 物件型別,但所有欄位都是指標以使其可選,從而允許準確表示應用請求。例如,當上述示例中的應用配置被整理為 YAML 時,它會生成
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: myHPA
namespace: myNamespace
spec:
minReplicas: 0
要理解為什麼需要這樣做,上面的 YAML 無法由 v1.HorizontalPodAutoscaler go struct 生成。例如:
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 struct 包含必需欄位,如果未明確設定,這些欄位的值為零。go struct 對於建立和更新操作按預期工作,但與應用從根本上不相容,這就是我們引入生成的“應用配置”型別的原因。
“應用配置”還具有方便的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 表示式工作組的下一個重點是提高已釋出的 Kubernetes API 模式的表達能力和大小。要檢視我們正在處理的完整專案列表,請加入我們的工作組並參閱工作專案文件。
如何參與?
應用工作組是 wg-api-expression。它在 Slack #wg-api-expression 上可用,透過郵件列表,我們還每隔一個星期二在太平洋時間上午 9:30 在 Zoom 上開會。
我們還要藉此機會感謝所有貢獻者的辛勤工作,使這次晉升為 GA 成為可能
- Andrea Nodari
- Antoine Pelisse
- Daniel Smith
- Jeffrey Ying
- Jenny Buckley
- Joe Betz
- Julian Modesto
- Kevin Delgado
- Kevin Wiesmüller
- Maria Ntalla