diff --git a/cmd/kubeadm/app/phases/upgrade/staticpods.go b/cmd/kubeadm/app/phases/upgrade/staticpods.go index b7b726a68a0..851732ace99 100644 --- a/cmd/kubeadm/app/phases/upgrade/staticpods.go +++ b/cmd/kubeadm/app/phases/upgrade/staticpods.go @@ -189,10 +189,18 @@ func (spm *KubeStaticPodPathManager) CleanupDirs() error { func upgradeComponent(component string, certsRenewMgr *renewal.Manager, waiter apiclient.Waiter, pathMgr StaticPodPathManager, cfg *kubeadmapi.InitConfiguration, beforePodHash string, recoverManifests map[string]string) error { // Special treatment is required for etcd case, when rollbackOldManifests should roll back etcd - // manifests only for the case when component is Etcd + // manifests only for the case when component is Etcd. Also check if the kube-apiserver needs an upgrade + // by comparing its manifests and later decide if etcd certs can be renewed and etcd can be restarted. recoverEtcd := false + apiServerUpgrade := false if component == constants.Etcd { recoverEtcd = true + equal, _, err := staticpod.ManifestFilesAreEqual(pathMgr.RealManifestPath(constants.KubeAPIServer), + pathMgr.TempManifestPath(constants.KubeAPIServer)) + if err != nil { + return err + } + apiServerUpgrade = !equal } fmt.Printf("[upgrade/staticpods] Preparing for %q upgrade\n", component) @@ -214,8 +222,12 @@ func upgradeComponent(component string, certsRenewMgr *renewal.Manager, waiter a return err } if equal { - fmt.Printf("[upgrade/staticpods] Current and new manifests of %s are equal, skipping upgrade\n", component) - return nil + if !apiServerUpgrade { + fmt.Printf("[upgrade/staticpods] Current and new manifests of %s are equal, skipping upgrade\n", component) + return nil + } + klog.V(4).Infof("[upgrade/staticpods] Current and new manifests of %s are equal, but %s will be upgraded\n", + component, constants.KubeAPIServer) } else { klog.V(4).Infof("Pod manifest files diff:\n%s\n", diff) } @@ -228,6 +240,15 @@ func upgradeComponent(component string, certsRenewMgr *renewal.Manager, waiter a } } + // This can only happen if the component is etcd, cert renewal is enabled and kube-apiserver needs an upgrade + if equal && certsRenewMgr != nil { + fmt.Printf("[upgrade/staticpods] Restarting the %s static pod and backing up its manifest to %q\n", + component, backupManifestPath) + } else { + fmt.Printf("[upgrade/staticpods] Moving new manifest to %q and backing up old manifest to %q\n", + currentManifestPath, backupManifestPath) + } + // Move the old manifest into the old-manifests directory if err := pathMgr.MoveFile(currentManifestPath, backupManifestPath); err != nil { return rollbackOldManifests(recoverManifests, err, pathMgr, recoverEtcd) @@ -238,8 +259,6 @@ func upgradeComponent(component string, certsRenewMgr *renewal.Manager, waiter a return rollbackOldManifests(recoverManifests, err, pathMgr, recoverEtcd) } - fmt.Printf("[upgrade/staticpods] Moved new manifest to %q and backed up old manifest to %q\n", currentManifestPath, backupManifestPath) - fmt.Println("[upgrade/staticpods] Waiting for the kubelet to restart the component") fmt.Printf("[upgrade/staticpods] This can take up to %v\n", kubeadmapi.GetActiveTimeouts().UpgradeManifests.Duration) @@ -247,8 +266,10 @@ func upgradeComponent(component string, certsRenewMgr *renewal.Manager, waiter a // notice the removal of the Static Pod, leading to a false positive below where we check that the API endpoint is healthy // If we don't do this, there is a case where we remove the Static Pod manifest, kubelet is slow to react, kubeadm checks the // API endpoint below of the OLD Static Pod component and proceeds quickly enough, which might lead to unexpected results. - if err := waiter.WaitForStaticPodHashChange(cfg.NodeRegistration.Name, component, beforePodHash); err != nil { - return rollbackOldManifests(recoverManifests, err, pathMgr, recoverEtcd) + if !equal { + if err := waiter.WaitForStaticPodHashChange(cfg.NodeRegistration.Name, component, beforePodHash); err != nil { + return rollbackOldManifests(recoverManifests, err, pathMgr, recoverEtcd) + } } // Wait for the static pod component to come up and register itself as a mirror pod @@ -453,11 +474,16 @@ func StaticPodControlPlane(client clientset.Interface, waiter apiclient.Waiter, } } + // Write the updated static Pod manifests into the temporary directory. + // As part of the design, this must be called before the below performEtcdStaticPodUpgrade() call. + fmt.Printf("[upgrade/staticpods] Writing new Static Pod manifests to %q\n", pathMgr.TempManifestDir()) + err = controlplane.CreateInitStaticPodManifestFiles(pathMgr.TempManifestDir(), pathMgr.PatchesDir(), cfg, false /* isDryRun */) + if err != nil { + return errors.Wrap(err, "error creating init static pod manifest files") + } + // etcd upgrade is done prior to other control plane components if !isExternalEtcd && etcdUpgrade { - // set the TLS upgrade flag for all components - fmt.Printf("[upgrade/etcd] Upgrading to TLS for %s\n", constants.Etcd) - // Perform etcd upgrade using common to all control plane components function fatal, err := performEtcdStaticPodUpgrade(certsRenewMgr, client, waiter, pathMgr, cfg, recoverManifests, oldEtcdClient, newEtcdClient) if err != nil { @@ -468,13 +494,7 @@ func StaticPodControlPlane(client clientset.Interface, waiter apiclient.Waiter, } } - // Write the updated static Pod manifests into the temporary directory - fmt.Printf("[upgrade/staticpods] Writing new Static Pod manifests to %q\n", pathMgr.TempManifestDir()) - err = controlplane.CreateInitStaticPodManifestFiles(pathMgr.TempManifestDir(), pathMgr.PatchesDir(), cfg, false /* isDryRun */) - if err != nil { - return errors.Wrap(err, "error creating init static pod manifest files") - } - + // Upgrade the rest of the control plane components for _, component := range constants.ControlPlaneComponents { if err = upgradeComponent(component, certsRenewMgr, waiter, pathMgr, cfg, beforePodHashMap[component], recoverManifests); err != nil { return err