KubeCube 新增版本轉換:K8s 嚐鮮再也不用擔心影響老版本了

多租戶可視化 K8s 管理平臺 KubeCube近日迎來了新版本的發佈,新版本增加了 K8s 版本轉化、HNC GA 版本適配、審計信息國際化、warden 主動上報模式,爲集羣和項目設置 Ingress 域名後綴等特性,也修復了若干已知問題,詳見 ChangeLog。

該版本中最主要的特性是 Version-Conversion 能力的支持,使得接入 KubeCube 的用戶無需感知被 KubeCube 接管的 K8s 集羣版本,可以使用指定版本的 K8s API 來操作 K8s 資源,KubeCube 會做自適應轉化;同時 KubeCube 也將這個能力包裝成 SDK 供外部使用。

img

爲什麼需要多 K8s 版本轉化?

在實際的生產場景中,用戶的 K8s 集羣往往固置於某一穩定版本,並隨着時間的推移,在該 K8s 集羣中沉澱了大量的業務、工具、方案等,同時 K8s 社區又會不斷的推出更高的版本,此時升級 K8s 版本往往需要比較高的代價。

K8s 的版本升級,並不總是保證 API 的完美兼容,絕大多數的 API 會經歷從 Development level --> Alpha level --> Beta level --> Stable level 的發展階段,理想情況下,用戶應該使用 Stable level 的 API 用於生產環境,但是現實中,用戶所使用的某一資源的 API 很可能處於 Stable level 以下的階段,比如 extensions/v1beta1 的 Deployment 和 apps/v1 的 Deployment。詳見 K8S API 變動規劃

當用戶需要在控制面納管多 K8s 集羣時,用戶暫時不希望升級老的穩定的 K8s 集羣,又希望新增的 K8s 集羣是比較高的版本,這時,管控面的 KubeCube,就能夠提供訪問多版本 K8s 的能力,對外暴露統一的 K8s 風格的 RESTfule API,用戶既可以使用精確的 GVR 去訪問不同版本的 K8s 資源,也可用使用統一版本的 GVR 去訪問不同版本的 K8s 資源,KubeCube 會做自適應轉化。

K8s native convert

1. K8s api workflow

2. K8s version convert

K8s 版本轉換原則

  1. 同一個 group 的不同 version 都可以轉換成該 group 的 internalVersion
  2. 某一 group 的 internalVersion 可以轉換成該 group 下的任一 version

K8s 版本轉化的核心 ——scheme

Scheme 中擁有 concerter 轉化器,其內部存放了各個 API 註冊的版本轉化函數。

type Scheme struct {
	...

	// converter stores all registered conversion functions. It also has
	// default converting behavior.
	converter *conversion.Converter

	...
}

// Converter knows how to convert one type to another.
type Converter struct {
	// Map from the conversion pair to a function which can
	// do the conversion.
	conversionFuncs          ConversionFuncs
	generatedConversionFuncs ConversionFuncs

	// Set of conversions that should be treated as a no-op
	ignoredUntypedConversions map[typePair]struct{}
}

我們已經知道 internalVersion 和指定 version 之間的轉換規則,它們的轉換函數位於 k8s apis 的定義文件夾下,如:pkg/apis/apps/v1/zz_generated.conversion.go

// Code generated by conversion-gen. DO NOT EDIT.

package v1

import (...)

func init() {
	localSchemeBuilder.Register(RegisterConversions)
}

// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(s *runtime.Scheme) error {...}

這些轉化函數,一般由 install 包下的 Install(scheme) 函數註冊到 Scheme 中。

// Package install installs the apps API group, making it available as
// an option to all of the API encoding/decoding machinery.
package install

import (...)

func init() {
	Install(legacyscheme.Scheme)
}

// Install registers the API group and adds types to a scheme
func Install(scheme *runtime.Scheme) {
	utilruntime.Must(apps.AddToScheme(scheme))
	utilruntime.Must(v1beta1.AddToScheme(scheme))
	utilruntime.Must(v1beta2.AddToScheme(scheme))
	utilruntime.Must(v1.AddToScheme(scheme))
	utilruntime.Must(scheme.SetVersionPriority(v1.SchemeGroupVersion, v1beta2.SchemeGroupVersion, v1beta1.SchemeGroupVersion))
}

註冊完的轉會函數,將會在 Convert () 方法中使用。

// Convert will translate src to dest if it knows how. Both must be pointers.
// If no conversion func is registered and the default copying mechanism
// doesn't work on this type pair, an error will be returned.
// 'meta' is given to allow you to pass information to conversion functions,
// it is not used by Convert() other than storing it in the scope.
// Not safe for objects with cyclic references!
func (c *Converter) Convert(src, dest interface{}, meta *Meta) error {
  // 轉換函數 map 的 key
	pair := typePair{reflect.TypeOf(src), reflect.TypeOf(dest)}
  
  // 實際的 convert 句柄
	scope := &scope{
		converter: c,
		meta:      meta,
	}

	// ignore conversions of this type
	if _, ok := c.ignoredUntypedConversions[pair]; ok {
		return nil
	}
  // 使用預先註冊的轉換函數進行轉換
	if fn, ok := c.conversionFuncs.untyped[pair]; ok {
		return fn(src, dest, scope)
	}
	if fn, ok := c.generatedConversionFuncs.untyped[pair]; ok {
		return fn(src, dest, scope)
	}

	dv, err := EnforcePtr(dest)
	if err != nil {
		return err
	}
	sv, err := EnforcePtr(src)
	if err != nil {
		return err
	}
	return fmt.Errorf("converting (%s) to (%s): unknown conversion", sv.Type(), dv.Type())
}

KubeCube version conversion

瞭解了 K8s 版本轉換的大致思路後,KubeCube 如果需要做版本轉換的能力,需要做到以下幾點:

  1. 維護版本轉換專用的 Scheme
  2. 註冊所有的 K8s 的 API 轉換函數,並提供拓展方法
  3. 使用 discovery client 提早做 src api 和 dest api 的轉換檢查

1. Conversion func register

KubeCube 會默認註冊所有 K8s 原生資源的轉換函數,同時也提供註冊自定義資源轉換函數的入口。

2. Greeting target cluster

3. Controller-runtime client support

KubeCube 的版本轉化 SDK 提供了 Wrap controller-runtime 的 client.Client 的能力,可以將 client.Client 升級爲具有版本轉化能力的句柄。

寫在最後

未來我們會持續提供更多功能,幫助企業簡化容器化落地。也歡迎大家參與貢獻,提出寶貴的建議。添加以下微信進入 KubeCube 交流羣。

瞭解更多

作者簡介: 蔡鑫濤,網易數帆輕舟容器平臺資深開發,KubeCube Committer

【點擊瞭解更多網易技術乾貨與活動】

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章