Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[release/v1.5] Update etcd to 3.5.5 or use the version provided by kubeadm if it's newer #2443

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 43 additions & 13 deletions pkg/templates/kubeadm/v1beta3/kubeadm.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"k8c.io/kubeone/pkg/fail"
"k8c.io/kubeone/pkg/features"
"k8c.io/kubeone/pkg/kubeflags"
"k8c.io/kubeone/pkg/semverutil"
"k8c.io/kubeone/pkg/state"
"k8c.io/kubeone/pkg/templates/kubeadm/kubeadmargs"
"k8c.io/kubeone/pkg/templates/kubernetesconfigs"
Expand All @@ -44,6 +45,25 @@ const (
bootstrapTokenTTL = 60 * time.Minute
)

const (
// fixedEtcdVersion is an etcd version that doesn't have known data integrity and durability bugs
// (see etcdVersionCorruptCheckExtraArgs for more details)
fixedEtcdVersion = "3.5.5-0"

// fixedEtcd123 defines a semver constraint used to check if Kubernetes 1.23 uses fixed etcd version
fixedEtcd123 = ">= 1.23.14, < 1.24"
// fixedEtcd124 defines a semver constraint used to check if Kubernetes 1.24 uses fixed etcd version
fixedEtcd124 = ">= 1.24.8, < 1.25"
// fixedEtcd125 defines a semver constraint used to check if Kubernetes 1.25+ uses fixed etcd version
fixedEtcd125 = ">= 1.25.4"
)

var (
fixedEtcd123Constraint = semverutil.MustParseConstraint(fixedEtcd123)
fixedEtcd124Constraint = semverutil.MustParseConstraint(fixedEtcd124)
fixedEtcd125Constraint = semverutil.MustParseConstraint(fixedEtcd125)
)

// NewConfig returns all required configs to init a cluster via a set of v1beta3 configs
func NewConfig(s *state.State, host kubeoneapi.HostConfig) ([]runtime.Object, error) {
cluster := s.Cluster
Expand All @@ -52,7 +72,7 @@ func NewConfig(s *state.State, host kubeoneapi.HostConfig) ([]runtime.Object, er
return nil, fail.Config(err, "parsing kubernetes semver")
}

etcdImageTag, etcdExtraArgs := etcdVersionCorruptCheckExtraArgs(cluster.AssetConfiguration.Etcd.ImageTag)
etcdImageTag, etcdExtraArgs := etcdVersionCorruptCheckExtraArgs(kubeSemVer, cluster.AssetConfiguration.Etcd.ImageTag)

nodeRegistration := newNodeRegistration(s, host)
nodeRegistration.IgnorePreflightErrors = []string{
Expand Down Expand Up @@ -402,18 +422,28 @@ func newNodeRegistration(s *state.State, host kubeoneapi.HostConfig) kubeadmv1be
}
}

func etcdVersionCorruptCheckExtraArgs(etcdImageTag string) (string, map[string]string) {
etcdExtraArgs := map[string]string{}

// This is required because etcd v3.5-[0-2] (used for Kubernetes 1.22+)
// has an issue with the data integrity.
// See https://groups.google.com/a/kubernetes.io/g/dev/c/B7gJs88XtQc/m/rSgNOzV2BwAJ
// for more details.
if etcdImageTag == "" {
etcdImageTag = "3.5.3-0"
// etcdVersionCorruptCheckExtraArgs provides etcd version and args to be used.
// This is required because:
// - etcd v3.5.[0-2] has an issue with the data integrity
// https://groups.google.com/a/kubernetes.io/g/dev/c/B7gJs88XtQc/m/rSgNOzV2BwAJ
// - etcd v3.5.[0-4] has a durability issue affecting single-node (non-HA) etcd clusters
// https://groups.google.com/a/kubernetes.io/g/dev/c/7q4tB_Vp3Uc/m/MrHalhCIBAAJ
func etcdVersionCorruptCheckExtraArgs(kubeVersion *semver.Version, etcdImageTag string) (string, map[string]string) {
etcdExtraArgs := map[string]string{
"experimental-initial-corrupt-check": "true",
"experimental-corrupt-check-time": "240m",
}
etcdExtraArgs["experimental-initial-corrupt-check"] = "true"
etcdExtraArgs["experimental-corrupt-check-time"] = "240m"

return etcdImageTag, etcdExtraArgs
switch {
case etcdImageTag != "":
return etcdImageTag, etcdExtraArgs
case fixedEtcd123Constraint.Check(kubeVersion):
fallthrough
case fixedEtcd124Constraint.Check(kubeVersion):
fallthrough
case fixedEtcd125Constraint.Check(kubeVersion):
return "", etcdExtraArgs
default:
return fixedEtcdVersion, etcdExtraArgs
}
}
114 changes: 114 additions & 0 deletions pkg/templates/kubeadm/v1beta3/kubeadm_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
Copyright 2022 The KubeOne 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 v1beta3

import (
"reflect"
"testing"

"github.com/Masterminds/semver/v3"
)

func TestEtcdVersionCorruptCheckExtraArgs(t *testing.T) {
etcdExtraArgs := map[string]string{
"experimental-initial-corrupt-check": "true",
"experimental-corrupt-check-time": "240m",
}

tests := []struct {
name string
kubeVersion *semver.Version
etcdImageTag string
expectedEtcdImageTag string
expectedEtcdArgs map[string]string
}{
{
name: "unfixed 1.22",
kubeVersion: semver.MustParse("1.22.10"),
expectedEtcdImageTag: fixedEtcdVersion,
expectedEtcdArgs: etcdExtraArgs,
},
{
name: "unfixed 1.23",
kubeVersion: semver.MustParse("1.23.13"),
expectedEtcdImageTag: fixedEtcdVersion,
expectedEtcdArgs: etcdExtraArgs,
},
{
name: "unfixed 1.24",
kubeVersion: semver.MustParse("1.24.7"),
expectedEtcdImageTag: fixedEtcdVersion,
expectedEtcdArgs: etcdExtraArgs,
},
{
name: "unfixed 1.25",
kubeVersion: semver.MustParse("1.25.3"),
expectedEtcdImageTag: fixedEtcdVersion,
expectedEtcdArgs: etcdExtraArgs,
},
{
name: "fixed 1.23",
kubeVersion: semver.MustParse("1.23.14"),
expectedEtcdImageTag: "",
expectedEtcdArgs: etcdExtraArgs,
},
{
name: "fixed 1.24",
kubeVersion: semver.MustParse("1.24.8"),
expectedEtcdImageTag: "",
expectedEtcdArgs: etcdExtraArgs,
},
{
name: "fixed 1.25",
kubeVersion: semver.MustParse("1.25.4"),
expectedEtcdImageTag: "",
expectedEtcdArgs: etcdExtraArgs,
},
{
name: "fixed 1.26",
kubeVersion: semver.MustParse("1.26.0"),
expectedEtcdImageTag: "",
expectedEtcdArgs: etcdExtraArgs,
},
{
name: "unfixed 1.25, but tag is overwritten",
kubeVersion: semver.MustParse("1.25.3"),
etcdImageTag: "9.9.9-0",
expectedEtcdImageTag: "9.9.9-0",
expectedEtcdArgs: etcdExtraArgs,
},
{
name: "fixed 1.25, but tag is overwritten",
kubeVersion: semver.MustParse("1.25.4"),
etcdImageTag: "9.9.9-0",
expectedEtcdImageTag: "9.9.9-0",
expectedEtcdArgs: etcdExtraArgs,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ver, args := etcdVersionCorruptCheckExtraArgs(tt.kubeVersion, tt.etcdImageTag)
if ver != tt.expectedEtcdImageTag {
t.Errorf("got etcd image tag %q, but expected %q", ver, tt.expectedEtcdImageTag)
}
if !reflect.DeepEqual(args, tt.expectedEtcdArgs) {
t.Errorf("got etcd tags %q, but expected %q", args, tt.expectedEtcdArgs)
}
})
}
}