From 6c6c7e5f0c62e881714f0fb45fb06d478c8c9298 Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Sat, 11 Dec 2021 01:27:34 +0200 Subject: [PATCH] kubeadm: handle dockershim specific flags for 1.24 Currently when the dockershim socket is used, kubeadm only passes the --network-plugin=cni to the kubelet and assumes the built-in dockershim. This is valid for versions <1.24, but with dockershim and related flags removed the kubelet will fail. Use preflight.GetKubeletVersion() to find the version of the host kubelet and if the version is <1.24 assume that it has built-in dockershim. Newer versions should will be treated as "remote" even if the socket is for dockershim, for example, provided by cri-dockerd. Update related unit tests. --- cmd/kubeadm/app/phases/kubelet/flags.go | 28 +++++++++++++++-- cmd/kubeadm/app/phases/kubelet/flags_test.go | 32 +++++++++++++++++++- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/cmd/kubeadm/app/phases/kubelet/flags.go b/cmd/kubeadm/app/phases/kubelet/flags.go index 5615bfdd8cc..de24a57ad3f 100644 --- a/cmd/kubeadm/app/phases/kubelet/flags.go +++ b/cmd/kubeadm/app/phases/kubelet/flags.go @@ -25,11 +25,15 @@ import ( "github.com/pkg/errors" + versionutil "k8s.io/apimachinery/pkg/util/version" + componentversion "k8s.io/component-base/version" "k8s.io/klog/v2" + utilsexec "k8s.io/utils/exec" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" "k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/images" + preflight "k8s.io/kubernetes/cmd/kubeadm/app/preflight" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" ) @@ -37,6 +41,9 @@ type kubeletFlagsOpts struct { nodeRegOpts *kubeadmapi.NodeRegistrationOptions pauseImage string registerTaintsUsingFlags bool + // This is a temporary measure until kubeadm no longer supports a kubelet version with built-in dockershim. + // TODO: https://github.com/kubernetes/kubeadm/issues/2626 + kubeletVersion *versionutil.Version } // GetNodeNameAndHostname obtains the name for this Node using the following precedence @@ -60,10 +67,24 @@ func GetNodeNameAndHostname(cfg *kubeadmapi.NodeRegistrationOptions) (string, st // WriteKubeletDynamicEnvFile writes an environment file with dynamic flags to the kubelet. // Used at "kubeadm init" and "kubeadm join" time. func WriteKubeletDynamicEnvFile(cfg *kubeadmapi.ClusterConfiguration, nodeReg *kubeadmapi.NodeRegistrationOptions, registerTaintsUsingFlags bool, kubeletDir string) error { + // This is a temporary measure until kubeadm no longer supports a kubelet version with built-in dockershim. + // TODO: https://github.com/kubernetes/kubeadm/issues/2626 + kubeletVersion, err := preflight.GetKubeletVersion(utilsexec.New()) + if err != nil { + // We cannot return an error here, due to the k/k CI, where /cmd/kubeadm/test tests run without + // a kubelet built on the host. On error, we assume a kubelet version equal to the version + // of the kubeadm binary. During normal cluster creation this should not happens as kubeadm needs + // the kubelet binary for init / join. + kubeletVersion = versionutil.MustParseSemantic(componentversion.Get().GitVersion) + klog.Warningf("cannot obtain the version of the kubelet while writing dynamic environment file: %v."+ + " Using the version of the kubeadm binary: %s", err, kubeletVersion.String()) + } + flagOpts := kubeletFlagsOpts{ nodeRegOpts: nodeReg, pauseImage: images.GetPauseImage(cfg), registerTaintsUsingFlags: registerTaintsUsingFlags, + kubeletVersion: kubeletVersion, } stringMap := buildKubeletArgMap(flagOpts) argList := kubeadmutil.BuildArgumentListFromMap(stringMap, nodeReg.KubeletExtraArgs) @@ -77,8 +98,11 @@ func WriteKubeletDynamicEnvFile(cfg *kubeadmapi.ClusterConfiguration, nodeReg *k func buildKubeletArgMapCommon(opts kubeletFlagsOpts) map[string]string { kubeletFlags := map[string]string{} - if opts.nodeRegOpts.CRISocket == constants.DefaultDockerCRISocket { - // These flags should only be set when running docker + // This is a temporary measure until kubeadm no longer supports a kubelet version with built-in dockershim. + // Once that happens only the "remote" branch option should be left. + // TODO: https://github.com/kubernetes/kubeadm/issues/2626 + hasDockershim := opts.kubeletVersion.Major() == 1 && opts.kubeletVersion.Minor() < 24 + if opts.nodeRegOpts.CRISocket == constants.DefaultDockerCRISocket && hasDockershim { kubeletFlags["network-plugin"] = "cni" } else { kubeletFlags["container-runtime"] = "remote" diff --git a/cmd/kubeadm/app/phases/kubelet/flags_test.go b/cmd/kubeadm/app/phases/kubelet/flags_test.go index 06a21b73357..3e810ac0bc4 100644 --- a/cmd/kubeadm/app/phases/kubelet/flags_test.go +++ b/cmd/kubeadm/app/phases/kubelet/flags_test.go @@ -21,12 +21,14 @@ import ( "testing" v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/version" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" ) func TestBuildKubeletArgMap(t *testing.T) { - + // Tests must be updated once kubeadm no longer supports a kubelet version with built-in dockershim. + // TODO: https://github.com/kubernetes/kubeadm/issues/2626 tests := []struct { name string opts kubeletFlagsOpts @@ -127,10 +129,38 @@ func TestBuildKubeletArgMap(t *testing.T) { "pod-infra-container-image": "k8s.gcr.io/pause:3.6", }, }, + { + name: "dockershim socket and kubelet version with built-in dockershim", + opts: kubeletFlagsOpts{ + nodeRegOpts: &kubeadmapi.NodeRegistrationOptions{ + CRISocket: "/var/run/dockershim.sock", + }, + kubeletVersion: version.MustParseSemantic("v1.23.6"), + }, + expected: map[string]string{ + "network-plugin": "cni", + }, + }, + { + name: "dockershim socket but kubelet version is without built-in dockershim", + opts: kubeletFlagsOpts{ + nodeRegOpts: &kubeadmapi.NodeRegistrationOptions{ + CRISocket: "/var/run/dockershim.sock", + }, + kubeletVersion: version.MustParseSemantic("v1.24.0-alpha.1"), + }, + expected: map[string]string{ + "container-runtime": "remote", + "container-runtime-endpoint": "/var/run/dockershim.sock", + }, + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { + if test.opts.kubeletVersion == nil { + test.opts.kubeletVersion = version.MustParseSemantic("v1.0.0") + } actual := buildKubeletArgMap(test.opts) if !reflect.DeepEqual(actual, test.expected) { t.Errorf(