@@ -31,10 +31,12 @@ import (
31
31
errorsutil "k8s.io/apimachinery/pkg/util/errors"
32
32
"k8s.io/apimachinery/pkg/util/sets"
33
33
clientset "k8s.io/client-go/kubernetes"
34
+ "k8s.io/client-go/tools/clientcmd"
34
35
"k8s.io/klog/v2"
35
36
36
37
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
37
38
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
39
+ "k8s.io/kubernetes/cmd/kubeadm/app/features"
38
40
"k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns"
39
41
"k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy"
40
42
"k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/clusterinfo"
@@ -109,6 +111,12 @@ func PerformPostUpgradeTasks(client clientset.Interface, cfg *kubeadmapi.InitCon
109
111
errs = append (errs , err )
110
112
}
111
113
114
+ if features .Enabled (cfg .FeatureGates , features .ControlPlaneKubeletLocalMode ) {
115
+ if err := UpdateKubeletLocalMode (cfg , dryRun ); err != nil {
116
+ return errors .Wrap (err , "failed to update kubelet local mode" )
117
+ }
118
+ }
119
+
112
120
return errorsutil .NewAggregate (errs )
113
121
}
114
122
@@ -281,3 +289,61 @@ func GetKubeletDir(dryRun bool) (string, error) {
281
289
}
282
290
return kubeadmconstants .KubeletRunDirectory , nil
283
291
}
292
+
293
+ // UpdateKubeletLocalMode changes the Server URL in the kubelets kubeconfig to the local API endpoint if it is currently
294
+ // set to the ControlPlaneEndpoint.
295
+ // TODO: remove this function once kubeletKubeConfigFilePath goes GA and is hardcoded to enabled by default:
296
+ // https://github.com/kubernetes/kubeadm/issues/2271
297
+ func UpdateKubeletLocalMode (cfg * kubeadmapi.InitConfiguration , dryRun bool ) error {
298
+ kubeletKubeConfigFilePath := filepath .Join (kubeadmconstants .KubernetesDir , kubeadmconstants .KubeletKubeConfigFileName )
299
+
300
+ if _ , err := os .Stat (kubeletKubeConfigFilePath ); err != nil {
301
+ if os .IsNotExist (err ) {
302
+ klog .V (2 ).Infof ("Could not mutate the Server URL in %s: %v" , kubeletKubeConfigFilePath , err )
303
+ return nil
304
+ }
305
+ return err
306
+ }
307
+
308
+ config , err := clientcmd .LoadFromFile (kubeletKubeConfigFilePath )
309
+ if err != nil {
310
+ return err
311
+ }
312
+
313
+ configContext , ok := config .Contexts [config .CurrentContext ]
314
+ if ! ok {
315
+ return errors .Errorf ("cannot find cluster for active context in kubeconfig %q" , kubeletKubeConfigFilePath )
316
+ }
317
+
318
+ localAPIEndpoint , err := kubeadmutil .GetLocalAPIEndpoint (& cfg .LocalAPIEndpoint )
319
+ if err != nil {
320
+ return err
321
+ }
322
+
323
+ controlPlaneAPIEndpoint , err := kubeadmutil .GetControlPlaneEndpoint (cfg .ControlPlaneEndpoint , & cfg .LocalAPIEndpoint )
324
+ if err != nil {
325
+ return err
326
+ }
327
+
328
+ // Skip changing kubeconfig file if Server does not match the ControlPlaneEndoint.
329
+ if config .Clusters [configContext .Cluster ].Server != controlPlaneAPIEndpoint || controlPlaneAPIEndpoint == localAPIEndpoint {
330
+ 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 , cfg .ControlPlaneEndpoint )
331
+ return nil
332
+ }
333
+
334
+ if dryRun {
335
+ 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 , localAPIEndpoint , kubeletKubeConfigFilePath )
336
+ return nil
337
+ }
338
+
339
+ klog .V (1 ).Infof ("Changing the Server URL from %q to %q in %s" , config .Clusters [configContext .Cluster ].Server , localAPIEndpoint , kubeletKubeConfigFilePath )
340
+ config .Clusters [configContext .Cluster ].Server = localAPIEndpoint
341
+
342
+ if err := clientcmd .WriteToFile (* config , kubeletKubeConfigFilePath ); err != nil {
343
+ return err
344
+ }
345
+
346
+ kubeletphase .TryRestartKubelet ()
347
+
348
+ return nil
349
+ }
0 commit comments