Filling mechanism of default parameters in kubelet service startup process

This article traces how the default values of parameters are injected during kubelet startup.

We know that in order to start the kubelet service, we first need to construct the configuration object of kubelet, that is, the kubeletconfig.KubeletConfiguration structure.

// 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()
	#Returns a kubelet configuration object with default values
	kubeletConfig, err := options.NewKubeletConfiguration()
	// programmer error
// NewKubeletConfiguration will create a new KubeletConfiguration with default values
func NewKubeletConfiguration() (*kubeletconfig.KubeletConfiguration, error) {
	//A Schema for kubelet is constructed. The schema is used to serialize and deserialize data structures.
	//And a concept introduced in the compatibility and transformation of multi-version objects; Schema registers resource objects to types, types to
	//Bidirectional mapping of resource objects; conversion functions of different versions of data objects;
	//Different types of default initialization functions (setting default values);
	scheme, _, err := kubeletscheme.NewSchemeAndCodecs()
	if err != nil {
		return nil, err
	}
	
	//kubelet configuration for V1 beta 1 version
	versioned := &v1beta1.KubeletConfiguration{}
	//The general principle of setting default values for each field is to get the type of versioned first and find the corresponding initial value according to the type.
	//Change the function, and then call the initialization function.
	scheme.Default(versioned)
	
	//Versionless kubelet configuration
	config := &kubeletconfig.KubeletConfiguration{}
	//Using the v1beta1 configuration to initialize the no-version kubelet configuration, I don't really understand why we should go around this?
	if err := scheme.Convert(versioned, config, nil); err != nil {
		return nil, err
	}
	
	//Set default values for other configuration items
	applyLegacyDefaults(config)
	return config, nil
}

The functions for constructing kubelet schmea are as follows:

// 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 has an empty Schema
	scheme := runtime.NewScheme()
	
	//The registration function in register.go is called for resources:
	//GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal} 
	//Two types are registered: KubeletConfiguration and Serialized NodeConfigSource
	if err := kubeletconfig.AddToScheme(scheme); err != nil {
		return nil, nil, err
	}
	
	//Call the registration function under v1beta1 and set the default initialization function of the structure for scheme.
	//It conforms to the default values of the fields in the structure Kubelet Configuration.
	//Specific code in the defaults.go file under v1beta1
	if err := kubeletconfigv1beta1.AddToScheme(scheme); err != nil {
		return nil, nil, err
	}
	
	codecs := serializer.NewCodecFactory(scheme)
	return scheme, &codecs, nil
}

The lowest initialization function is as follows:

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
	}

Finally, look at the specific code for 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 interfaces are implemented for all types of objects, as follows:
	// 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
}

Through this interface, the resource type GroupVersionKind associated with an object can be obtained: the Group, version and resource name to which it belongs;
With the information provided by gvkToType and typeToGVK, the problem of serialization and deserialization of end data objects can be solved.
	*/
	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.
	//Initialization function, each type has its own initialization function
	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
}

The total invocation link is roughly as follows:
Options. New KubeletConfiguration () - > Kubeletscheme. New SchemeAndCodecs () (completing the construction of kubeletSchema, including type registration, initialization function registration) - > scheme. Default () - > SetDefaults_KubeletConfiguration ()

Keywords: Big Data kubelet Kubernetes

Added by cahva on Wed, 31 Jul 2019 16:29:39 +0300