From 52302e4ad51e6014d013df303219dffc310f565a Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Sat, 1 Jun 2024 10:10:31 +0300 Subject: [PATCH] kubeadm: use the actual configured kubelet healthz address:port When doing a kubelet health check on init/join, do not hardcode the "localhost" address. Instead, use the KubeletConfiguration HealthzBindAddress and HealthzPort fields. --- cmd/kubeadm/app/cmd/phases/init/waitcontrolplane.go | 11 +++++++++-- cmd/kubeadm/app/cmd/phases/join/kubelet.go | 9 ++++++++- cmd/kubeadm/app/componentconfigs/kubelet.go | 2 +- cmd/kubeadm/app/phases/upgrade/staticpods_test.go | 2 +- cmd/kubeadm/app/util/apiclient/wait.go | 6 +++--- cmd/kubeadm/app/util/dryrun/dryrun.go | 4 ++-- 6 files changed, 24 insertions(+), 10 deletions(-) diff --git a/cmd/kubeadm/app/cmd/phases/init/waitcontrolplane.go b/cmd/kubeadm/app/cmd/phases/init/waitcontrolplane.go index cfa5ff901d7..e74d8b20960 100644 --- a/cmd/kubeadm/app/cmd/phases/init/waitcontrolplane.go +++ b/cmd/kubeadm/app/cmd/phases/init/waitcontrolplane.go @@ -26,8 +26,10 @@ import ( "github.com/pkg/errors" clientset "k8s.io/client-go/kubernetes" + kubeletconfig "k8s.io/kubelet/config/v1beta1" "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow" + "k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs" "k8s.io/kubernetes/cmd/kubeadm/app/features" "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient" dryrunutil "k8s.io/kubernetes/cmd/kubeadm/app/util/dryrun" @@ -107,11 +109,16 @@ func runWaitControlPlanePhase(c workflow.RunData) error { } kubeletFailTempl.Execute(data.OutputWriter(), context) - return errors.New("couldn't initialize a Kubernetes cluster") + return errors.New("could not initialize a Kubernetes cluster") } waiter.SetTimeout(data.Cfg().Timeouts.KubeletHealthCheck.Duration) - if err := waiter.WaitForKubelet(); err != nil { + kubeletConfig := data.Cfg().ClusterConfiguration.ComponentConfigs[componentconfigs.KubeletGroup].Get() + kubeletConfigTyped, ok := kubeletConfig.(*kubeletconfig.KubeletConfiguration) + if !ok { + return errors.New("could not convert the KubeletConfiguration to a typed object") + } + if err := waiter.WaitForKubelet(kubeletConfigTyped.HealthzBindAddress, *kubeletConfigTyped.HealthzPort); err != nil { return handleError(err) } diff --git a/cmd/kubeadm/app/cmd/phases/join/kubelet.go b/cmd/kubeadm/app/cmd/phases/join/kubelet.go index b5395b11305..a24386df8f6 100644 --- a/cmd/kubeadm/app/cmd/phases/join/kubelet.go +++ b/cmd/kubeadm/app/cmd/phases/join/kubelet.go @@ -33,10 +33,12 @@ import ( clientcmdapi "k8s.io/client-go/tools/clientcmd/api" certutil "k8s.io/client-go/util/cert" "k8s.io/klog/v2" + kubeletconfig "k8s.io/kubelet/config/v1beta1" 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" + "k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" kubeletphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet" patchnodephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/patchnode" @@ -208,7 +210,12 @@ func runKubeletStartJoinPhase(c workflow.RunData) (returnErr error) { // times out, display a somewhat user-friendly message. waiter := apiclient.NewKubeWaiter(nil, 0, os.Stdout) waiter.SetTimeout(cfg.Timeouts.KubeletHealthCheck.Duration) - if err := waiter.WaitForKubelet(); err != nil { + kubeletConfig := initCfg.ClusterConfiguration.ComponentConfigs[componentconfigs.KubeletGroup].Get() + kubeletConfigTyped, ok := kubeletConfig.(*kubeletconfig.KubeletConfiguration) + if !ok { + return errors.New("could not convert the KubeletConfiguration to a typed object") + } + if err := waiter.WaitForKubelet(kubeletConfigTyped.HealthzBindAddress, *kubeletConfigTyped.HealthzPort); err != nil { fmt.Printf(kubeadmJoinFailMsg, err) return err } diff --git a/cmd/kubeadm/app/componentconfigs/kubelet.go b/cmd/kubeadm/app/componentconfigs/kubelet.go index 57458157931..9472796068f 100644 --- a/cmd/kubeadm/app/componentconfigs/kubelet.go +++ b/cmd/kubeadm/app/componentconfigs/kubelet.go @@ -170,7 +170,7 @@ func (kc *kubeletConfig) Default(cfg *kubeadmapi.ClusterConfiguration, _ *kubead warnDefaultComponentConfigValue(kind, "authentication.webhook.enabled", kubeletAuthenticationWebhookEnabled, *kc.config.Authentication.Webhook.Enabled) } - // Serve a /healthz webserver on localhost:10248 that kubeadm can talk to + // Serve a /healthz webserver on 127.0.0.1:10248 that kubeadm can talk to if kc.config.HealthzBindAddress == "" { kc.config.HealthzBindAddress = kubeletHealthzBindAddress } else if kc.config.HealthzBindAddress != kubeletHealthzBindAddress { diff --git a/cmd/kubeadm/app/phases/upgrade/staticpods_test.go b/cmd/kubeadm/app/phases/upgrade/staticpods_test.go index 0c90b03071f..18402813ac1 100644 --- a/cmd/kubeadm/app/phases/upgrade/staticpods_test.go +++ b/cmd/kubeadm/app/phases/upgrade/staticpods_test.go @@ -137,7 +137,7 @@ func (w *fakeWaiter) WaitForStaticPodHashChange(_, _, _ string) error { } // WaitForHKubelet returns a dummy nil just to implement the interface -func (w *fakeWaiter) WaitForKubelet() error { +func (w *fakeWaiter) WaitForKubelet(_ string, _ int32) error { return nil } diff --git a/cmd/kubeadm/app/util/apiclient/wait.go b/cmd/kubeadm/app/util/apiclient/wait.go index 8515af16462..50191503909 100644 --- a/cmd/kubeadm/app/util/apiclient/wait.go +++ b/cmd/kubeadm/app/util/apiclient/wait.go @@ -58,7 +58,7 @@ type Waiter interface { // WaitForStaticPodControlPlaneHashes fetches sha256 hashes for the control plane static pods WaitForStaticPodControlPlaneHashes(nodeName string) (map[string]string, error) // WaitForKubelet blocks until the kubelet /healthz endpoint returns 'ok' - WaitForKubelet() error + WaitForKubelet(healthzAddress string, healthzPort int32) error // SetTimeout adjusts the timeout to the specified duration SetTimeout(timeout time.Duration) } @@ -243,11 +243,11 @@ func (w *KubeWaiter) WaitForPodToDisappear(podName string) error { } // WaitForKubelet blocks until the kubelet /healthz endpoint returns 'ok'. -func (w *KubeWaiter) WaitForKubelet() error { +func (w *KubeWaiter) WaitForKubelet(healthzAddress string, healthzPort int32) error { var ( lastError error start = time.Now() - healthzEndpoint = fmt.Sprintf("http://localhost:%d/healthz", constants.KubeletHealthzPort) + healthzEndpoint = fmt.Sprintf("http://%s:%d/healthz", healthzAddress, healthzPort) ) fmt.Printf("[kubelet-check] Waiting for a healthy kubelet. This can take up to %v\n", w.timeout) diff --git a/cmd/kubeadm/app/util/dryrun/dryrun.go b/cmd/kubeadm/app/util/dryrun/dryrun.go index ce8d54c8a3d..4dc9e63e8b6 100644 --- a/cmd/kubeadm/app/util/dryrun/dryrun.go +++ b/cmd/kubeadm/app/util/dryrun/dryrun.go @@ -113,8 +113,8 @@ func (w *Waiter) WaitForPodToDisappear(podName string) error { } // WaitForKubelet blocks until the kubelet /healthz endpoint returns 'ok' -func (w *Waiter) WaitForKubelet() error { - fmt.Println("[dryrun] Would make sure the kubelet's /healthz endpoint is healthy") +func (w *Waiter) WaitForKubelet(healthzAddress string, healthzPort int32) error { + fmt.Printf("[dryrun] Would make sure the kubelet returns 'ok' at http://%s:%d/healthz\n", healthzAddress, healthzPort) return nil }