Merge pull request #105437 from cmssczy/update-kubelet-configuration

migrate --register-with-taints to KubeletConfiguration
This commit is contained in:
Kubernetes Prow Robot 2021-11-16 17:44:00 -08:00 committed by GitHub
commit 1f6d5caa9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 260 additions and 149 deletions

View File

@ -379,6 +379,7 @@ API rule violation: list_type_missing,k8s.io/kubelet/config/v1alpha1,CredentialP
API rule violation: list_type_missing,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,AllowedUnsafeSysctls API rule violation: list_type_missing,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,AllowedUnsafeSysctls
API rule violation: list_type_missing,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,ClusterDNS API rule violation: list_type_missing,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,ClusterDNS
API rule violation: list_type_missing,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,EnforceNodeAllocatable API rule violation: list_type_missing,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,EnforceNodeAllocatable
API rule violation: list_type_missing,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,RegisterWithTaints
API rule violation: list_type_missing,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,ReservedMemory API rule violation: list_type_missing,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,ReservedMemory
API rule violation: list_type_missing,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,TLSCipherSuites API rule violation: list_type_missing,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,TLSCipherSuites
API rule violation: list_type_missing,k8s.io/metrics/pkg/apis/metrics/v1alpha1,PodMetrics,Containers API rule violation: list_type_missing,k8s.io/metrics/pkg/apis/metrics/v1alpha1,PodMetrics,Containers

View File

@ -32,7 +32,6 @@ import (
"k8s.io/component-base/logs" "k8s.io/component-base/logs"
"k8s.io/kubelet/config/v1beta1" "k8s.io/kubelet/config/v1beta1"
kubeletapis "k8s.io/kubelet/pkg/apis" kubeletapis "k8s.io/kubelet/pkg/apis"
"k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/cluster/ports" "k8s.io/kubernetes/pkg/cluster/ports"
"k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/features"
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config" kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
@ -40,7 +39,6 @@ import (
kubeletconfigvalidation "k8s.io/kubernetes/pkg/kubelet/apis/config/validation" kubeletconfigvalidation "k8s.io/kubernetes/pkg/kubelet/apis/config/validation"
"k8s.io/kubernetes/pkg/kubelet/config" "k8s.io/kubernetes/pkg/kubelet/config"
utilflag "k8s.io/kubernetes/pkg/util/flag" utilflag "k8s.io/kubernetes/pkg/util/flag"
utiltaints "k8s.io/kubernetes/pkg/util/taints"
) )
const defaultRootDir = "/var/lib/kubelet" const defaultRootDir = "/var/lib/kubelet"
@ -97,14 +95,6 @@ type KubeletFlags struct {
// Omit this flag to use the combination of built-in default configuration values and flags. // Omit this flag to use the combination of built-in default configuration values and flags.
KubeletConfigFile string KubeletConfigFile string
// registerNode enables automatic registration with the apiserver.
RegisterNode bool
// registerWithTaints are an array of taints to add to a node object when
// the kubelet registers itself. This only takes effect when registerNode
// is true and upon the initial registration of the node.
RegisterWithTaints []core.Taint
// WindowsService should be set to true if kubelet is running as a service on Windows. // WindowsService should be set to true if kubelet is running as a service on Windows.
// Its corresponding flag only gets registered in Windows builds. // Its corresponding flag only gets registered in Windows builds.
WindowsService bool WindowsService bool
@ -188,7 +178,6 @@ func NewKubeletFlags() *KubeletFlags {
RegisterSchedulable: true, RegisterSchedulable: true,
RemoteRuntimeEndpoint: remoteRuntimeEndpoint, RemoteRuntimeEndpoint: remoteRuntimeEndpoint,
NodeLabels: make(map[string]string), NodeLabels: make(map[string]string),
RegisterNode: true,
} }
} }
@ -339,9 +328,6 @@ func (f *KubeletFlags) AddFlags(mainfs *pflag.FlagSet) {
fs.Var(&f.DynamicConfigDir, "dynamic-config-dir", "The Kubelet will use this directory for checkpointing downloaded configurations and tracking configuration health. The Kubelet will create this directory if it does not already exist. The path may be absolute or relative; relative paths start at the Kubelet's current working directory. Providing this flag enables dynamic Kubelet configuration. The DynamicKubeletConfig feature gate must be enabled to pass this flag.") fs.Var(&f.DynamicConfigDir, "dynamic-config-dir", "The Kubelet will use this directory for checkpointing downloaded configurations and tracking configuration health. The Kubelet will create this directory if it does not already exist. The path may be absolute or relative; relative paths start at the Kubelet's current working directory. Providing this flag enables dynamic Kubelet configuration. The DynamicKubeletConfig feature gate must be enabled to pass this flag.")
fs.MarkDeprecated("dynamic-config-dir", "Feature DynamicKubeletConfig is deprecated in 1.22 and will not move to GA. It is planned to be removed from Kubernetes in the version 1.23. Please use alternative ways to update kubelet configuration.") fs.MarkDeprecated("dynamic-config-dir", "Feature DynamicKubeletConfig is deprecated in 1.22 and will not move to GA. It is planned to be removed from Kubernetes in the version 1.23. Please use alternative ways to update kubelet configuration.")
fs.BoolVar(&f.RegisterNode, "register-node", f.RegisterNode, "Register the node with the apiserver. If --kubeconfig is not provided, this flag is irrelevant, as the Kubelet won't have an apiserver to register with.")
fs.Var(utiltaints.NewTaintsVar(&f.RegisterWithTaints), "register-with-taints", "Register the node with the given list of taints (comma separated \"<key>=<value>:<effect>\"). No-op if register-node is false.")
// EXPERIMENTAL FLAGS // EXPERIMENTAL FLAGS
fs.StringVar(&f.RemoteRuntimeEndpoint, "container-runtime-endpoint", f.RemoteRuntimeEndpoint, "[Experimental] The endpoint of remote runtime service. Currently unix socket endpoint is supported on Linux, while npipe and tcp endpoints are supported on windows. Note: When using docker as container runtime this specifies the dockershim socket location which kubelet itself creates. Examples:'unix:///var/run/dockershim.sock', 'npipe:////./pipe/dockershim'") fs.StringVar(&f.RemoteRuntimeEndpoint, "container-runtime-endpoint", f.RemoteRuntimeEndpoint, "[Experimental] The endpoint of remote runtime service. Currently unix socket endpoint is supported on Linux, while npipe and tcp endpoints are supported on windows. Note: When using docker as container runtime this specifies the dockershim socket location which kubelet itself creates. Examples:'unix:///var/run/dockershim.sock', 'npipe:////./pipe/dockershim'")
fs.StringVar(&f.RemoteImageEndpoint, "image-service-endpoint", f.RemoteImageEndpoint, "[Experimental] The endpoint of remote image service. If not specified, it will be the same with container-runtime-endpoint by default. Currently unix socket endpoint is supported on Linux, while npipe and tcp endpoints are supported on windows. Examples:'unix:///var/run/dockershim.sock', 'npipe:////./pipe/dockershim'") fs.StringVar(&f.RemoteImageEndpoint, "image-service-endpoint", f.RemoteImageEndpoint, "[Experimental] The endpoint of remote image service. If not specified, it will be the same with container-runtime-endpoint by default. Currently unix socket endpoint is supported on Linux, while npipe and tcp endpoints are supported on windows. Examples:'unix:///var/run/dockershim.sock', 'npipe:////./pipe/dockershim'")
@ -556,4 +542,8 @@ func AddKubeletConfigFlags(mainfs *pflag.FlagSet, c *kubeletconfig.KubeletConfig
// Memory Manager Flags // Memory Manager Flags
fs.StringVar(&c.MemoryManagerPolicy, "memory-manager-policy", c.MemoryManagerPolicy, "Memory Manager policy to use. Possible values: 'None', 'Static'.") fs.StringVar(&c.MemoryManagerPolicy, "memory-manager-policy", c.MemoryManagerPolicy, "Memory Manager policy to use. Possible values: 'None', 'Static'.")
fs.Var(&utilflag.ReservedMemoryVar{Value: &c.ReservedMemory}, "reserved-memory", "A comma separated list of memory reservations for NUMA nodes. (e.g. --reserved-memory 0:memory=1Gi,hugepages-1M=2Gi --reserved-memory 1:memory=2Gi). The total sum for each memory type should be equal to the sum of kube-reserved, system-reserved and eviction-threshold. See https://kubernetes.io/docs/tasks/administer-cluster/memory-manager/#reserved-memory-flag for more details.") fs.Var(&utilflag.ReservedMemoryVar{Value: &c.ReservedMemory}, "reserved-memory", "A comma separated list of memory reservations for NUMA nodes. (e.g. --reserved-memory 0:memory=1Gi,hugepages-1M=2Gi --reserved-memory 1:memory=2Gi). The total sum for each memory type should be equal to the sum of kube-reserved, system-reserved and eviction-threshold. See https://kubernetes.io/docs/tasks/administer-cluster/memory-manager/#reserved-memory-flag for more details.")
fs.BoolVar(&c.RegisterNode, "register-node", c.RegisterNode, "Register the node with the apiserver. If --kubeconfig is not provided, this flag is irrelevant, as the Kubelet won't have an apiserver to register with.")
fs.Var(&utilflag.RegisterWithTaintsVar{Value: &c.RegisterWithTaints}, "register-with-taints", "Register the node with the given list of taints (comma separated \"<key>=<value>:<effect>\"). No-op if register-node is false.")
} }

View File

@ -72,7 +72,6 @@ import (
kubeletconfigv1beta1 "k8s.io/kubelet/config/v1beta1" kubeletconfigv1beta1 "k8s.io/kubelet/config/v1beta1"
"k8s.io/kubernetes/cmd/kubelet/app/options" "k8s.io/kubernetes/cmd/kubelet/app/options"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/capabilities" "k8s.io/kubernetes/pkg/capabilities"
"k8s.io/kubernetes/pkg/credentialprovider" "k8s.io/kubernetes/pkg/credentialprovider"
"k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/features"
@ -1265,7 +1264,7 @@ func createAndInitKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
imageCredentialProviderConfigFile string, imageCredentialProviderConfigFile string,
imageCredentialProviderBinDir string, imageCredentialProviderBinDir string,
registerNode bool, registerNode bool,
registerWithTaints []api.Taint, registerWithTaints []v1.Taint,
allowedUnsafeSysctls []string, allowedUnsafeSysctls []string,
experimentalMounterPath string, experimentalMounterPath string,
kernelMemcgNotification bool, kernelMemcgNotification bool,

View File

@ -43,15 +43,14 @@ import (
"k8s.io/component-base/version/verflag" "k8s.io/component-base/version/verflag"
fakesysctl "k8s.io/component-helpers/node/util/sysctl/testing" fakesysctl "k8s.io/component-helpers/node/util/sysctl/testing"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/cluster/ports" "k8s.io/kubernetes/pkg/cluster/ports"
cadvisortest "k8s.io/kubernetes/pkg/kubelet/cadvisor/testing" cadvisortest "k8s.io/kubernetes/pkg/kubelet/cadvisor/testing"
"k8s.io/kubernetes/pkg/kubelet/cm" "k8s.io/kubernetes/pkg/kubelet/cm"
"k8s.io/kubernetes/pkg/kubelet/cri/remote" "k8s.io/kubernetes/pkg/kubelet/cri/remote"
fakeremote "k8s.io/kubernetes/pkg/kubelet/cri/remote/fake" fakeremote "k8s.io/kubernetes/pkg/kubelet/cri/remote/fake"
"k8s.io/kubernetes/pkg/kubemark" "k8s.io/kubernetes/pkg/kubemark"
utilflag "k8s.io/kubernetes/pkg/util/flag"
fakeiptables "k8s.io/kubernetes/pkg/util/iptables/testing" fakeiptables "k8s.io/kubernetes/pkg/util/iptables/testing"
utiltaints "k8s.io/kubernetes/pkg/util/taints"
fakeexec "k8s.io/utils/exec/testing" fakeexec "k8s.io/utils/exec/testing"
) )
@ -67,7 +66,7 @@ type hollowNodeConfig struct {
ProxierSyncPeriod time.Duration ProxierSyncPeriod time.Duration
ProxierMinSyncPeriod time.Duration ProxierMinSyncPeriod time.Duration
NodeLabels map[string]string NodeLabels map[string]string
RegisterWithTaints []core.Taint RegisterWithTaints []v1.Taint
MaxPods int MaxPods int
ExtendedResources map[string]string ExtendedResources map[string]string
UseHostImageService bool UseHostImageService bool
@ -95,7 +94,7 @@ func (c *hollowNodeConfig) addFlags(fs *pflag.FlagSet) {
fs.DurationVar(&c.ProxierMinSyncPeriod, "proxier-min-sync-period", 0, "Minimum period that proxy rules are refreshed in hollow-proxy.") fs.DurationVar(&c.ProxierMinSyncPeriod, "proxier-min-sync-period", 0, "Minimum period that proxy rules are refreshed in hollow-proxy.")
bindableNodeLabels := cliflag.ConfigurationMap(c.NodeLabels) bindableNodeLabels := cliflag.ConfigurationMap(c.NodeLabels)
fs.Var(&bindableNodeLabels, "node-labels", "Additional node labels") fs.Var(&bindableNodeLabels, "node-labels", "Additional node labels")
fs.Var(utiltaints.NewTaintsVar(&c.RegisterWithTaints), "register-with-taints", "Register the node with the given list of taints (comma separated \"<key>=<value>:<effect>\"). No-op if register-node is false.") fs.Var(utilflag.RegisterWithTaintsVar{Value: &c.RegisterWithTaints}, "register-with-taints", "Register the node with the given list of taints (comma separated \"<key>=<value>:<effect>\"). No-op if register-node is false.")
fs.IntVar(&c.MaxPods, "max-pods", maxPods, "Number of pods that can run on this Kubelet.") fs.IntVar(&c.MaxPods, "max-pods", maxPods, "Number of pods that can run on this Kubelet.")
bindableExtendedResources := cliflag.ConfigurationMap(c.ExtendedResources) bindableExtendedResources := cliflag.ConfigurationMap(c.ExtendedResources)
fs.Var(&bindableExtendedResources, "extended-resources", "Register the node with extended resources (comma separated \"<name>=<quantity>\")") fs.Var(&bindableExtendedResources, "extended-resources", "Register the node with extended resources (comma separated \"<name>=<quantity>\")")

View File

@ -256,10 +256,12 @@ var (
"ProtectKernelDefaults", "ProtectKernelDefaults",
"ProviderID", "ProviderID",
"ReadOnlyPort", "ReadOnlyPort",
"RegisterNode",
"RegistryBurst", "RegistryBurst",
"RegistryPullQPS", "RegistryPullQPS",
"ReservedMemory", "ReservedMemory",
"ReservedSystemCPUs", "ReservedSystemCPUs",
"RegisterWithTaints",
"RuntimeRequestTimeout.Duration", "RuntimeRequestTimeout.Duration",
"RunOnce", "RunOnce",
"SeccompDefault", "SeccompDefault",

View File

@ -35,6 +35,7 @@ func TestComponentConfigSetup(t *testing.T) {
reflect.TypeOf(metav1.TypeMeta{}): true, reflect.TypeOf(metav1.TypeMeta{}): true,
reflect.TypeOf(metav1.Duration{}): true, reflect.TypeOf(metav1.Duration{}): true,
reflect.TypeOf(v1.NodeConfigSource{}): true, reflect.TypeOf(v1.NodeConfigSource{}): true,
reflect.TypeOf(v1.Taint{}): true,
}, },
} }

View File

@ -72,6 +72,7 @@ nodeStatusUpdateFrequency: 10s
oomScoreAdj: -999 oomScoreAdj: -999
podPidsLimit: -1 podPidsLimit: -1
port: 10250 port: 10250
registerNode: true
registryBurst: 10 registryBurst: 10
registryPullQPS: 5 registryPullQPS: 5
resolvConf: /etc/resolv.conf resolvConf: /etc/resolv.conf

View File

@ -72,6 +72,7 @@ nodeStatusUpdateFrequency: 10s
oomScoreAdj: -999 oomScoreAdj: -999
podPidsLimit: -1 podPidsLimit: -1
port: 10250 port: 10250
registerNode: true
registryBurst: 10 registryBurst: 10
registryPullQPS: 5 registryPullQPS: 5
resolvConf: /etc/resolv.conf resolvConf: /etc/resolv.conf

View File

@ -426,6 +426,15 @@ type KubeletConfiguration struct {
// +featureGate=MemoryQoS // +featureGate=MemoryQoS
// +optional // +optional
MemoryThrottlingFactor *float64 MemoryThrottlingFactor *float64
// registerWithTaints are an array of taints to add to a node object when
// the kubelet registers itself. This only takes effect when registerNode
// is true and upon the initial registration of the node.
// +optional
RegisterWithTaints []v1.Taint
// registerNode enables automatic registration with the apiserver.
// +optional
RegisterNode bool
} }
// KubeletAuthorizationMode denotes the authorization mode for the kubelet // KubeletAuthorizationMode denotes the authorization mode for the kubelet

View File

@ -261,4 +261,7 @@ func SetDefaults_KubeletConfiguration(obj *kubeletconfigv1beta1.KubeletConfigura
if obj.MemoryThrottlingFactor == nil { if obj.MemoryThrottlingFactor == nil {
obj.MemoryThrottlingFactor = utilpointer.Float64Ptr(DefaultMemoryThrottlingFactor) obj.MemoryThrottlingFactor = utilpointer.Float64Ptr(DefaultMemoryThrottlingFactor)
} }
if obj.RegisterNode == nil {
obj.RegisterNode = utilpointer.BoolPtr(true)
}
} }

View File

@ -120,6 +120,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
EnableDebugFlagsHandler: utilpointer.BoolPtr(true), EnableDebugFlagsHandler: utilpointer.BoolPtr(true),
SeccompDefault: utilpointer.BoolPtr(false), SeccompDefault: utilpointer.BoolPtr(false),
MemoryThrottlingFactor: utilpointer.Float64Ptr(DefaultMemoryThrottlingFactor), MemoryThrottlingFactor: utilpointer.Float64Ptr(DefaultMemoryThrottlingFactor),
RegisterNode: utilpointer.BoolPtr(true),
}, },
}, },
{ {
@ -244,6 +245,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
EnableDebugFlagsHandler: utilpointer.Bool(false), EnableDebugFlagsHandler: utilpointer.Bool(false),
SeccompDefault: utilpointer.Bool(false), SeccompDefault: utilpointer.Bool(false),
MemoryThrottlingFactor: utilpointer.Float64(0), MemoryThrottlingFactor: utilpointer.Float64(0),
RegisterNode: utilpointer.BoolPtr(false),
}, },
&v1beta1.KubeletConfiguration{ &v1beta1.KubeletConfiguration{
EnableServer: utilpointer.BoolPtr(false), EnableServer: utilpointer.BoolPtr(false),
@ -339,6 +341,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
EnableDebugFlagsHandler: utilpointer.Bool(false), EnableDebugFlagsHandler: utilpointer.Bool(false),
SeccompDefault: utilpointer.Bool(false), SeccompDefault: utilpointer.Bool(false),
MemoryThrottlingFactor: utilpointer.Float64(0), MemoryThrottlingFactor: utilpointer.Float64(0),
RegisterNode: utilpointer.BoolPtr(false),
}, },
}, },
{ {
@ -488,6 +491,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
EnableDebugFlagsHandler: utilpointer.Bool(true), EnableDebugFlagsHandler: utilpointer.Bool(true),
SeccompDefault: utilpointer.Bool(true), SeccompDefault: utilpointer.Bool(true),
MemoryThrottlingFactor: utilpointer.Float64(1), MemoryThrottlingFactor: utilpointer.Float64(1),
RegisterNode: utilpointer.BoolPtr(true),
}, },
&v1beta1.KubeletConfiguration{ &v1beta1.KubeletConfiguration{
EnableServer: utilpointer.BoolPtr(true), EnableServer: utilpointer.BoolPtr(true),
@ -634,6 +638,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
EnableDebugFlagsHandler: utilpointer.Bool(true), EnableDebugFlagsHandler: utilpointer.Bool(true),
SeccompDefault: utilpointer.Bool(true), SeccompDefault: utilpointer.Bool(true),
MemoryThrottlingFactor: utilpointer.Float64(1), MemoryThrottlingFactor: utilpointer.Float64(1),
RegisterNode: utilpointer.BoolPtr(true),
}, },
}, },
{ {
@ -719,6 +724,7 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
EnableDebugFlagsHandler: utilpointer.BoolPtr(true), EnableDebugFlagsHandler: utilpointer.BoolPtr(true),
SeccompDefault: utilpointer.BoolPtr(false), SeccompDefault: utilpointer.BoolPtr(false),
MemoryThrottlingFactor: utilpointer.Float64Ptr(DefaultMemoryThrottlingFactor), MemoryThrottlingFactor: utilpointer.Float64Ptr(DefaultMemoryThrottlingFactor),
RegisterNode: utilpointer.BoolPtr(true),
}, },
}, },
} }

View File

@ -392,6 +392,10 @@ func autoConvert_v1beta1_KubeletConfiguration_To_config_KubeletConfiguration(in
return err return err
} }
out.MemoryThrottlingFactor = (*float64)(unsafe.Pointer(in.MemoryThrottlingFactor)) out.MemoryThrottlingFactor = (*float64)(unsafe.Pointer(in.MemoryThrottlingFactor))
out.RegisterWithTaints = *(*[]corev1.Taint)(unsafe.Pointer(&in.RegisterWithTaints))
if err := v1.Convert_Pointer_bool_To_bool(&in.RegisterNode, &out.RegisterNode, s); err != nil {
return err
}
return nil return nil
} }
@ -563,6 +567,10 @@ func autoConvert_config_KubeletConfiguration_To_v1beta1_KubeletConfiguration(in
return err return err
} }
out.MemoryThrottlingFactor = (*float64)(unsafe.Pointer(in.MemoryThrottlingFactor)) out.MemoryThrottlingFactor = (*float64)(unsafe.Pointer(in.MemoryThrottlingFactor))
out.RegisterWithTaints = *(*[]corev1.Taint)(unsafe.Pointer(&in.RegisterWithTaints))
if err := v1.Convert_bool_To_Pointer_bool(&in.RegisterNode, &out.RegisterNode, s); err != nil {
return err
}
return nil return nil
} }

View File

@ -31,6 +31,7 @@ import (
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config" kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
"k8s.io/kubernetes/pkg/kubelet/cm/cpuset" "k8s.io/kubernetes/pkg/kubelet/cm/cpuset"
kubetypes "k8s.io/kubernetes/pkg/kubelet/types" kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
utiltaints "k8s.io/kubernetes/pkg/util/taints"
) )
var ( var (
@ -126,6 +127,16 @@ func ValidateKubeletConfiguration(kc *kubeletconfig.KubeletConfiguration) error
if kc.TopologyManagerPolicy != kubeletconfig.NoneTopologyManagerPolicy && !localFeatureGate.Enabled(features.TopologyManager) { if kc.TopologyManagerPolicy != kubeletconfig.NoneTopologyManagerPolicy && !localFeatureGate.Enabled(features.TopologyManager) {
allErrors = append(allErrors, fmt.Errorf("invalid configuration: topologyManagerPolicy %v requires feature gate TopologyManager", kc.TopologyManagerPolicy)) allErrors = append(allErrors, fmt.Errorf("invalid configuration: topologyManagerPolicy %v requires feature gate TopologyManager", kc.TopologyManagerPolicy))
} }
for _, nodeTaint := range kc.RegisterWithTaints {
if err := utiltaints.CheckTaintValidation(nodeTaint); err != nil {
allErrors = append(allErrors, fmt.Errorf("invalid taint: %v", nodeTaint))
}
if nodeTaint.TimeAdded != nil {
allErrors = append(allErrors, fmt.Errorf("taint TimeAdded is not nil"))
}
}
switch kc.TopologyManagerPolicy { switch kc.TopologyManagerPolicy {
case kubeletconfig.NoneTopologyManagerPolicy: case kubeletconfig.NoneTopologyManagerPolicy:
case kubeletconfig.BestEffortTopologyManagerPolicy: case kubeletconfig.BestEffortTopologyManagerPolicy:

View File

@ -295,6 +295,13 @@ func (in *KubeletConfiguration) DeepCopyInto(out *KubeletConfiguration) {
*out = new(float64) *out = new(float64)
**out = **in **out = **in
} }
if in.RegisterWithTaints != nil {
in, out := &in.RegisterWithTaints, &out.RegisterWithTaints
*out = make([]corev1.Taint, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return return
} }

View File

@ -62,7 +62,6 @@ import (
"k8s.io/klog/v2" "k8s.io/klog/v2"
pluginwatcherapi "k8s.io/kubelet/pkg/apis/pluginregistration/v1" pluginwatcherapi "k8s.io/kubelet/pkg/apis/pluginregistration/v1"
statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1" statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/features"
kubeletconfiginternal "k8s.io/kubernetes/pkg/kubelet/apis/config" kubeletconfiginternal "k8s.io/kubernetes/pkg/kubelet/apis/config"
"k8s.io/kubernetes/pkg/kubelet/apis/podresources" "k8s.io/kubernetes/pkg/kubelet/apis/podresources"
@ -360,7 +359,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
imageCredentialProviderConfigFile string, imageCredentialProviderConfigFile string,
imageCredentialProviderBinDir string, imageCredentialProviderBinDir string,
registerNode bool, registerNode bool,
registerWithTaints []api.Taint, registerWithTaints []v1.Taint,
allowedUnsafeSysctls []string, allowedUnsafeSysctls []string,
experimentalMounterPath string, experimentalMounterPath string,
kernelMemcgNotification bool, kernelMemcgNotification bool,
@ -944,7 +943,7 @@ type Kubelet struct {
// Set to true to have the node register itself with the apiserver. // Set to true to have the node register itself with the apiserver.
registerNode bool registerNode bool
// List of taints to add to a node object when the kubelet registers itself. // List of taints to add to a node object when the kubelet registers itself.
registerWithTaints []api.Taint registerWithTaints []v1.Taint
// Set to true to have the node register itself as schedulable. // Set to true to have the node register itself as schedulable.
registerSchedulable bool registerSchedulable bool
// for internal book keeping; access only from within registerWithApiserver // for internal book keeping; access only from within registerWithApiserver

View File

@ -37,7 +37,6 @@ import (
nodeutil "k8s.io/component-helpers/node/util" nodeutil "k8s.io/component-helpers/node/util"
"k8s.io/klog/v2" "k8s.io/klog/v2"
kubeletapis "k8s.io/kubelet/pkg/apis" kubeletapis "k8s.io/kubelet/pkg/apis"
k8s_api_v1 "k8s.io/kubernetes/pkg/apis/core/v1"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
"k8s.io/kubernetes/pkg/kubelet/events" "k8s.io/kubernetes/pkg/kubelet/events"
"k8s.io/kubernetes/pkg/kubelet/nodestatus" "k8s.io/kubernetes/pkg/kubelet/nodestatus"
@ -308,17 +307,8 @@ func (kl *Kubelet) initialNode(ctx context.Context) (*v1.Node, error) {
node.Labels[label] = value node.Labels[label] = value
} }
nodeTaints := make([]v1.Taint, 0) nodeTaints := make([]v1.Taint, len(kl.registerWithTaints))
if len(kl.registerWithTaints) > 0 { copy(nodeTaints, kl.registerWithTaints)
taints := make([]v1.Taint, len(kl.registerWithTaints))
for i := range kl.registerWithTaints {
if err := k8s_api_v1.Convert_core_Taint_To_v1_Taint(&kl.registerWithTaints[i], &taints[i], nil); err != nil {
return nil, err
}
}
nodeTaints = append(nodeTaints, taints...)
}
unschedulableTaint := v1.Taint{ unschedulableTaint := v1.Taint{
Key: v1.TaintNodeUnschedulable, Key: v1.TaintNodeUnschedulable,
Effect: v1.TaintEffectNoSchedule, Effect: v1.TaintEffectNoSchedule,

View File

@ -20,6 +20,7 @@ import (
"fmt" "fmt"
"time" "time"
v1 "k8s.io/api/core/v1"
"k8s.io/klog/v2" "k8s.io/klog/v2"
"k8s.io/mount-utils" "k8s.io/mount-utils"
@ -28,7 +29,6 @@ import (
internalapi "k8s.io/cri-api/pkg/apis" internalapi "k8s.io/cri-api/pkg/apis"
kubeletapp "k8s.io/kubernetes/cmd/kubelet/app" kubeletapp "k8s.io/kubernetes/cmd/kubelet/app"
"k8s.io/kubernetes/cmd/kubelet/app/options" "k8s.io/kubernetes/cmd/kubelet/app/options"
"k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/kubelet" "k8s.io/kubernetes/pkg/kubelet"
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config" kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
"k8s.io/kubernetes/pkg/kubelet/cadvisor" "k8s.io/kubernetes/pkg/kubelet/cadvisor"
@ -143,7 +143,7 @@ type HollowKubletOptions struct {
MaxPods int MaxPods int
PodsPerCore int PodsPerCore int
NodeLabels map[string]string NodeLabels map[string]string
RegisterWithTaints []core.Taint RegisterWithTaints []v1.Taint
} }
// Builds a KubeletConfiguration for the HollowKubelet, ensuring that the // Builds a KubeletConfiguration for the HollowKubelet, ensuring that the
@ -162,9 +162,7 @@ func GetHollowKubeletConfig(opt *HollowKubletOptions) (*options.KubeletFlags, *k
f.MaxPerPodContainerCount = 2 f.MaxPerPodContainerCount = 2
f.NodeLabels = opt.NodeLabels f.NodeLabels = opt.NodeLabels
f.ContainerRuntimeOptions.ContainerRuntime = kubetypes.RemoteContainerRuntime f.ContainerRuntimeOptions.ContainerRuntime = kubetypes.RemoteContainerRuntime
f.RegisterNode = true
f.RegisterSchedulable = true f.RegisterSchedulable = true
f.RegisterWithTaints = opt.RegisterWithTaints
f.RemoteImageEndpoint = "unix:///run/containerd/containerd.sock" f.RemoteImageEndpoint = "unix:///run/containerd/containerd.sock"
// Config struct // Config struct
@ -209,6 +207,8 @@ func GetHollowKubeletConfig(opt *HollowKubletOptions) (*options.KubeletFlags, *k
c.SerializeImagePulls = true c.SerializeImagePulls = true
c.SystemCgroups = "" c.SystemCgroups = ""
c.ProtectKernelDefaults = false c.ProtectKernelDefaults = false
c.RegisterWithTaints = opt.RegisterWithTaints
c.RegisterNode = true
return f, c return f, c
} }

View File

@ -30,6 +30,7 @@ import (
utilnet "k8s.io/apimachinery/pkg/util/net" utilnet "k8s.io/apimachinery/pkg/util/net"
corev1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" corev1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config" kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
utiltaints "k8s.io/kubernetes/pkg/util/taints"
netutils "k8s.io/utils/net" netutils "k8s.io/utils/net"
) )
@ -40,6 +41,7 @@ var (
_ pflag.Value = &IPPortVar{} _ pflag.Value = &IPPortVar{}
_ pflag.Value = &PortRangeVar{} _ pflag.Value = &PortRangeVar{}
_ pflag.Value = &ReservedMemoryVar{} _ pflag.Value = &ReservedMemoryVar{}
_ pflag.Value = &RegisterWithTaintsVar{}
) )
// IPVar is used for validating a command line option that represents an IP. It implements the pflag.Value interface // IPVar is used for validating a command line option that represents an IP. It implements the pflag.Value interface
@ -255,3 +257,44 @@ func (v *ReservedMemoryVar) String() string {
func (v *ReservedMemoryVar) Type() string { func (v *ReservedMemoryVar) Type() string {
return "reserved-memory" return "reserved-memory"
} }
// RegisterWithTaintsVar is used for validating a command line option that represents a register with taints. It implements the pflag.Value interface
type RegisterWithTaintsVar struct {
Value *[]v1.Taint
}
// Set sets the flag value
func (t RegisterWithTaintsVar) Set(s string) error {
if len(s) == 0 {
*t.Value = nil
return nil
}
sts := strings.Split(s, ",")
corev1Taints, _, err := utiltaints.ParseTaints(sts)
if err != nil {
return err
}
var taints []v1.Taint
for _, ct := range corev1Taints {
taints = append(taints, v1.Taint{Key: ct.Key, Value: ct.Value, Effect: v1.TaintEffect(ct.Effect)})
}
*t.Value = taints
return nil
}
// String returns the flag value
func (t RegisterWithTaintsVar) String() string {
if len(*t.Value) == 0 {
return ""
}
var taints []string
for _, taint := range *t.Value {
taints = append(taints, fmt.Sprintf("%s=%s:%s", taint.Key, taint.Value, taint.Effect))
}
return strings.Join(taints, ",")
}
// Type gets the flag type
func (t RegisterWithTaintsVar) Type() string {
return "[]v1.Taint"
}

View File

@ -18,6 +18,7 @@ package flag
import ( import (
"fmt" "fmt"
"reflect"
"strings" "strings"
"testing" "testing"
@ -287,3 +288,62 @@ func TestReservedMemoryVar(t *testing.T) {
} }
} }
} }
func TestTaintsVar(t *testing.T) {
cases := []struct {
f string
err bool
t []v1.Taint
}{
{
f: "",
t: []v1.Taint(nil),
},
{
f: "--t=foo=bar:NoSchedule",
t: []v1.Taint{{Key: "foo", Value: "bar", Effect: "NoSchedule"}},
},
{
f: "--t=baz:NoSchedule",
t: []v1.Taint{{Key: "baz", Value: "", Effect: "NoSchedule"}},
},
{
f: "--t=foo=bar:NoSchedule,baz:NoSchedule,bing=bang:PreferNoSchedule,qux=:NoSchedule",
t: []v1.Taint{
{Key: "foo", Value: "bar", Effect: v1.TaintEffectNoSchedule},
{Key: "baz", Value: "", Effect: "NoSchedule"},
{Key: "bing", Value: "bang", Effect: v1.TaintEffectPreferNoSchedule},
{Key: "qux", Value: "", Effect: "NoSchedule"},
},
},
{
f: "--t=dedicated-for=user1:NoExecute,baz:NoSchedule,foo-bar=:NoSchedule",
t: []v1.Taint{
{Key: "dedicated-for", Value: "user1", Effect: "NoExecute"},
{Key: "baz", Value: "", Effect: "NoSchedule"},
{Key: "foo-bar", Value: "", Effect: "NoSchedule"},
},
},
}
for i, c := range cases {
args := append([]string{"test"}, strings.Fields(c.f)...)
cli := pflag.NewFlagSet("test", pflag.ContinueOnError)
var taints []v1.Taint
cli.Var(RegisterWithTaintsVar{Value: &taints}, "t", "bar")
err := cli.Parse(args)
if err == nil && c.err {
t.Errorf("[%v] expected error", i)
continue
}
if err != nil && !c.err {
t.Errorf("[%v] unexpected error: %v", i, err)
continue
}
if !reflect.DeepEqual(c.t, taints) {
t.Errorf("[%v] unexpected taints:\n\texpected:\n\t\t%#v\n\tgot:\n\t\t%#v", i, c.t, taints)
}
}
}

View File

@ -21,11 +21,10 @@ import (
"fmt" "fmt"
"strings" "strings"
"k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
utilerrors "k8s.io/apimachinery/pkg/util/errors" utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/core/helper" "k8s.io/kubernetes/pkg/apis/core/helper"
) )
@ -88,51 +87,6 @@ func validateTaintEffect(effect v1.TaintEffect) error {
return nil return nil
} }
// NewTaintsVar wraps []api.Taint in a struct that implements flag.Value to allow taints to be
// bound to command line flags.
func NewTaintsVar(ptr *[]api.Taint) taintsVar {
return taintsVar{
ptr: ptr,
}
}
type taintsVar struct {
ptr *[]api.Taint
}
func (t taintsVar) Set(s string) error {
if len(s) == 0 {
*t.ptr = nil
return nil
}
sts := strings.Split(s, ",")
var taints []api.Taint
for _, st := range sts {
taint, err := parseTaint(st)
if err != nil {
return err
}
taints = append(taints, api.Taint{Key: taint.Key, Value: taint.Value, Effect: api.TaintEffect(taint.Effect)})
}
*t.ptr = taints
return nil
}
func (t taintsVar) String() string {
if len(*t.ptr) == 0 {
return ""
}
var taints []string
for _, taint := range *t.ptr {
taints = append(taints, fmt.Sprintf("%s=%s:%s", taint.Key, taint.Value, taint.Effect))
}
return strings.Join(taints, ",")
}
func (t taintsVar) Type() string {
return "[]api.Taint"
}
// ParseTaints takes a spec which is an array and creates slices for new taints to be added, taints to be deleted. // ParseTaints takes a spec which is an array and creates slices for new taints to be added, taints to be deleted.
// It also validates the spec. For example, the form `<key>` may be used to remove a taint, but not to add one. // It also validates the spec. For example, the form `<key>` may be used to remove a taint, but not to add one.
func ParseTaints(spec []string) ([]v1.Taint, []v1.Taint, error) { func ParseTaints(spec []string) ([]v1.Taint, []v1.Taint, error) {
@ -350,3 +304,23 @@ func TaintSetFilter(taints []v1.Taint, fn func(*v1.Taint) bool) []v1.Taint {
return res return res
} }
// CheckTaintValidation checks if the given taint is valid.
// Returns error if the given taint is invalid.
func CheckTaintValidation(taint v1.Taint) error {
if errs := validation.IsQualifiedName(taint.Key); len(errs) > 0 {
return fmt.Errorf("invalid taint key: %s", strings.Join(errs, "; "))
}
if taint.Value != "" {
if errs := validation.IsValidLabelValue(taint.Value); len(errs) > 0 {
return fmt.Errorf("invalid taint value: %s", strings.Join(errs, "; "))
}
}
if taint.Effect != "" {
if err := validateTaintEffect(taint.Effect); err != nil {
return err
}
}
return nil
}

View File

@ -21,71 +21,9 @@ import (
"strings" "strings"
"testing" "testing"
"k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
api "k8s.io/kubernetes/pkg/apis/core"
"github.com/spf13/pflag"
) )
func TestTaintsVar(t *testing.T) {
cases := []struct {
f string
err bool
t []api.Taint
}{
{
f: "",
t: []api.Taint(nil),
},
{
f: "--t=foo=bar:NoSchedule",
t: []api.Taint{{Key: "foo", Value: "bar", Effect: "NoSchedule"}},
},
{
f: "--t=baz:NoSchedule",
t: []api.Taint{{Key: "baz", Value: "", Effect: "NoSchedule"}},
},
{
f: "--t=foo=bar:NoSchedule,baz:NoSchedule,bing=bang:PreferNoSchedule,qux=:NoSchedule",
t: []api.Taint{
{Key: "foo", Value: "bar", Effect: api.TaintEffectNoSchedule},
{Key: "baz", Value: "", Effect: "NoSchedule"},
{Key: "bing", Value: "bang", Effect: api.TaintEffectPreferNoSchedule},
{Key: "qux", Value: "", Effect: "NoSchedule"},
},
},
{
f: "--t=dedicated-for=user1:NoExecute,baz:NoSchedule,foo-bar=:NoSchedule",
t: []api.Taint{
{Key: "dedicated-for", Value: "user1", Effect: "NoExecute"},
{Key: "baz", Value: "", Effect: "NoSchedule"},
{Key: "foo-bar", Value: "", Effect: "NoSchedule"},
},
},
}
for i, c := range cases {
args := append([]string{"test"}, strings.Fields(c.f)...)
cli := pflag.NewFlagSet("test", pflag.ContinueOnError)
var taints []api.Taint
cli.Var(NewTaintsVar(&taints), "t", "bar")
err := cli.Parse(args)
if err == nil && c.err {
t.Errorf("[%v] expected error", i)
continue
}
if err != nil && !c.err {
t.Errorf("[%v] unexpected error: %v", i, err)
continue
}
if !reflect.DeepEqual(c.t, taints) {
t.Errorf("[%v] unexpected taints:\n\texpected:\n\t\t%#v\n\tgot:\n\t\t%#v", i, c.t, taints)
}
}
}
func TestAddOrUpdateTaint(t *testing.T) { func TestAddOrUpdateTaint(t *testing.T) {
node := &v1.Node{} node := &v1.Node{}
@ -757,3 +695,50 @@ func TestParseTaints(t *testing.T) {
} }
} }
} }
func TestValidateTaint(t *testing.T) {
cases := []struct {
name string
taintsToCheck v1.Taint
expectedErr bool
}{
{
name: "taint invalid key",
taintsToCheck: v1.Taint{Key: "", Value: "bar_1", Effect: v1.TaintEffectNoExecute},
expectedErr: true,
},
{
name: "taint invalid value",
taintsToCheck: v1.Taint{Key: "foo_1", Value: strings.Repeat("a", 64), Effect: v1.TaintEffectNoExecute},
expectedErr: true,
},
{
name: "taint invalid effect",
taintsToCheck: v1.Taint{Key: "foo_2", Value: "bar_2", Effect: "no_such_effect"},
expectedErr: true,
},
{
name: "valid taint",
taintsToCheck: v1.Taint{Key: "foo_3", Value: "bar_3", Effect: v1.TaintEffectNoExecute},
expectedErr: false,
},
{
name: "valid taint",
taintsToCheck: v1.Taint{Key: "foo_4", Effect: v1.TaintEffectNoExecute},
expectedErr: false,
},
{
name: "valid taint",
taintsToCheck: v1.Taint{Key: "foo_5", Value: "bar_5"},
expectedErr: false,
},
}
for _, c := range cases {
err := CheckTaintValidation(c.taintsToCheck)
if c.expectedErr && err == nil {
t.Errorf("[%s] expected error for spec %+v, but got nothing", c.name, c.taintsToCheck)
}
}
}

View File

@ -1033,6 +1033,16 @@ type KubeletConfiguration struct {
// +featureGate=MemoryQoS // +featureGate=MemoryQoS
// +optional // +optional
MemoryThrottlingFactor *float64 `json:"memoryThrottlingFactor,omitempty"` MemoryThrottlingFactor *float64 `json:"memoryThrottlingFactor,omitempty"`
// registerWithTaints are an array of taints to add to a node object when
// the kubelet registers itself. This only takes effect when registerNode
// is true and upon the initial registration of the node.
// Default: nil
// +optional
RegisterWithTaints []v1.Taint `json:"registerWithTaints,omitempty"`
// registerNode enables automatic registration with the apiserver.
// Default: true
// +optional
RegisterNode *bool `json:"registerNode,omitempty"`
} }
type KubeletAuthorizationMode string type KubeletAuthorizationMode string

View File

@ -345,6 +345,18 @@ func (in *KubeletConfiguration) DeepCopyInto(out *KubeletConfiguration) {
*out = new(float64) *out = new(float64)
**out = **in **out = **in
} }
if in.RegisterWithTaints != nil {
in, out := &in.RegisterWithTaints, &out.RegisterWithTaints
*out = make([]corev1.Taint, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.RegisterNode != nil {
in, out := &in.RegisterNode, &out.RegisterNode
*out = new(bool)
**out = **in
}
return return
} }