Merge pull request #127242 from SataQiu/refactor-upgrade-node

kubeadm: add addon and post-upgrade phases for 'kubeadm upgrade node'
This commit is contained in:
Kubernetes Prow Robot 2024-09-10 09:55:15 +01:00 committed by GitHub
commit e30d994129
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 131 additions and 220 deletions

View File

@ -14,8 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// Package apply implements phases of 'kubeadm upgrade apply'.
package apply
// Package upgrade holds the common phases for 'kubeadm upgrade'.
package upgrade
import (
"fmt"
@ -28,7 +28,6 @@ import (
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"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"
dnsaddon "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns"
proxyaddon "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade"
@ -39,7 +38,6 @@ func NewAddonPhase() workflow.Phase {
return workflow.Phase{
Name: "addon",
Short: "Upgrade the default kubeadm addons",
Long: cmdutil.MacroCommandLongDescription,
Phases: []workflow.Phase{
{
Name: "all",
@ -98,7 +96,6 @@ func runCoreDNSAddon(c workflow.RunData) error {
return nil
}
// Upgrade CoreDNS
if err := dnsaddon.EnsureDNSAddon(&cfg.ClusterConfiguration, client, patchesDir, out, dryRun); err != nil {
return err
}
@ -121,7 +118,6 @@ func runKubeProxyAddon(c workflow.RunData) error {
return nil
}
// Upgrade kube-proxy
if err := proxyaddon.EnsureProxyAddon(&cfg.ClusterConfiguration, &cfg.LocalAPIEndpoint, client, out, dryRun); err != nil {
return err
}

View File

@ -18,26 +18,14 @@ limitations under the License.
package apply
import (
"io"
"k8s.io/apimachinery/pkg/util/sets"
clientset "k8s.io/client-go/kubernetes"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/upgrade"
)
// Data is the interface to use for kubeadm upgrade apply phases.
// The "applyData" type from "cmd/upgrade/apply.go" must satisfy this interface.
type Data interface {
EtcdUpgrade() bool
RenewCerts() bool
DryRun() bool
Cfg() *kubeadmapi.UpgradeConfiguration
InitCfg() *kubeadmapi.InitConfiguration
Client() clientset.Interface
IgnorePreflightErrors() sets.Set[string]
PatchesDir() string
OutputWriter() io.Writer
upgrade.Data
SessionIsInteractive() bool
AllowExperimentalUpgrades() bool
AllowRCUpgrades() bool

View File

@ -28,7 +28,6 @@ import (
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"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"
kubeletphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet"
patchnodephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/patchnode"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig"
@ -40,7 +39,6 @@ func NewUploadConfigPhase() workflow.Phase {
Name: "upload-config",
Aliases: []string{"uploadconfig"},
Short: "Upload the kubeadm and kubelet configurations to ConfigMaps",
Long: cmdutil.MacroCommandLongDescription,
Phases: []workflow.Phase{
{
Name: "all",

View File

@ -0,0 +1,40 @@
/*
Copyright 2024 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package upgrade holds the common phases for 'kubeadm upgrade'.
package upgrade
import (
"io"
"k8s.io/apimachinery/pkg/util/sets"
clientset "k8s.io/client-go/kubernetes"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
)
// Data is the common interface to use for kubeadm upgrade phases.
type Data interface {
EtcdUpgrade() bool
RenewCerts() bool
DryRun() bool
Cfg() *kubeadmapi.UpgradeConfiguration
InitCfg() *kubeadmapi.InitConfiguration
Client() clientset.Interface
IgnorePreflightErrors() sets.Set[string]
PatchesDir() string
OutputWriter() io.Writer
}

View File

@ -0,0 +1,42 @@
/*
Copyright 2024 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package upgrade
import (
"io"
"k8s.io/apimachinery/pkg/util/sets"
clientset "k8s.io/client-go/kubernetes"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
)
// a package local type for testing purposes.
type testData struct{}
// testData must satisfy Data.
var _ Data = &testData{}
func (t *testData) EtcdUpgrade() bool { return false }
func (t *testData) RenewCerts() bool { return false }
func (t *testData) DryRun() bool { return false }
func (t *testData) Cfg() *kubeadmapi.UpgradeConfiguration { return nil }
func (t *testData) InitCfg() *kubeadmapi.InitConfiguration { return nil }
func (t *testData) Client() clientset.Interface { return nil }
func (t *testData) IgnorePreflightErrors() sets.Set[string] { return nil }
func (t *testData) PatchesDir() string { return "" }
func (t *testData) OutputWriter() io.Writer { return nil }

View File

@ -14,8 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// Package apply implements phases of 'kubeadm upgrade apply'.
package apply
// Package upgrade holds the common phases for 'kubeadm upgrade'.
package upgrade
import (
"fmt"
@ -57,16 +57,14 @@ func runKubeletConfigPhase(c workflow.RunData) error {
return errors.New("kubelet-config phase invoked with an invalid data struct")
}
initCfg, dryRun := data.InitCfg(), data.DryRun()
// Write the configuration for the kubelet down to disk and print the generated manifests instead of dry-running.
// If not dry-running, the kubelet config file will be backed up to the /etc/kubernetes/tmp/ dir, so that it could be
// recovered if anything goes wrong.
err := upgrade.WriteKubeletConfigFiles(initCfg, data.PatchesDir(), dryRun, data.OutputWriter())
err := upgrade.WriteKubeletConfigFiles(data.InitCfg(), data.PatchesDir(), data.DryRun(), data.OutputWriter())
if err != nil {
return err
}
fmt.Println("[upgrade/kubelet-config] The kubelet configuration for this node was successfully updated!")
fmt.Println("[upgrade/kubelet-config] The kubelet configuration for this node was successfully upgraded!")
return nil
}

View File

@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// Package node implements phases of 'kubeadm upgrade node'.
package node
import (
@ -28,13 +29,14 @@ import (
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
)
// NewControlPlane creates a kubeadm workflow phase that implements handling of control-plane upgrade.
// NewControlPlane returns a new control-plane phase.
func NewControlPlane() workflow.Phase {
phase := workflow.Phase{
Name: "control-plane",
Short: "Upgrade the control plane instance deployed on this node, if any",
Run: runControlPlane(),
InheritFlags: []string{
options.CfgPath,
options.DryRun,
options.KubeconfigPath,
options.CertificateRenewal,
@ -54,7 +56,7 @@ func runControlPlane() func(c workflow.RunData) error {
// if this is not a control-plane node, this phase should not be executed
if !data.IsControlPlaneNode() {
fmt.Println("[upgrade] Skipping phase. Not a control plane node.")
fmt.Println("[upgrade/control-plane] Skipping phase. Not a control plane node.")
return nil
}
@ -67,8 +69,9 @@ func runControlPlane() func(c workflow.RunData) error {
patchesDir := data.PatchesDir()
// Upgrade the control plane and etcd if installed on this node
fmt.Printf("[upgrade] Upgrading your Static Pod-hosted control plane instance to version %q...\n", cfg.KubernetesVersion)
fmt.Printf("[upgrade/control-plane] Upgrading your Static Pod-hosted control plane instance to version %q...\n", cfg.KubernetesVersion)
if dryRun {
fmt.Printf("[dryrun] Would upgrade your static Pod-hosted control plane to version %q", cfg.KubernetesVersion)
return upgrade.DryRunStaticPodUpgrade(patchesDir, cfg)
}
@ -78,11 +81,7 @@ func runControlPlane() func(c workflow.RunData) error {
return errors.Wrap(err, "couldn't complete the static pod upgrade")
}
if err := upgrade.PerformAddonsUpgrade(client, cfg, data.PatchesDir(), data.OutputWriter()); err != nil {
return errors.Wrap(err, "failed to perform addons upgrade")
}
fmt.Println("[upgrade] The control plane instance for this node was successfully updated!")
fmt.Println("[upgrade/control-plane] The control plane instance for this node was successfully upgraded!")
return nil
}

View File

@ -14,29 +14,18 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// Package node implements phases of 'kubeadm upgrade node'.
package node
import (
"io"
"k8s.io/apimachinery/pkg/util/sets"
clientset "k8s.io/client-go/kubernetes"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/upgrade"
)
// Data is the interface to use for kubeadm upgrade node phases.
// The "nodeData" type from "cmd/upgrade/node.go" must satisfy this interface.
type Data interface {
EtcdUpgrade() bool
RenewCerts() bool
DryRun() bool
Cfg() *kubeadmapi.UpgradeConfiguration
InitCfg() *kubeadmapi.InitConfiguration
upgrade.Data
IsControlPlaneNode() bool
Client() clientset.Interface
IgnorePreflightErrors() sets.Set[string]
PatchesDir() string
KubeConfigPath() string
OutputWriter() io.Writer
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// Package node holds phases of "kubeadm upgrade node".
// Package node implements phases of 'kubeadm upgrade node'.
package node
import (
@ -28,7 +28,7 @@ import (
"k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade"
)
// NewKubeconfigPhase creates a kubeadm workflow phase that implements handling of kubeconfig upgrade.
// NewKubeconfigPhase returns a new kubeconfig phase.
func NewKubeconfigPhase() workflow.Phase {
phase := workflow.Phase{
Name: "kubeconfig",
@ -36,6 +36,7 @@ func NewKubeconfigPhase() workflow.Phase {
Run: runKubeconfig(),
Hidden: true,
InheritFlags: []string{
options.CfgPath,
options.DryRun,
options.KubeconfigPath,
},
@ -50,23 +51,22 @@ func runKubeconfig() func(c workflow.RunData) error {
return errors.New("kubeconfig phase invoked with an invalid data struct")
}
// if this is not a control-plane node, this phase should not be executed
// If this is not a control-plane node, this phase should not be executed.
if !data.IsControlPlaneNode() {
fmt.Println("[upgrade] Skipping phase. Not a control plane node.")
fmt.Println("[upgrade/kubeconfig] Skipping phase. Not a control plane node.")
return nil
}
// otherwise, retrieve all the info required for kubeconfig upgrade
// Otherwise, retrieve all the info required for kubeconfig upgrade.
cfg := data.InitCfg()
dryRun := data.DryRun()
if features.Enabled(cfg.FeatureGates, features.ControlPlaneKubeletLocalMode) {
if err := upgrade.UpdateKubeletLocalMode(cfg, dryRun); err != nil {
if err := upgrade.UpdateKubeletLocalMode(cfg, data.DryRun()); err != nil {
return errors.Wrap(err, "failed to update kubelet local mode")
}
}
fmt.Println("[upgrade] The kubeconfig for this node was successfully updated!")
fmt.Println("[upgrade/kubeconfig] The kubeconfig files for this node were successfully upgraded!")
return nil
}

View File

@ -1,75 +0,0 @@
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package node
import (
"fmt"
"github.com/pkg/errors"
"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/phases/upgrade"
)
var (
kubeletConfigLongDesc = cmdutil.LongDesc(`
Download the kubelet configuration from the kubelet-config ConfigMap stored in the cluster
`)
)
// NewKubeletConfigPhase creates a kubeadm workflow phase that implements handling of kubelet-config upgrade.
func NewKubeletConfigPhase() workflow.Phase {
phase := workflow.Phase{
Name: "kubelet-config",
Short: "Upgrade the kubelet configuration for this node",
Long: kubeletConfigLongDesc,
Run: runKubeletConfigPhase(),
InheritFlags: []string{
options.DryRun,
options.KubeconfigPath,
options.Patches,
},
}
return phase
}
func runKubeletConfigPhase() func(c workflow.RunData) error {
return func(c workflow.RunData) error {
data, ok := c.(Data)
if !ok {
return errors.New("kubelet-config phase invoked with an invalid data struct")
}
// otherwise, retrieve all the info required for kubelet config upgrade
cfg := data.InitCfg()
dryRun := data.DryRun()
// Write the configuration for the kubelet down to disk and print the generated manifests instead if dry-running.
// If not dry-running, the kubelet config file will be backed up to /etc/kubernetes/tmp/ dir, so that it could be
// recovered if there is anything goes wrong.
err := upgrade.WriteKubeletConfigFiles(cfg, data.PatchesDir(), dryRun, data.OutputWriter())
if err != nil {
return err
}
fmt.Println("[upgrade] The configuration for this node was successfully updated!")
fmt.Println("[upgrade] Now you should go ahead and upgrade the kubelet package using your package manager.")
return nil
}
}

View File

@ -28,7 +28,7 @@ import (
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
)
// NewPreflightPhase creates a kubeadm workflow phase that implements preflight checks for a new node join
// NewPreflightPhase returns a new preflight phase.
func NewPreflightPhase() workflow.Phase {
return workflow.Phase{
Name: "preflight",
@ -36,6 +36,7 @@ func NewPreflightPhase() workflow.Phase {
Long: "Run pre-flight checks for kubeadm upgrade node.",
Run: runPreflight,
InheritFlags: []string{
options.CfgPath,
options.IgnorePreflightErrors,
},
}
@ -47,14 +48,14 @@ func runPreflight(c workflow.RunData) error {
if !ok {
return errors.New("preflight phase invoked with an invalid data struct")
}
fmt.Println("[preflight] Running pre-flight checks")
fmt.Println("[upgrade/preflight] Running pre-flight checks")
// First, check if we're root separately from the other preflight checks and fail fast
// First, check if we're root separately from the other preflight checks and fail fast.
if err := preflight.RunRootCheckOnly(data.IgnorePreflightErrors()); err != nil {
return err
}
// If this is a control-plane node, pull the basic images
// If this is a control-plane node, pull the basic images.
if data.IsControlPlaneNode() {
// Update the InitConfiguration used for RunPullImagesCheck with ImagePullPolicy and ImagePullSerial
// that come from UpgradeNodeConfiguration.
@ -63,17 +64,17 @@ func runPreflight(c workflow.RunData) error {
initConfig.NodeRegistration.ImagePullSerial = data.Cfg().Node.ImagePullSerial
if !data.DryRun() {
fmt.Println("[preflight] Pulling images required for setting up a Kubernetes cluster")
fmt.Println("[preflight] This might take a minute or two, depending on the speed of your internet connection")
fmt.Println("[preflight] You can also perform this action beforehand using 'kubeadm config images pull'")
fmt.Println("[upgrade/preflight] Pulling images required for setting up a Kubernetes cluster")
fmt.Println("[upgrade/preflight] This might take a minute or two, depending on the speed of your internet connection")
fmt.Println("[upgrade/preflight] You can also perform this action beforehand using 'kubeadm config images pull'")
if err := preflight.RunPullImagesCheck(utilsexec.New(), initConfig, data.IgnorePreflightErrors()); err != nil {
return err
}
} else {
fmt.Println("[preflight] Would pull the required images (like 'kubeadm config images pull')")
fmt.Println("[upgrade/preflight] Would pull the required images (like 'kubeadm config images pull')")
}
} else {
fmt.Println("[preflight] Skipping prepull. Not a control plane node.")
fmt.Println("[upgrade/preflight] Skipping prepull. Not a control plane node.")
return nil
}

View File

@ -14,8 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// Package apply implements phases of 'kubeadm upgrade apply'.
package apply
// Package upgrade holds the common phases for 'kubeadm upgrade'.
package upgrade
import (
"github.com/pkg/errors"
@ -41,7 +41,7 @@ func NewPostUpgradePhase() workflow.Phase {
func runPostUpgrade(c workflow.RunData) error {
_, ok := c.(Data)
if !ok {
return errors.New("preflight phase invoked with an invalid data struct")
return errors.New("post-upgrade phase invoked with an invalid data struct")
}
// PLACEHOLDER: this phase should contain any release specific post-upgrade tasks.

View File

@ -34,6 +34,7 @@ import (
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta4"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
commonphases "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/upgrade"
phases "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/upgrade/apply"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
@ -134,10 +135,10 @@ func newCmdApply(apf *applyPlanFlags) *cobra.Command {
applyRunner.AppendPhase(phases.NewControlPlanePhase())
applyRunner.AppendPhase(phases.NewUploadConfigPhase())
applyRunner.AppendPhase(phases.NewKubeconfigPhase())
applyRunner.AppendPhase(phases.NewKubeletConfigPhase())
applyRunner.AppendPhase(commonphases.NewKubeletConfigPhase())
applyRunner.AppendPhase(phases.NewBootstrapTokenPhase())
applyRunner.AppendPhase(phases.NewAddonPhase())
applyRunner.AppendPhase(phases.NewPostUpgradePhase())
applyRunner.AppendPhase(commonphases.NewAddonPhase())
applyRunner.AppendPhase(commonphases.NewPostUpgradePhase())
// Sets the data builder function, that will be used by the runner,
// both when running the entire workflow or single phases.

View File

@ -31,6 +31,7 @@ import (
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta4"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
commonphases "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/upgrade"
phases "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/upgrade/node"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
@ -98,7 +99,9 @@ func newCmdNode(out io.Writer) *cobra.Command {
nodeRunner.AppendPhase(phases.NewPreflightPhase())
nodeRunner.AppendPhase(phases.NewControlPlane())
nodeRunner.AppendPhase(phases.NewKubeconfigPhase())
nodeRunner.AppendPhase(phases.NewKubeletConfigPhase())
nodeRunner.AppendPhase(commonphases.NewKubeletConfigPhase())
nodeRunner.AppendPhase(commonphases.NewAddonPhase())
nodeRunner.AppendPhase(commonphases.NewPostUpgradePhase())
// sets the data builder function, that will be used by the runner
// both when running the entire workflow or single phases

View File

@ -25,7 +25,6 @@ import (
"github.com/pkg/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
errorsutil "k8s.io/apimachinery/pkg/util/errors"
@ -36,79 +35,11 @@ import (
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy"
kubeletphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
dryrunutil "k8s.io/kubernetes/cmd/kubeadm/app/util/dryrun"
)
// PerformAddonsUpgrade performs the upgrade of the coredns and kube-proxy addons.
func PerformAddonsUpgrade(client clientset.Interface, cfg *kubeadmapi.InitConfiguration, patchesDir string, out io.Writer) error {
unupgradedControlPlanes, err := UnupgradedControlPlaneInstances(client, cfg.NodeRegistration.Name)
if err != nil {
return errors.Wrapf(err, "failed to determine whether all the control plane instances have been upgraded")
}
if len(unupgradedControlPlanes) > 0 {
fmt.Fprintf(out, "[upgrade/addons] skip upgrade addons because control plane instances %v have not been upgraded\n", unupgradedControlPlanes)
return nil
}
var errs []error
// If the coredns ConfigMap is missing, show a warning and assume that the
// DNS addon was skipped during "kubeadm init", and that its redeployment on upgrade is not desired.
//
// TODO: remove this once "kubeadm upgrade apply" phases are supported:
// https://github.com/kubernetes/kubeadm/issues/1318
var missingCoreDNSConfigMap bool
if _, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(
context.TODO(),
kubeadmconstants.CoreDNSConfigMap,
metav1.GetOptions{},
); err != nil && apierrors.IsNotFound(err) {
missingCoreDNSConfigMap = true
}
if missingCoreDNSConfigMap {
klog.Warningf("the ConfigMaps %q in the namespace %q were not found. "+
"Assuming that a DNS server was not deployed for this cluster. "+
"Note that once 'kubeadm upgrade apply' supports phases you "+
"will have to skip the DNS upgrade manually",
kubeadmconstants.CoreDNSConfigMap,
metav1.NamespaceSystem)
} else {
// Upgrade CoreDNS
if err := dns.EnsureDNSAddon(&cfg.ClusterConfiguration, client, patchesDir, out, false); err != nil {
errs = append(errs, err)
}
}
// If the kube-proxy ConfigMap is missing, show a warning and assume that kube-proxy
// was skipped during "kubeadm init", and that its redeployment on upgrade is not desired.
//
// TODO: remove this once "kubeadm upgrade apply" phases are supported:
// https://github.com/kubernetes/kubeadm/issues/1318
if _, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(
context.TODO(),
kubeadmconstants.KubeProxyConfigMap,
metav1.GetOptions{},
); err != nil && apierrors.IsNotFound(err) {
klog.Warningf("the ConfigMap %q in the namespace %q was not found. "+
"Assuming that kube-proxy was not deployed for this cluster. "+
"Note that once 'kubeadm upgrade apply' supports phases you "+
"will have to skip the kube-proxy upgrade manually",
kubeadmconstants.KubeProxyConfigMap,
metav1.NamespaceSystem)
} else {
// Upgrade kube-proxy
if err := proxy.EnsureProxyAddon(&cfg.ClusterConfiguration, &cfg.LocalAPIEndpoint, client, out, false); err != nil {
errs = append(errs, err)
}
}
return errorsutil.NewAggregate(errs)
}
// UnupgradedControlPlaneInstances returns a list of control plane instances that have not yet been upgraded.
//
// NB. This function can only be called after the current control plane instance has been upgraded already.