在kubernetes生態中,通過自定義CRD(CustomResourceDefinition)來擴展自定義資源,擴展集群的功能。通過執行kubectl get crd來獲取kubernetes集群中安裝的CRD資源,CRD擴展方式有效的擴展kubernetes生態。
在對資源定義的時候,通過GVK(Group-Version-Kind)來唯一的表示一種資源類型,可以看到如下的yaml中Deployment這個類型對應的Group為apps, 版本是v1
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
labels:
app.kubernetes.io/component: manager
name: project-controller-manager
namespace: default
在創建CRD的時候,需要定義一個版本,例如v1beta1,所有自定義資源對象最初都將存儲在這個版本中,所有的client將會使用v1beta1 版本的API。隨著資源對象的演進,會引入其他新的版本,例如v1beta2、v1、v2beta1、v2beta2等等,等某些api對象版本成熟,將會將歷史版本的api對象設置成廢棄的狀態,最終移除對于廢棄api對象的支持。對應的client去訪問和操作api對象的時候需要根據不同版本的api去做調整,下面的內容是kubernetes中針對自定義CRD資源如何去做多版本的管理以及kubebuilder框架為我們提供了那些機制完成多版本資源的管理。
CRD資源支持對象支持多個版本
CustomResourceDefinition定義的時候,可以在spec.versions中定義多個版本的對象,例如可以自定義CronJob資源存在三個版本v1beta1、v1、v2beta1。
資源對象的版本可以三個狀態
使用中:該版本的資源定義可以被使用
廢棄狀態:該版本的資源定義仍然可以被使用,但是已經處于不推薦使用狀態,在未來將會被移除,處于該狀態的資源對象,需要將其升級到新版本的對象
移除狀態:該版本的資源對象已經無法被訪問和使用
資源對象版本的管理可以參考kubernetes api管理規范去規劃CRD資源對象的管理。Kubernetes 是一個 API 驅動的系統,API的版本號通常用于描述API的成熟階段。
v1
正式發布(Generally available,GA,穩定版本)
v1beta1
Beta (預發布)
v1alpha1
Alpha (試驗性)
不同版本對應的廢棄和移除策略也是不一樣的, 當某個API的實現達到一個新的GA穩定版本時(如v2),舊的GA版本(如v1)和Beta版本(例如v2beta1)將逐漸被廢棄,Kubernetes建議廢棄的時間如下。
對于舊的GA版本(如v1),Kubernetes建議廢棄的時間應不少于12個月或3個大版本Release的時間,選擇最長的時間。
對舊的Beta版本(如v2beta1),Kubernetes建議廢棄的時間應不少于9個月或3個大版本Release的時間,選擇最長的時間。
對舊的Alpha版本,則無須等待,可以直接廢棄。
通過在自定義資源的時候指定字段標注出來那個版本的資源對象處于廢棄狀態,
當對該資源的已棄用版本發出API請求時,將在API響應中作為頭返回一條警告消息。通過這個告警信息可以方便的對api版本進行治理。
另外可以在定義資源對象的時候,設置是否移除該版本的資源對象,如下圖所示。可以通過調整這個字段來關閉該版本的資源對象,測試對該資源對象訪問的組件是否工作正常,常常會在組件升級的過程中會去使用。
對象的版本與存儲
Client端去訪問資源對象的時候,需要指定對應的版本,廢棄狀態的版本以及正常使用的版本可以正常的訪問,移除狀態的版本無法訪問。Client可以訪問不同版本的api版本,通過版本之間的轉換來支持多個版本的資源對象,不同版本的資源對象需要可以相互轉換,并且轉換的時候不能發生字段屬性的丟失。 Kubebuilder中采用“hub and spoke”模型來管理不同版本的api轉換
實心點表示某個版本的對象,需要實現不同版本資源的轉換,kubebuilder中定義了某個版本是hub,如右邊圖中心的實心點,對象之間的轉換需要通過hub version。Hub version也可以被稱為storage version. Hub version在CRD可以通過設置版本對象中的storage: true來標志為hub。
對于CRD對象的版本之間的轉換需要提供webhook來支持,在CRD對象定義中通過spec.conversion來定義webhook, webhook是外部一個服務。之后由kube-apiserver調用過程中對對象版本進行轉換。Webhook支持URL或者Service Reference兩種格式,下圖為service reference為kubernetes集群中某個service.
當對象存在v1beta1、 v1、 v2beta1三個版本,v1為storage/hub version, client創建v1beta1的對象,kube-apiserver將會調用webhook完成v1beta1轉換成v1格式的對象。之后存儲的對象版本為v1版本。當client獲取該對象的v2beta1版本的時候,kube-apiserver獲取到存儲的v1版本的時候,會調用webhook完成v1版本的格式轉換成v2beta1版本,返回給client。
Kubebuilder支持多版本對象
通過kubebuilder初始化一個demo項目,演示如何在kubebuilder的框架下支持多個版本對象,以Changing things up - The Kubebuilder Book為例子。
# 創建project項目空間
mkdir project
cd project
# 初始化
kubebuilder init --domain tutorial.kubebuilder.io --repo tutorial.kubebuilder.io/project
##創建三個版本的api對象
# kubebuilder create api --group batch --version v1 --kind CronJob --force
# kubebuilder create api --group batch --version v2 --kind CronJob --force
# kubebuilder create api --group batch --version v3 --kind CronJob --force
##在v1對應的project/api/v1/cronjob_types.go中設置+kubebuilder:storageversion該v1版本為storage
##添加project/api/v1/cronjob_conversion.go
// Hub marks this type as a conversion hub.
func (*CronJob) Hub() {}
##添加project/api/v2/cronjob_conversion.go
// ConvertTo converts this CronJob to the Hub version (v1).
func (src *CronJob) ConvertTo(dstRaw conversion.Hub) error {
….
}
// ConvertFrom converts from the Hub version (v1) to this version.
func (dst *CronJob) ConvertFrom(srcRaw conversion.Hub) error {
…….
}
##添加project/api/v3/cronjob_conversion.go
// ConvertTo converts this CronJob to the Hub version (v1).
func (src *CronJob) ConvertTo(dstRaw conversion.Hub) error {
….
}
// ConvertFrom converts from the Hub version (v1) to this version.
func (dst *CronJob) ConvertFrom(srcRaw conversion.Hub) error {
…….
}
###添加一個webhook,來實現/convert
kubebuilder create webhook --group batch --version v1 --kind CronJob --conversion
Kubebuilder基于“hub and spoke”模型來實現對象之間的轉換,如上個例子所示,我們需要實現v2<->v1, v1<->v3之間的ConvertTo、ConvertFrom函數
總結
Kubernetes 資源對象的版本定義對于kubernetes的成功起到了至關重要的作用,其中資源對象的多版本管理包括了kubernetes社區的思考和探索,對于其他系統的api對象的設計有很好的參考價值。
參考資料
Kubernetes 棄用策略 | Kubernetes
and setting up the webhooks - The Kubebuilder Book