kubelet服務啓動流程中,默認參數的填充機制

本文跟蹤一下kubelet啓動過程中,參數的默認值是如何注入的。

我們知道,爲了啓動kubelet服務,首先要構造kubelet的配置對象,即kubeletconfig.KubeletConfiguration結構體,

// NewKubeletCommand creates a *cobra.Command object with default parameters
func NewKubeletCommand() *cobra.Command {
	cleanFlagSet := pflag.NewFlagSet(componentKubelet, pflag.ContinueOnError)
	cleanFlagSet.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
	kubeletFlags := options.NewKubeletFlags()
	#返回一個帶有默認值的kubelet配置對象
	kubeletConfig, err := options.NewKubeletConfiguration()
	// programmer error
// NewKubeletConfiguration will create a new KubeletConfiguration with default values
func NewKubeletConfiguration() (*kubeletconfig.KubeletConfiguration, error) {
	//構造了一個針對kubelet的Schema,schema是爲了解決數據結構 序列化、反序列化
	//以及多版本對象的兼容和轉換問題引入的一個概念;Schema會登記資源對象到類型、類型到
	//資源對象的雙向映射;不同版本數據對象的轉換函數;
	//不同類型的默認初始化函數(設置default值);
	scheme, _, err := kubeletscheme.NewSchemeAndCodecs()
	if err != nil {
		return nil, err
	}
	
	//v1beta1版本的kubelet配置
	versioned := &v1beta1.KubeletConfiguration{}
	//設置各字段的默認值,大致的原理是:先拿到versioned的類型,根據該類型找到對應的初始
	//化函數,然後調用初始化函數。
	scheme.Default(versioned)
	
	//無版本的kubelet配置
	config := &kubeletconfig.KubeletConfiguration{}
	//用v1beta1版本的配置去初始化無版本的kubelet配置,這裏其實沒有理解爲什麼要繞這麼一下??
	if err := scheme.Convert(versioned, config, nil); err != nil {
		return nil, err
	}
	
	//設置其他配置項的默認值
	applyLegacyDefaults(config)
	return config, nil
}

構造kubelet schmea的函數如下:

// NewSchemeAndCodecs is a utility function that returns a Scheme and CodecFactory
// that understand the types in the kubeletconfig API group.
func NewSchemeAndCodecs() (*runtime.Scheme, *serializer.CodecFactory, error) {
	//new了一個空的Schema
	scheme := runtime.NewScheme()
	
	//調用了register.go中的註冊函數,針對資源:
	//GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal} 
	//註冊了兩個類型:KubeletConfiguration 和 SerializedNodeConfigSource
	if err := kubeletconfig.AddToScheme(scheme); err != nil {
		return nil, nil, err
	}
	
	//調用v1beta1下的註冊函數,爲scheme設置了結構體默認值初始化函數,該初始化函數
	//符合結構體 KubeletConfiguration各字段默認值的設置,
	//具體的代碼在v1beta1下的defaults.go文件中
	if err := kubeletconfigv1beta1.AddToScheme(scheme); err != nil {
		return nil, nil, err
	}
	
	codecs := serializer.NewCodecFactory(scheme)
	return scheme, &codecs, nil
}

最下層的初始化函數如下:

func SetDefaults_KubeletConfiguration(obj *kubeletconfigv1beta1.KubeletConfiguration) {
	if obj.SyncFrequency == zeroDuration {
		obj.SyncFrequency = metav1.Duration{Duration: 1 * time.Minute}
	}
	if obj.FileCheckFrequency == zeroDuration {
		obj.FileCheckFrequency = metav1.Duration{Duration: 20 * time.Second}
	}
	if obj.HTTPCheckFrequency == zeroDuration {
		obj.HTTPCheckFrequency = metav1.Duration{Duration: 20 * time.Second}
	}
	if obj.Address == "" {
		obj.Address = "0.0.0.0"
	}
	if obj.Port == 0 {
		obj.Port = ports.KubeletPort
	}
	if obj.Authentication.Anonymous.Enabled == nil {
		obj.Authentication.Anonymous.Enabled = utilpointer.BoolPtr(false)
	}
	if obj.Authentication.Webhook.Enabled == nil {
		obj.Authentication.Webhook.Enabled = utilpointer.BoolPtr(true)
	}
	if obj.Authentication.Webhook.CacheTTL == zeroDuration {
		obj.Authentication.Webhook.CacheTTL = metav1.Duration{Duration: 2 * time.Minute}
	}
	if obj.Authorization.Mode == "" {
		obj.Authorization.Mode = kubeletconfigv1beta1.KubeletAuthorizationModeWebhook
	}
	if obj.Authorization.Webhook.CacheAuthorizedTTL == zeroDuration {
		obj.Authorization.Webhook.CacheAuthorizedTTL = metav1.Duration{Duration: 5 * time.Minute}
	}
	if obj.Authorization.Webhook.CacheUnauthorizedTTL == zeroDuration {
		obj.Authorization.Webhook.CacheUnauthorizedTTL = metav1.Duration{Duration: 30 * time.Second}
	}
	if obj.RegistryPullQPS == nil {
		obj.RegistryPullQPS = utilpointer.Int32Ptr(5)
	}
	if obj.RegistryBurst == 0 {
		obj.RegistryBurst = 10
	}

最後看下,scheme的具體代碼

// Scheme defines methods for serializing and deserializing API objects, a type
// registry for converting group, version, and kind information to and from Go
// schemas, and mappings between Go schemas of different versions. A scheme is the
// foundation for a versioned API and versioned configuration over time.
//
// In a Scheme, a Type is a particular Go struct, a Version is a point-in-time
// identifier for a particular representation of that Type (typically backwards
// compatible), a Kind is the unique name for that Type within the Version, and a
// Group identifies a set of Versions, Kinds, and Types that evolve over time. An
// Unversioned Type is one that is not yet formally bound to a type and is promised
// to be backwards compatible (effectively a "v1" of a Type that does not expect
// to break in the future).
//
// Schemes are not expected to change at runtime and are only threadsafe after
// registration is complete.
type Scheme struct {
	// versionMap allows one to figure out the go type of an object with
	// the given version and name.
	/*
	kubernetes中的類型對象都實現了Object接口,如下:
	// Object interface must be supported by all API types registered with Scheme. Since objects in a scheme are
// expected to be serialized to the wire, the interface an Object must provide to the Scheme allows
// serializers to set the kind, version, and group the object is represented as. An Object may choose
// to return a no-op ObjectKindAccessor in cases where it is not expected to be serialized.
type Object interface {
	GetObjectKind() schema.ObjectKind
	DeepCopyObject() Object
}

通過該接口可以獲取到某個對象關聯的資源類型GroupVersionKind:所屬的Group、版本以及資源名;
有了gvkToType和typeToGVK所提供的信息,就可以結局數據對象的序列化和反序列化問題。
	*/
	gvkToType map[schema.GroupVersionKind]reflect.Type

	// typeToGroupVersion allows one to find metadata for a given go object.
	// The reflect.Type we index by should *not* be a pointer.
	typeToGVK map[reflect.Type][]schema.GroupVersionKind

	// unversionedTypes are transformed without conversion in ConvertToVersion.
	unversionedTypes map[reflect.Type]schema.GroupVersionKind

	// unversionedKinds are the names of kinds that can be created in the context of any group
	// or version
	// TODO: resolve the status of unversioned types.
	unversionedKinds map[string]reflect.Type

	// Map from version and resource to the corresponding func to convert
	// resource field labels in that version to internal version.
	fieldLabelConversionFuncs map[schema.GroupVersionKind]FieldLabelConversionFunc

	// defaulterFuncs is an array of interfaces to be called with an object to provide defaulting
	// the provided object must be a pointer.
	//初始化函數,每種類型都有自己的初始化函數
	defaulterFuncs map[reflect.Type]func(interface{})

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

	// versionPriority is a map of groups to ordered lists of versions for those groups indicating the
	// default priorities of these versions as registered in the scheme
	versionPriority map[string][]string

	// observedVersions keeps track of the order we've seen versions during type registration
	observedVersions []schema.GroupVersion

	// schemeName is the name of this scheme.  If you don't specify a name, the stack of the NewScheme caller will be used.
	// This is useful for error reporting to indicate the origin of the scheme.
	schemeName string
}

總的調用鏈路大概如下:
options.NewKubeletConfiguration() -> kubeletscheme.NewSchemeAndCodecs()(完成kubeletSchema的構建,包括類型的註冊,初始化函數的註冊) -> scheme.Default() -> SetDefaults_KubeletConfiguration()

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