From 9d4b91dbd802cebe2539ec028d06eefba80b5b3a Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Wed, 17 Sep 2025 15:19:09 +0200 Subject: [PATCH] kubeadm: cleanup after ControlPlaneKubeletLocalMode --- cmd/kubeadm/app/cmd/phases/init/kubeconfig.go | 9 ++-- .../app/cmd/phases/join/controlplanejoin.go | 19 +++----- cmd/kubeadm/app/cmd/phases/join/data.go | 17 ------- cmd/kubeadm/app/cmd/phases/join/kubelet.go | 44 ++++--------------- cmd/kubeadm/app/phases/upgrade/postupgrade.go | 24 +++------- 5 files changed, 24 insertions(+), 89 deletions(-) diff --git a/cmd/kubeadm/app/cmd/phases/init/kubeconfig.go b/cmd/kubeadm/app/cmd/phases/init/kubeconfig.go index 2e95cd1990b..d8ce56ad360 100644 --- a/cmd/kubeadm/app/cmd/phases/init/kubeconfig.go +++ b/cmd/kubeadm/app/cmd/phases/init/kubeconfig.go @@ -24,7 +24,6 @@ import ( "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow" cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" - "k8s.io/kubernetes/cmd/kubeadm/app/features" kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" "k8s.io/kubernetes/cmd/kubeadm/app/util/errors" @@ -158,11 +157,9 @@ func runKubeConfigFile(kubeConfigFileName string) func(workflow.RunData) error { initConfiguration := data.Cfg().DeepCopy() - if features.Enabled(cfg.FeatureGates, features.ControlPlaneKubeletLocalMode) { - if kubeConfigFileName == kubeadmconstants.KubeletKubeConfigFileName { - // Unset the ControlPlaneEndpoint so the creation falls back to the LocalAPIEndpoint for the kubelet's kubeconfig. - initConfiguration.ControlPlaneEndpoint = "" - } + if kubeConfigFileName == kubeadmconstants.KubeletKubeConfigFileName { + // Unset the ControlPlaneEndpoint so the creation falls back to the LocalAPIEndpoint for the kubelet's kubeconfig. + initConfiguration.ControlPlaneEndpoint = "" } // creates the KubeConfig file (or use existing) diff --git a/cmd/kubeadm/app/cmd/phases/join/controlplanejoin.go b/cmd/kubeadm/app/cmd/phases/join/controlplanejoin.go index 860175e8add..c30df5f6577 100644 --- a/cmd/kubeadm/app/cmd/phases/join/controlplanejoin.go +++ b/cmd/kubeadm/app/cmd/phases/join/controlplanejoin.go @@ -24,7 +24,6 @@ import ( "k8s.io/kubernetes/cmd/kubeadm/app/cmd/options" "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow" cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util" - "k8s.io/kubernetes/cmd/kubeadm/app/features" etcdphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd" markcontrolplanephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/markcontrolplane" "k8s.io/kubernetes/cmd/kubeadm/app/util/errors" @@ -83,32 +82,26 @@ func NewControlPlaneJoinPhase() workflow.Phase { func NewEtcdJoinPhase() workflow.Phase { return workflow.Phase{ Name: "etcd-join", - Short: fmt.Sprintf("[EXPERIMENTAL] Join etcd for control plane nodes (only used when feature gate %s is enabled)", features.ControlPlaneKubeletLocalMode), + Short: "Join etcd for control plane nodes", Run: runEtcdPhase, Example: etcdJoinExample, InheritFlags: getControlPlaneJoinPhaseFlags("etcd"), ArgsValidator: cobra.NoArgs, - // TODO: unhide this phase once ControlPlaneKubeletLocalMode goes GA: - // https://github.com/kubernetes/enhancements/issues/4471 - Hidden: true, - // Only run this phase as if `ControlPlaneKubeletLocalMode` is activated. - RunIf: func(c workflow.RunData) (bool, error) { - return checkFeatureState(c, features.ControlPlaneKubeletLocalMode, true) - }, } } +// TODO: Deprecated. Remove once ControlPlaneKubeletLocalMode is removed in 1.36. +// https://github.com/kubernetes/kubeadm/issues/2271 func newEtcdLocalSubphase() workflow.Phase { return workflow.Phase{ Name: "etcd", - Short: "Add a new local etcd member", + Short: "[DEPRECATED] Add a new local etcd member. Deprecated in favor of 'etcd-join' and will be removed in 1.36", Run: runEtcdPhase, InheritFlags: getControlPlaneJoinPhaseFlags("etcd"), ArgsValidator: cobra.NoArgs, - // Only run this phase as subphase of control-plane-join phase if - // `ControlPlaneKubeletLocalMode` is deactivated. + Hidden: true, RunIf: func(c workflow.RunData) (bool, error) { - return checkFeatureState(c, features.ControlPlaneKubeletLocalMode, false) + return false, nil }, } } diff --git a/cmd/kubeadm/app/cmd/phases/join/data.go b/cmd/kubeadm/app/cmd/phases/join/data.go index 8005a6b07fd..bbfb8730cbe 100644 --- a/cmd/kubeadm/app/cmd/phases/join/data.go +++ b/cmd/kubeadm/app/cmd/phases/join/data.go @@ -25,9 +25,6 @@ import ( clientcmdapi "k8s.io/client-go/tools/clientcmd/api" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" - "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow" - "k8s.io/kubernetes/cmd/kubeadm/app/features" - "k8s.io/kubernetes/cmd/kubeadm/app/util/errors" ) // JoinData is the interface to use for join phases. @@ -47,17 +44,3 @@ type JoinData interface { ManifestDir() string CertificateWriteDir() string } - -func checkFeatureState(c workflow.RunData, featureGate string, state bool) (bool, error) { - data, ok := c.(JoinData) - if !ok { - return false, errors.New("control-plane-join phase invoked with an invalid data struct") - } - - cfg, err := data.InitCfg() - if err != nil { - return false, err - } - - return state == features.Enabled(cfg.FeatureGates, featureGate), nil -} diff --git a/cmd/kubeadm/app/cmd/phases/join/kubelet.go b/cmd/kubeadm/app/cmd/phases/join/kubelet.go index 751ab305d5c..822bf7a509f 100644 --- a/cmd/kubeadm/app/cmd/phases/join/kubelet.go +++ b/cmd/kubeadm/app/cmd/phases/join/kubelet.go @@ -75,20 +75,13 @@ func NewKubeletStartPhase() workflow.Phase { func NewKubeletWaitBootstrapPhase() workflow.Phase { return workflow.Phase{ Name: "kubelet-wait-bootstrap", - Short: "[EXPERIMENTAL] Wait for the kubelet to bootstrap itself (only used when feature gate ControlPlaneKubeletLocalMode is enabled)", + Short: "Wait for the kubelet to bootstrap itself", Run: runKubeletWaitBootstrapPhase, InheritFlags: []string{ options.CfgPath, options.NodeCRISocket, options.DryRun, }, - // TODO: unhide this phase once ControlPlaneKubeletLocalMode goes GA: - // https://github.com/kubernetes/enhancements/issues/4471 - Hidden: true, - // Only run this phase as if `ControlPlaneKubeletLocalMode` is activated. - RunIf: func(c workflow.RunData) (bool, error) { - return checkFeatureState(c, features.ControlPlaneKubeletLocalMode, true) - }, } } @@ -124,16 +117,6 @@ func runKubeletStartJoinPhase(c workflow.RunData) (returnErr error) { } bootstrapKubeConfigFile := filepath.Join(data.KubeConfigDir(), kubeadmconstants.KubeletBootstrapKubeConfigFileName) - // Do not delete the bootstrapKubeConfigFile at the end of this function when - // using ControlPlaneKubeletLocalMode. The KubeletWaitBootstrapPhase will delete - // it when the feature is enabled. - if !features.Enabled(initCfg.FeatureGates, features.ControlPlaneKubeletLocalMode) { - // Deletes the bootstrapKubeConfigFile, so the credential used for TLS bootstrap is removed from disk - defer func() { - _ = os.Remove(bootstrapKubeConfigFile) - }() - } - var client clientset.Interface // If dry-use the client from joinData, else create a new bootstrap client if data.DryRun() { @@ -148,17 +131,15 @@ func runKubeletStartJoinPhase(c workflow.RunData) (returnErr error) { } } - if features.Enabled(initCfg.FeatureGates, features.ControlPlaneKubeletLocalMode) { - // Set the server url to LocalAPIEndpoint if the feature gate is enabled so the config - // which gets passed to the kubelet forces it to talk to the local kube-apiserver. - if cfg.ControlPlane != nil { - for c, conf := range tlsBootstrapCfg.Clusters { - conf.Server, err = kubeadmutil.GetLocalAPIEndpoint(&cfg.ControlPlane.LocalAPIEndpoint) - if err != nil { - return errors.Wrapf(err, "could not get LocalAPIEndpoint when %s is enabled", features.ControlPlaneKubeletLocalMode) - } - tlsBootstrapCfg.Clusters[c] = conf + // Set the server url to LocalAPIEndpoint if the feature gate is enabled so the config + // which gets passed to the kubelet forces it to talk to the local kube-apiserver. + if cfg.ControlPlane != nil { + for c, conf := range tlsBootstrapCfg.Clusters { + conf.Server, err = kubeadmutil.GetLocalAPIEndpoint(&cfg.ControlPlane.LocalAPIEndpoint) + if err != nil { + return errors.Wrapf(err, "could not get LocalAPIEndpoint") } + tlsBootstrapCfg.Clusters[c] = conf } } @@ -252,13 +233,6 @@ func runKubeletStartJoinPhase(c workflow.RunData) (returnErr error) { fmt.Println("[kubelet-start] Starting the kubelet") kubeletphase.TryStartKubelet() - // Run the same code as KubeletWaitBootstrapPhase would do if the ControlPlaneKubeletLocalMode feature gate is disabled. - if !features.Enabled(initCfg.FeatureGates, features.ControlPlaneKubeletLocalMode) { - if err := runKubeletWaitBootstrapPhase(c); err != nil { - return err - } - } - return nil } diff --git a/cmd/kubeadm/app/phases/upgrade/postupgrade.go b/cmd/kubeadm/app/phases/upgrade/postupgrade.go index 9ae50e05e5c..caa67ef931d 100644 --- a/cmd/kubeadm/app/phases/upgrade/postupgrade.go +++ b/cmd/kubeadm/app/phases/upgrade/postupgrade.go @@ -180,10 +180,7 @@ func WriteKubeletConfigFiles(cfg *kubeadmapi.InitConfiguration, kubeletDir strin return nil } -// UpdateKubeletKubeconfigServer changes the Server URL in the kubelets kubeconfig if necessary depending on the -// ControlPlaneKubeletLocalMode feature gate. -// TODO: remove this function once ControlPlaneKubeletLocalMode goes GA and is hardcoded to be enabled by default: -// https://github.com/kubernetes/kubeadm/issues/2271 +// UpdateKubeletKubeconfigServer changes the Server URL in the kubelet's kubeconfig if necessary. func UpdateKubeletKubeconfigServer(cfg *kubeadmapi.InitConfiguration, dryRun bool) error { kubeletKubeConfigFilePath := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.KubeletKubeConfigFileName) @@ -216,21 +213,12 @@ func UpdateKubeletKubeconfigServer(cfg *kubeadmapi.InitConfiguration, dryRun boo } var targetServer string - if features.Enabled(cfg.FeatureGates, features.ControlPlaneKubeletLocalMode) { - // Skip changing kubeconfig file if Server does not match the ControlPlaneEndpoint. - if config.Clusters[configContext.Cluster].Server != controlPlaneAPIEndpoint || controlPlaneAPIEndpoint == localAPIEndpoint { - klog.V(2).Infof("Skipping update of the Server URL in %s, because it's already not equal to %q or already matches the localAPIEndpoint", kubeletKubeConfigFilePath, controlPlaneAPIEndpoint) - return nil - } - targetServer = localAPIEndpoint - } else { - // Skip changing kubeconfig file if Server does not match the localAPIEndpoint. - if config.Clusters[configContext.Cluster].Server != localAPIEndpoint { - klog.V(2).Infof("Skipping update of the Server URL in %s, because it already matches the controlPlaneAPIEndpoint", kubeletKubeConfigFilePath) - return nil - } - targetServer = controlPlaneAPIEndpoint + // Skip changing kubeconfig file if Server does not match the ControlPlaneEndpoint. + if config.Clusters[configContext.Cluster].Server != controlPlaneAPIEndpoint || controlPlaneAPIEndpoint == localAPIEndpoint { + klog.V(2).Infof("Skipping update of the Server URL in %s, because it's already not equal to %q or already matches the localAPIEndpoint", kubeletKubeConfigFilePath, controlPlaneAPIEndpoint) + return nil } + targetServer = localAPIEndpoint if dryRun { fmt.Printf("[dryrun] Would change the Server URL from %q to %q in %s and try to restart kubelet\n", config.Clusters[configContext.Cluster].Server, targetServer, kubeletKubeConfigFilePath)