From cef9f9edb6e109de75f5bf5351d7f60a2feef13a Mon Sep 17 00:00:00 2001 From: carlory Date: Thu, 17 Jul 2025 16:58:58 +0800 Subject: [PATCH] kubeadm: fix a bug where it should generate default etcd command based on etcd version when the etcd image tag supports semver --- cmd/kubeadm/app/images/images.go | 8 ++- cmd/kubeadm/app/phases/etcd/local.go | 3 +- cmd/kubeadm/app/phases/etcd/local_test.go | 84 +++++++++++++++++++---- 3 files changed, 81 insertions(+), 14 deletions(-) diff --git a/cmd/kubeadm/app/images/images.go b/cmd/kubeadm/app/images/images.go index 8323cb41601..a9f4700707c 100644 --- a/cmd/kubeadm/app/images/images.go +++ b/cmd/kubeadm/app/images/images.go @@ -70,6 +70,12 @@ func GetEtcdImage(cfg *kubeadmapi.ClusterConfiguration) string { if cfg.Etcd.Local != nil && cfg.Etcd.Local.ImageRepository != "" { etcdImageRepository = cfg.Etcd.Local.ImageRepository } + etcdImageTag := GetEtcdImageTag(cfg) + return GetGenericImage(etcdImageRepository, constants.Etcd, etcdImageTag) +} + +// GetEtcdImageTag generates and returns the image tag for etcd +func GetEtcdImageTag(cfg *kubeadmapi.ClusterConfiguration) string { // Etcd uses an imageTag that corresponds to the etcd version matching the Kubernetes version etcdImageTag := constants.DefaultEtcdVersion etcdVersion, warning, err := constants.EtcdSupportedVersion(constants.SupportedEtcdVersion, cfg.KubernetesVersion) @@ -83,7 +89,7 @@ func GetEtcdImage(cfg *kubeadmapi.ClusterConfiguration) string { if cfg.Etcd.Local != nil && cfg.Etcd.Local.ImageTag != "" { etcdImageTag = cfg.Etcd.Local.ImageTag } - return GetGenericImage(etcdImageRepository, constants.Etcd, etcdImageTag) + return etcdImageTag } // GetControlPlaneImages returns a list of container images kubeadm expects to use on a control plane node diff --git a/cmd/kubeadm/app/phases/etcd/local.go b/cmd/kubeadm/app/phases/etcd/local.go index a3689d74569..b3728128a79 100644 --- a/cmd/kubeadm/app/phases/etcd/local.go +++ b/cmd/kubeadm/app/phases/etcd/local.go @@ -265,7 +265,8 @@ func getEtcdCommand(cfg *kubeadmapi.ClusterConfiguration, endpoint *kubeadmapi.A {Name: "listen-metrics-urls", Value: fmt.Sprintf("http://%s", net.JoinHostPort(etcdLocalhostAddress, strconv.Itoa(kubeadmconstants.EtcdMetricsPort)))}, } - if len(cfg.KubernetesVersion) > 0 && version.MustParseSemantic(cfg.KubernetesVersion).Minor() >= 34 { + etcdImageTag := images.GetEtcdImageTag(cfg) + if etcdVersion, err := version.ParseSemantic(etcdImageTag); err == nil && etcdVersion.AtLeast(version.MustParseSemantic("3.6.0")) { // Arguments used by Etcd 3.6.0+. // TODO: Start always using these once kubeadm only supports etcd >= 3.6.0 for all its supported k8s versions. defaultArguments = append(defaultArguments, []kubeadmapi.Arg{ diff --git a/cmd/kubeadm/app/phases/etcd/local_test.go b/cmd/kubeadm/app/phases/etcd/local_test.go index 8c0cffb0f8d..16cd66ec948 100644 --- a/cmd/kubeadm/app/phases/etcd/local_test.go +++ b/cmd/kubeadm/app/phases/etcd/local_test.go @@ -288,6 +288,7 @@ func TestGetEtcdCommand(t *testing.T) { name string advertiseAddress string k8sVersion string + etcdImageTag string nodeName string extraArgs []kubeadmapi.Arg initialCluster []etcdutil.Member @@ -300,8 +301,8 @@ func TestGetEtcdCommand(t *testing.T) { expected: []string{ "etcd", "--name=foo", - "--experimental-initial-corrupt-check=true", - "--experimental-watch-progress-notify-interval=5s", + "--feature-gates=InitialCorruptCheck=true", + "--watch-progress-notify-interval=5s", fmt.Sprintf("--listen-client-urls=https://127.0.0.1:%d,https://1.2.3.4:%d", kubeadmconstants.EtcdListenClientPort, kubeadmconstants.EtcdListenClientPort), fmt.Sprintf("--listen-metrics-urls=http://127.0.0.1:%d", kubeadmconstants.EtcdMetricsPort), fmt.Sprintf("--advertise-client-urls=https://1.2.3.4:%d", kubeadmconstants.EtcdListenClientPort), @@ -331,8 +332,8 @@ func TestGetEtcdCommand(t *testing.T) { expected: []string{ "etcd", "--name=foo", - "--experimental-initial-corrupt-check=true", - "--experimental-watch-progress-notify-interval=5s", + "--feature-gates=InitialCorruptCheck=true", + "--watch-progress-notify-interval=5s", fmt.Sprintf("--listen-client-urls=https://127.0.0.1:%d,https://1.2.3.4:%d", kubeadmconstants.EtcdListenClientPort, kubeadmconstants.EtcdListenClientPort), fmt.Sprintf("--listen-metrics-urls=http://127.0.0.1:%d", kubeadmconstants.EtcdMetricsPort), fmt.Sprintf("--advertise-client-urls=https://1.2.3.4:%d", kubeadmconstants.EtcdListenClientPort), @@ -363,8 +364,8 @@ func TestGetEtcdCommand(t *testing.T) { expected: []string{ "etcd", "--name=bar", - "--experimental-initial-corrupt-check=true", - "--experimental-watch-progress-notify-interval=5s", + "--feature-gates=InitialCorruptCheck=true", + "--watch-progress-notify-interval=5s", "--listen-client-urls=https://10.0.1.10:2379", fmt.Sprintf("--listen-metrics-urls=http://127.0.0.1:%d", kubeadmconstants.EtcdMetricsPort), "--advertise-client-urls=https://10.0.1.10:2379", @@ -390,8 +391,8 @@ func TestGetEtcdCommand(t *testing.T) { expected: []string{ "etcd", "--name=foo", - "--experimental-initial-corrupt-check=true", - "--experimental-watch-progress-notify-interval=5s", + "--feature-gates=InitialCorruptCheck=true", + "--watch-progress-notify-interval=5s", fmt.Sprintf("--listen-client-urls=https://[::1]:%d,https://[2001:db8::3]:%d", kubeadmconstants.EtcdListenClientPort, kubeadmconstants.EtcdListenClientPort), fmt.Sprintf("--listen-metrics-urls=http://[::1]:%d", kubeadmconstants.EtcdMetricsPort), fmt.Sprintf("--advertise-client-urls=https://[2001:db8::3]:%d", kubeadmconstants.EtcdListenClientPort), @@ -411,15 +412,71 @@ func TestGetEtcdCommand(t *testing.T) { }, }, { - name: "New etcd (3.6.0+) flags", + name: "Default args - with k8s 1.33.0", advertiseAddress: "1.2.3.4", - k8sVersion: "1.34.0", + k8sVersion: "1.33.0", nodeName: "bar", expected: []string{ "etcd", "--name=bar", - "--feature-gates=InitialCorruptCheck=true", - "--watch-progress-notify-interval=5s", + "--experimental-initial-corrupt-check=true", + "--experimental-watch-progress-notify-interval=5s", + fmt.Sprintf("--listen-client-urls=https://127.0.0.1:%d,https://1.2.3.4:%d", kubeadmconstants.EtcdListenClientPort, kubeadmconstants.EtcdListenClientPort), + fmt.Sprintf("--listen-metrics-urls=http://127.0.0.1:%d", kubeadmconstants.EtcdMetricsPort), + fmt.Sprintf("--advertise-client-urls=https://1.2.3.4:%d", kubeadmconstants.EtcdListenClientPort), + fmt.Sprintf("--listen-peer-urls=https://1.2.3.4:%d", kubeadmconstants.EtcdListenPeerPort), + fmt.Sprintf("--initial-advertise-peer-urls=https://1.2.3.4:%d", kubeadmconstants.EtcdListenPeerPort), + "--data-dir=/var/lib/etcd", + "--cert-file=" + filepath.FromSlash(kubeadmconstants.EtcdServerCertName), + "--key-file=" + filepath.FromSlash(kubeadmconstants.EtcdServerKeyName), + "--trusted-ca-file=" + filepath.FromSlash(kubeadmconstants.EtcdCACertName), + "--client-cert-auth=true", + "--peer-cert-file=" + filepath.FromSlash(kubeadmconstants.EtcdPeerCertName), + "--peer-key-file=" + filepath.FromSlash(kubeadmconstants.EtcdPeerKeyName), + "--peer-trusted-ca-file=" + filepath.FromSlash(kubeadmconstants.EtcdCACertName), + "--snapshot-count=10000", + "--peer-client-cert-auth=true", + fmt.Sprintf("--initial-cluster=bar=https://1.2.3.4:%d", kubeadmconstants.EtcdListenPeerPort), + }, + }, + { + name: "Default args - with semver etcd image (3.5.21-0)", + advertiseAddress: "1.2.3.4", + etcdImageTag: "3.5.21-0", + nodeName: "bar", + expected: []string{ + "etcd", + "--name=bar", + "--experimental-initial-corrupt-check=true", + "--experimental-watch-progress-notify-interval=5s", + fmt.Sprintf("--listen-client-urls=https://127.0.0.1:%d,https://1.2.3.4:%d", kubeadmconstants.EtcdListenClientPort, kubeadmconstants.EtcdListenClientPort), + fmt.Sprintf("--listen-metrics-urls=http://127.0.0.1:%d", kubeadmconstants.EtcdMetricsPort), + fmt.Sprintf("--advertise-client-urls=https://1.2.3.4:%d", kubeadmconstants.EtcdListenClientPort), + fmt.Sprintf("--listen-peer-urls=https://1.2.3.4:%d", kubeadmconstants.EtcdListenPeerPort), + fmt.Sprintf("--initial-advertise-peer-urls=https://1.2.3.4:%d", kubeadmconstants.EtcdListenPeerPort), + "--data-dir=/var/lib/etcd", + "--cert-file=" + filepath.FromSlash(kubeadmconstants.EtcdServerCertName), + "--key-file=" + filepath.FromSlash(kubeadmconstants.EtcdServerKeyName), + "--trusted-ca-file=" + filepath.FromSlash(kubeadmconstants.EtcdCACertName), + "--client-cert-auth=true", + "--peer-cert-file=" + filepath.FromSlash(kubeadmconstants.EtcdPeerCertName), + "--peer-key-file=" + filepath.FromSlash(kubeadmconstants.EtcdPeerKeyName), + "--peer-trusted-ca-file=" + filepath.FromSlash(kubeadmconstants.EtcdCACertName), + "--snapshot-count=10000", + "--peer-client-cert-auth=true", + fmt.Sprintf("--initial-cluster=bar=https://1.2.3.4:%d", kubeadmconstants.EtcdListenPeerPort), + }, + }, + { + name: "Default args - with non-semver etcd image", + advertiseAddress: "1.2.3.4", + etcdImageTag: "non-semver", + nodeName: "bar", + expected: []string{ + "etcd", + "--name=bar", + "--experimental-initial-corrupt-check=true", + "--experimental-watch-progress-notify-interval=5s", fmt.Sprintf("--listen-client-urls=https://127.0.0.1:%d,https://1.2.3.4:%d", kubeadmconstants.EtcdListenClientPort, kubeadmconstants.EtcdListenClientPort), fmt.Sprintf("--listen-metrics-urls=http://127.0.0.1:%d", kubeadmconstants.EtcdMetricsPort), fmt.Sprintf("--advertise-client-urls=https://1.2.3.4:%d", kubeadmconstants.EtcdListenClientPort), @@ -449,6 +506,9 @@ func TestGetEtcdCommand(t *testing.T) { KubernetesVersion: rt.k8sVersion, Etcd: kubeadmapi.Etcd{ Local: &kubeadmapi.LocalEtcd{ + ImageMeta: kubeadmapi.ImageMeta{ + ImageTag: rt.etcdImageTag, + }, DataDir: "/var/lib/etcd", ExtraArgs: rt.extraArgs, },