本文跟蹤一下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()