kubeadm: fallback to a known etcd version if an unknown k8s version is passed

This commit is contained in:
SataQiu 2020-02-24 10:46:39 +08:00
parent acd97b42f3
commit 2e23f84745
6 changed files with 92 additions and 47 deletions

View File

@ -44,6 +44,5 @@ go_test(
deps = [ deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library", "//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
], ],
) )

View File

@ -27,6 +27,7 @@ import (
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/version" "k8s.io/apimachinery/pkg/util/version"
bootstrapapi "k8s.io/cluster-bootstrap/token/api" bootstrapapi "k8s.io/cluster-bootstrap/token/api"
@ -435,21 +436,45 @@ var (
) )
// EtcdSupportedVersion returns officially supported version of etcd for a specific Kubernetes release // EtcdSupportedVersion returns officially supported version of etcd for a specific Kubernetes release
// if passed version is not listed, the function returns nil and an error // If passed version is not in the given list, the function returns the nearest version with a warning
func EtcdSupportedVersion(versionString string) (*version.Version, error) { func EtcdSupportedVersion(supportedEtcdVersion map[uint8]string, versionString string) (etcdVersion *version.Version, warning, err error) {
kubernetesVersion, err := version.ParseSemantic(versionString) kubernetesVersion, err := version.ParseSemantic(versionString)
if err != nil { if err != nil {
return nil, err return nil, nil, err
}
desiredVersion, etcdStringVersion := uint8(kubernetesVersion.Minor()), ""
min, max := ^uint8(0), uint8(0)
for k, v := range supportedEtcdVersion {
if desiredVersion == k {
etcdStringVersion = v
break
}
if k < min {
min = k
}
if k > max {
max = k
}
} }
if etcdStringVersion, ok := SupportedEtcdVersion[uint8(kubernetesVersion.Minor())]; ok { if len(etcdStringVersion) == 0 {
etcdVersion, err := version.ParseSemantic(etcdStringVersion) if desiredVersion < min {
if err != nil { etcdStringVersion = supportedEtcdVersion[min]
return nil, err
} }
return etcdVersion, nil if desiredVersion > max {
etcdStringVersion = supportedEtcdVersion[max]
}
warning = fmt.Errorf("could not find officially supported version of etcd for Kubernetes %s, falling back to the nearest etcd version (%s)",
versionString, etcdStringVersion)
} }
return nil, errors.Errorf("unsupported or unknown Kubernetes version(%v)", kubernetesVersion)
etcdVersion, err = version.ParseSemantic(etcdStringVersion)
if err != nil {
return nil, nil, err
}
return etcdVersion, warning, nil
} }
// GetStaticPodDirectory returns the location on the disk where the Static Pod should be present // GetStaticPodDirectory returns the location on the disk where the Static Pod should be present

View File

@ -18,11 +18,8 @@ package constants
import ( import (
"path/filepath" "path/filepath"
"strings"
"testing" "testing"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/util/version" "k8s.io/apimachinery/pkg/util/version"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
) )
@ -149,50 +146,62 @@ func TestAddSelfHostedPrefix(t *testing.T) {
} }
func TestEtcdSupportedVersion(t *testing.T) { func TestEtcdSupportedVersion(t *testing.T) {
var supportedEtcdVersion = map[uint8]string{
13: "3.2.24",
14: "3.3.10",
15: "3.3.10",
16: "3.3.17-0",
17: "3.4.3-0",
18: "3.4.3-0",
}
var tests = []struct { var tests = []struct {
kubernetesVersion string kubernetesVersion string
expectedVersion *version.Version expectedVersion *version.Version
expectedError error expectedWarning bool
expectedError bool
}{ }{
{ {
kubernetesVersion: "1.99.0", kubernetesVersion: "1.x.1",
expectedVersion: nil, expectedVersion: nil,
expectedError: errors.New("unsupported or unknown Kubernetes version(1.99.0)"), expectedWarning: false,
expectedError: true,
}, },
{ {
kubernetesVersion: MinimumControlPlaneVersion.WithPatch(1).String(), kubernetesVersion: "1.10.1",
expectedVersion: version.MustParseSemantic(SupportedEtcdVersion[uint8(MinimumControlPlaneVersion.Minor())]), expectedVersion: version.MustParseSemantic("3.2.24"),
expectedError: nil, expectedWarning: true,
expectedError: false,
}, },
{ {
kubernetesVersion: CurrentKubernetesVersion.String(), kubernetesVersion: "1.99.0",
expectedVersion: version.MustParseSemantic(SupportedEtcdVersion[uint8(CurrentKubernetesVersion.Minor())]), expectedVersion: version.MustParseSemantic("3.4.3-0"),
expectedError: nil, expectedWarning: true,
expectedError: false,
},
{
kubernetesVersion: "v1.16.0",
expectedVersion: version.MustParseSemantic("3.3.17-0"),
expectedWarning: false,
expectedError: false,
},
{
kubernetesVersion: "1.17.2",
expectedVersion: version.MustParseSemantic("3.4.3-0"),
expectedWarning: false,
expectedError: false,
}, },
} }
for _, rt := range tests { for _, rt := range tests {
t.Run(rt.kubernetesVersion, func(t *testing.T) { t.Run(rt.kubernetesVersion, func(t *testing.T) {
actualVersion, actualError := EtcdSupportedVersion(rt.kubernetesVersion) actualVersion, actualWarning, actualError := EtcdSupportedVersion(supportedEtcdVersion, rt.kubernetesVersion)
if actualError != nil { if (actualError != nil) != rt.expectedError {
if rt.expectedError == nil { t.Fatalf("expected error %v, got %v", rt.expectedError, actualError != nil)
t.Errorf("failed EtcdSupportedVersion:\n\texpected no error, but got: %v", actualError) }
} else if actualError.Error() != rt.expectedError.Error() { if (actualWarning != nil) != rt.expectedWarning {
t.Errorf( t.Fatalf("expected warning %v, got %v", rt.expectedWarning, actualWarning != nil)
"failed EtcdSupportedVersion:\n\texpected error: %v\n\t actual error: %v", }
rt.expectedError, if actualError == nil && actualVersion.String() != rt.expectedVersion.String() {
actualError, t.Errorf("expected version %s, got %s", rt.expectedVersion.String(), actualVersion.String())
)
}
} else {
if rt.expectedError != nil {
t.Errorf("failed EtcdSupportedVersion:\n\texpected error: %v, but got no error", rt.expectedError)
} else if strings.Compare(actualVersion.String(), rt.expectedVersion.String()) != 0 {
t.Errorf(
"failed EtcdSupportedVersion:\n\texpected version: %s\n\t actual version: %s",
rt.expectedVersion.String(),
actualVersion.String(),
)
}
} }
}) })
} }

View File

@ -73,10 +73,13 @@ func GetEtcdImage(cfg *kubeadmapi.ClusterConfiguration) string {
} }
// Etcd uses an imageTag that corresponds to the etcd version matching the Kubernetes version // Etcd uses an imageTag that corresponds to the etcd version matching the Kubernetes version
etcdImageTag := constants.DefaultEtcdVersion etcdImageTag := constants.DefaultEtcdVersion
etcdVersion, err := constants.EtcdSupportedVersion(cfg.KubernetesVersion) etcdVersion, warning, err := constants.EtcdSupportedVersion(constants.SupportedEtcdVersion, cfg.KubernetesVersion)
if err == nil { if err == nil {
etcdImageTag = etcdVersion.String() etcdImageTag = etcdVersion.String()
} }
if warning != nil {
klog.Warningln(warning)
}
// unless an override is specified // unless an override is specified
if cfg.Etcd.Local != nil && cfg.Etcd.Local.ImageTag != "" { if cfg.Etcd.Local != nil && cfg.Etcd.Local.ImageTag != "" {
etcdImageTag = cfg.Etcd.Local.ImageTag etcdImageTag = cfg.Etcd.Local.ImageTag

View File

@ -22,6 +22,7 @@ import (
versionutil "k8s.io/apimachinery/pkg/util/version" versionutil "k8s.io/apimachinery/pkg/util/version"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
"k8s.io/klog"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" 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/dns"
@ -300,10 +301,13 @@ func minorUpgradePossibleWithPatchRelease(stableVersion, patchVersion *versionut
} }
func getSuggestedEtcdVersion(kubernetesVersion string) string { func getSuggestedEtcdVersion(kubernetesVersion string) string {
etcdVersion, err := kubeadmconstants.EtcdSupportedVersion(kubernetesVersion) etcdVersion, warning, err := kubeadmconstants.EtcdSupportedVersion(kubeadmconstants.SupportedEtcdVersion, kubernetesVersion)
if err != nil { if err != nil {
fmt.Printf("[upgrade/versions] WARNING: No recommended etcd for requested Kubernetes version (%s)\n", kubernetesVersion) klog.Warningf("[upgrade/versions] could not retrieve an etcd version for the target Kubernetes version: %v", err)
return "N/A" return "N/A"
} }
if warning != nil {
klog.Warningf("[upgrade/versions] %v", warning)
}
return etcdVersion.String() return etcdVersion.String()
} }

View File

@ -24,9 +24,11 @@ import (
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
utilerrors "k8s.io/apimachinery/pkg/util/errors" utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/version" "k8s.io/apimachinery/pkg/util/version"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
"k8s.io/klog"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/constants"
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs" certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
@ -281,10 +283,13 @@ func performEtcdStaticPodUpgrade(certsRenewMgr *renewal.Manager, client clientse
} }
// Need to check currently used version and version from constants, if differs then upgrade // Need to check currently used version and version from constants, if differs then upgrade
desiredEtcdVersion, err := constants.EtcdSupportedVersion(cfg.KubernetesVersion) desiredEtcdVersion, warning, err := constants.EtcdSupportedVersion(constants.SupportedEtcdVersion, cfg.KubernetesVersion)
if err != nil { if err != nil {
return true, errors.Wrap(err, "failed to retrieve an etcd version for the target Kubernetes version") return true, errors.Wrap(err, "failed to retrieve an etcd version for the target Kubernetes version")
} }
if warning != nil {
klog.Warningf("[upgrade/etcd] %v", warning)
}
// gets the etcd version of the local/stacked etcd member running on the current machine // gets the etcd version of the local/stacked etcd member running on the current machine
currentEtcdVersions, err := oldEtcdClient.GetClusterVersions() currentEtcdVersions, err := oldEtcdClient.GetClusterVersions()