Skip to content

Commit 6d7649f

Browse files
authored
Merge pull request #4481 from fabriziopandini/fix-CoreDNS-1.20-1.21upgrade
🐛 Fix CoreDNS upgrade from v1.20 to v1.21
2 parents c4082b2 + 92ac8b2 commit 6d7649f

File tree

2 files changed

+161
-17
lines changed

2 files changed

+161
-17
lines changed

controlplane/kubeadm/internal/workload_cluster_coredns.go

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ package internal
1919
import (
2020
"context"
2121
"fmt"
22+
"strings"
23+
24+
"github.com/blang/semver"
2225

2326
"github.com/coredns/corefile-migration/migration"
2427
"github.com/pkg/errors"
@@ -39,6 +42,10 @@ const (
3942
corefileBackupKey = "Corefile-backup"
4043
coreDNSKey = "coredns"
4144
coreDNSVolumeKey = "config-volume"
45+
46+
kubernetesImageRepository = "k8s.gcr.io"
47+
oldCoreDNSImageName = "coredns"
48+
coreDNSImageName = "coredns/coredns"
4249
)
4350

4451
type coreDNSMigrator interface {
@@ -155,12 +162,12 @@ func (w *Workload) getCoreDNSInfo(ctx context.Context, clusterConfig *kubeadmv1.
155162
}
156163

157164
// Handle imageRepository.
158-
toImageRepository := fmt.Sprintf("%s/%s", parsedImage.Repository, parsedImage.Name)
165+
toImageRepository := parsedImage.Repository
159166
if clusterConfig.ImageRepository != "" {
160-
toImageRepository = fmt.Sprintf("%s/%s", clusterConfig.ImageRepository, coreDNSKey)
167+
toImageRepository = strings.TrimSuffix(clusterConfig.ImageRepository, "/")
161168
}
162169
if clusterConfig.DNS.ImageRepository != "" {
163-
toImageRepository = fmt.Sprintf("%s/%s", clusterConfig.DNS.ImageRepository, coreDNSKey)
170+
toImageRepository = strings.TrimSuffix(clusterConfig.DNS.ImageRepository, "/")
164171
}
165172

166173
// Handle imageTag.
@@ -180,15 +187,21 @@ func (w *Workload) getCoreDNSInfo(ctx context.Context, clusterConfig *kubeadmv1.
180187
return nil, err
181188
}
182189

190+
// Handle the renaming of the upstream image from "k8s.gcr.io/coredns" to "k8s.gcr.io/coredns/coredns"
191+
toImageName := parsedImage.Name
192+
if toImageRepository == kubernetesImageRepository && toImageName == oldCoreDNSImageName && targetMajorMinorPatch.GTE(semver.MustParse("1.8.0")) {
193+
toImageName = coreDNSImageName
194+
}
195+
183196
return &coreDNSInfo{
184197
Corefile: corefile,
185198
Deployment: deployment,
186-
CurrentMajorMinorPatch: currentMajorMinorPatch,
187-
TargetMajorMinorPatch: targetMajorMinorPatch,
199+
CurrentMajorMinorPatch: currentMajorMinorPatch.String(),
200+
TargetMajorMinorPatch: targetMajorMinorPatch.String(),
188201
FromImageTag: parsedImage.Tag,
189202
ToImageTag: toImageTag,
190203
FromImage: container.Image,
191-
ToImage: fmt.Sprintf("%s:%s", toImageRepository, toImageTag),
204+
ToImage: fmt.Sprintf("%s/%s:%s", toImageRepository, toImageName, toImageTag),
192205
}, nil
193206
}
194207

@@ -297,12 +310,12 @@ func patchCoreDNSDeploymentImage(deployment *appsv1.Deployment, image string) {
297310
}
298311
}
299312

300-
func extractImageVersion(tag string) (string, error) {
313+
func extractImageVersion(tag string) (semver.Version, error) {
301314
ver, err := util.ParseMajorMinorPatch(tag)
302315
if err != nil {
303-
return "", err
316+
return semver.Version{}, err
304317
}
305-
return fmt.Sprintf("%d.%d.%d", ver.Major, ver.Minor, ver.Patch), nil
318+
return ver, nil
306319
}
307320

308321
// validateCoreDNSImageTag returns error if the versions don't meet requirements.

controlplane/kubeadm/internal/workload_cluster_coredns_test.go

Lines changed: 139 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ func TestUpdateCoreDNS(t *testing.T) {
6565
"BadCoreFileKey": "",
6666
},
6767
}
68-
expectedImage := "k8s.gcr.io/some-folder/coredns:1.6.2"
6968
depl := &appsv1.Deployment{
7069
TypeMeta: v1.TypeMeta{
7170
Kind: "Deployment",
@@ -83,13 +82,19 @@ func TestUpdateCoreDNS(t *testing.T) {
8382
Spec: corev1.PodSpec{
8483
Containers: []corev1.Container{{
8584
Name: coreDNSKey,
86-
Image: expectedImage,
85+
Image: "k8s.gcr.io/some-folder/coredns:1.6.2",
8786
}},
8887
},
8988
},
9089
},
9190
}
9291

92+
deplWithImage := func(image string) *appsv1.Deployment {
93+
d := depl.DeepCopy()
94+
d.Spec.Template.Spec.Containers[0].Image = image
95+
return d
96+
}
97+
9398
expectedCorefile := "coredns-core-file"
9499
cm := &corev1.ConfigMap{
95100
ObjectMeta: v1.ObjectMeta{
@@ -123,6 +128,7 @@ kind: ClusterConfiguration
123128
objs []runtime.Object
124129
expectErr bool
125130
expectUpdates bool
131+
expectImage string
126132
}{
127133
{
128134
name: "returns early without error if skip core dns annotation is present",
@@ -280,6 +286,131 @@ kind: ClusterConfiguration
280286
objs: []runtime.Object{depl, cm, kubeadmCM},
281287
expectErr: false,
282288
expectUpdates: true,
289+
expectImage: "k8s.gcr.io/some-repo/coredns:1.7.2",
290+
},
291+
{
292+
name: "updates everything successfully to v1.8.0 with a custom repo should not change the image name",
293+
kcp: &controlplanev1.KubeadmControlPlane{
294+
Spec: controlplanev1.KubeadmControlPlaneSpec{
295+
KubeadmConfigSpec: cabpkv1.KubeadmConfigSpec{
296+
ClusterConfiguration: &kubeadmv1.ClusterConfiguration{
297+
DNS: kubeadmv1.DNS{
298+
Type: kubeadmv1.CoreDNS,
299+
ImageMeta: kubeadmv1.ImageMeta{
300+
// provide an newer image to update to
301+
ImageRepository: "k8s.gcr.io/some-repo",
302+
ImageTag: "1.8.0",
303+
},
304+
},
305+
},
306+
},
307+
},
308+
},
309+
migrator: &fakeMigrator{
310+
migratedCorefile: "updated-core-file",
311+
},
312+
objs: []runtime.Object{deplWithImage("k8s.gcr.io/some-repo/coredns:1.7.0"), cm, kubeadmCM},
313+
expectErr: false,
314+
expectUpdates: true,
315+
expectImage: "k8s.gcr.io/some-repo/coredns:1.8.0",
316+
},
317+
{
318+
name: "kubeadm defaults, upgrade from Kubernetes v1.18.x to v1.19.y (from k8s.gcr.io/coredns:1.6.7 to k8s.gcr.io/coredns:1.7.0)",
319+
kcp: &controlplanev1.KubeadmControlPlane{
320+
Spec: controlplanev1.KubeadmControlPlaneSpec{
321+
KubeadmConfigSpec: cabpkv1.KubeadmConfigSpec{
322+
ClusterConfiguration: &kubeadmv1.ClusterConfiguration{
323+
DNS: kubeadmv1.DNS{
324+
Type: kubeadmv1.CoreDNS,
325+
ImageMeta: kubeadmv1.ImageMeta{
326+
ImageRepository: "k8s.gcr.io",
327+
ImageTag: "1.7.0",
328+
},
329+
},
330+
},
331+
},
332+
},
333+
},
334+
migrator: &fakeMigrator{
335+
migratedCorefile: "updated-core-file",
336+
},
337+
objs: []runtime.Object{deplWithImage("k8s.gcr.io/coredns:1.6.7"), cm, kubeadmCM},
338+
expectErr: false,
339+
expectUpdates: true,
340+
expectImage: "k8s.gcr.io/coredns:1.7.0",
341+
},
342+
{
343+
name: "kubeadm defaults, upgrade from Kubernetes v1.19.x to v1.20.y (stay on k8s.gcr.io/coredns:1.7.0)",
344+
kcp: &controlplanev1.KubeadmControlPlane{
345+
Spec: controlplanev1.KubeadmControlPlaneSpec{
346+
KubeadmConfigSpec: cabpkv1.KubeadmConfigSpec{
347+
ClusterConfiguration: &kubeadmv1.ClusterConfiguration{
348+
DNS: kubeadmv1.DNS{
349+
Type: kubeadmv1.CoreDNS,
350+
ImageMeta: kubeadmv1.ImageMeta{
351+
ImageRepository: "k8s.gcr.io",
352+
ImageTag: "1.7.0",
353+
},
354+
},
355+
},
356+
},
357+
},
358+
},
359+
migrator: &fakeMigrator{
360+
migratedCorefile: "updated-core-file",
361+
},
362+
objs: []runtime.Object{deplWithImage("k8s.gcr.io/coredns:1.7.0"), cm, kubeadmCM},
363+
expectErr: false,
364+
expectUpdates: false,
365+
},
366+
{
367+
name: "kubeadm defaults, upgrade from Kubernetes v1.20.x to v1.21.y (from k8s.gcr.io/coredns:1.7.0 to k8s.gcr.io/coredns/coredns:v1.8.0)",
368+
kcp: &controlplanev1.KubeadmControlPlane{
369+
Spec: controlplanev1.KubeadmControlPlaneSpec{
370+
KubeadmConfigSpec: cabpkv1.KubeadmConfigSpec{
371+
ClusterConfiguration: &kubeadmv1.ClusterConfiguration{
372+
DNS: kubeadmv1.DNS{
373+
Type: kubeadmv1.CoreDNS,
374+
ImageMeta: kubeadmv1.ImageMeta{
375+
ImageRepository: "k8s.gcr.io",
376+
ImageTag: "v1.8.0", // NOTE: ImageTags requires the v prefix
377+
},
378+
},
379+
},
380+
},
381+
},
382+
},
383+
migrator: &fakeMigrator{
384+
migratedCorefile: "updated-core-file",
385+
},
386+
objs: []runtime.Object{deplWithImage("k8s.gcr.io/coredns:1.7.0"), cm, kubeadmCM},
387+
expectErr: false,
388+
expectUpdates: true,
389+
expectImage: "k8s.gcr.io/coredns/coredns:v1.8.0", // NOTE: ImageName has coredns/coredns
390+
},
391+
{
392+
name: "kubeadm defaults, upgrade from Kubernetes v1.21.x to v1.22.y (stay on k8s.gcr.io/coredns/coredns:v1.8.0)",
393+
kcp: &controlplanev1.KubeadmControlPlane{
394+
Spec: controlplanev1.KubeadmControlPlaneSpec{
395+
KubeadmConfigSpec: cabpkv1.KubeadmConfigSpec{
396+
ClusterConfiguration: &kubeadmv1.ClusterConfiguration{
397+
DNS: kubeadmv1.DNS{
398+
Type: kubeadmv1.CoreDNS,
399+
ImageMeta: kubeadmv1.ImageMeta{
400+
ImageRepository: "k8s.gcr.io",
401+
ImageTag: "v1.8.0", // NOTE: ImageTags requires the v prefix
402+
},
403+
},
404+
},
405+
},
406+
},
407+
},
408+
migrator: &fakeMigrator{
409+
migratedCorefile: "updated-core-file",
410+
},
411+
objs: []runtime.Object{deplWithImage("k8s.gcr.io/coredns/coredns:v1.8.0"), cm, kubeadmCM},
412+
expectErr: false,
413+
expectUpdates: false,
283414
},
284415
}
285416

@@ -303,8 +434,8 @@ kind: ClusterConfiguration
303434
// assert kubeadmConfigMap
304435
var expectedKubeadmConfigMap corev1.ConfigMap
305436
g.Expect(fakeClient.Get(context.TODO(), ctrlclient.ObjectKey{Name: kubeadmConfigKey, Namespace: metav1.NamespaceSystem}, &expectedKubeadmConfigMap)).To(Succeed())
306-
g.Expect(expectedKubeadmConfigMap.Data).To(HaveKeyWithValue("ClusterConfiguration", ContainSubstring("1.7.2")))
307-
g.Expect(expectedKubeadmConfigMap.Data).To(HaveKeyWithValue("ClusterConfiguration", ContainSubstring("k8s.gcr.io/some-repo")))
437+
g.Expect(expectedKubeadmConfigMap.Data).To(HaveKeyWithValue("ClusterConfiguration", ContainSubstring(tt.kcp.Spec.KubeadmConfigSpec.ClusterConfiguration.DNS.ImageTag)))
438+
g.Expect(expectedKubeadmConfigMap.Data).To(HaveKeyWithValue("ClusterConfiguration", ContainSubstring(tt.kcp.Spec.KubeadmConfigSpec.ClusterConfiguration.DNS.ImageRepository)))
308439

309440
// assert CoreDNS corefile
310441
var expectedConfigMap corev1.ConfigMap
@@ -315,10 +446,10 @@ kind: ClusterConfiguration
315446

316447
// assert CoreDNS deployment
317448
var actualDeployment appsv1.Deployment
318-
g.Expect(fakeClient.Get(context.TODO(), ctrlclient.ObjectKey{Name: coreDNSKey, Namespace: metav1.NamespaceSystem}, &actualDeployment)).To(Succeed())
319-
// ensure the image is updated and the volumes point to the corefile
320-
g.Expect(actualDeployment.Spec.Template.Spec.Containers[0].Image).To(Equal("k8s.gcr.io/some-repo/coredns:1.7.2"))
321-
449+
g.Eventually(func() string {
450+
g.Expect(fakeClient.Get(context.TODO(), ctrlclient.ObjectKey{Name: coreDNSKey, Namespace: metav1.NamespaceSystem}, &actualDeployment)).To(Succeed())
451+
return actualDeployment.Spec.Template.Spec.Containers[0].Image
452+
}, "5s").Should(Equal(tt.expectImage))
322453
}
323454
})
324455
}

0 commit comments

Comments
 (0)