Skip to content

Commit 6073e52

Browse files
authored
Merge pull request #8880 from fabriziopandini/add-kind-mapper
🐛 Add kind mapper
2 parents 00469fa + 7a4e06c commit 6073e52

File tree

10 files changed

+513
-94
lines changed

10 files changed

+513
-94
lines changed

test/e2e/data/infrastructure-docker/main/clusterclass-quick-start.yaml

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -220,34 +220,6 @@ spec:
220220
valueFrom:
221221
template: |
222222
kindest/node:{{ .builtin.controlPlane.version | replace "+" "_" }}
223-
- name: replaceImage-v1.23.17-machineDeployment
224-
description: "Sets the container image for MD DockerMachineTemplates using Kubernetes v1.23.17."
225-
enabledIf: '{{ semverCompare "v1.23.17" .builtin.machineDeployment.version }}'
226-
definitions:
227-
- selector:
228-
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
229-
kind: DockerMachineTemplate
230-
matchResources:
231-
machineDeploymentClass:
232-
names:
233-
- default-worker
234-
jsonPatches:
235-
- op: add
236-
path: "/spec/template/spec/customImage"
237-
value: "kindest/node:v1.23.17@sha256:f77f8cf0b30430ca4128cc7cfafece0c274a118cd0cdb251049664ace0dee4ff"
238-
- name: replaceImage-v1.23.17-controlPlane
239-
description: "Sets the container image for CP DockerMachineTemplates using Kubernetes v1.23.17."
240-
enabledIf: '{{ semverCompare "v1.23.17" .builtin.controlPlane.version }}'
241-
definitions:
242-
- selector:
243-
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
244-
kind: DockerMachineTemplate
245-
matchResources:
246-
controlPlane: true
247-
jsonPatches:
248-
- op: add
249-
path: "/spec/template/spec/customImage"
250-
value: "kindest/node:v1.23.17@sha256:f77f8cf0b30430ca4128cc7cfafece0c274a118cd0cdb251049664ace0dee4ff"
251223
- name: preloadImages
252224
description: |
253225
Sets the container images to preload to the node that is used for running dockerMachines.
@@ -535,4 +507,3 @@ spec:
535507
kubeletExtraArgs:
536508
eviction-hard: 'nodefs.available<0%,nodefs.inodesFree<0%,imagefs.available<0%'
537509
fail-swap-on: "false"
538-

test/extension/handlers/topologymutation/handler.go

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ package topologymutation
2424
import (
2525
"context"
2626
"fmt"
27-
"strings"
2827

2928
"github.com/blang/semver"
3029
"github.com/pkg/errors"
@@ -40,6 +39,7 @@ import (
4039
runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
4140
"sigs.k8s.io/cluster-api/exp/runtime/topologymutation"
4241
infrav1 "sigs.k8s.io/cluster-api/test/infrastructure/docker/api/v1beta1"
42+
"sigs.k8s.io/cluster-api/test/infrastructure/kind"
4343
"sigs.k8s.io/cluster-api/util/version"
4444
)
4545

@@ -257,7 +257,9 @@ func patchKubeadmConfigTemplate(ctx context.Context, k *bootstrapv1.KubeadmConfi
257257

258258
// patchDockerMachineTemplate patches the DockerMachineTemplate.
259259
// It sets the CustomImage to an image for the version in use by the controlPlane or by the MachineDeployment
260-
// the DockerMachineTemplate belongs to. This patch is required to pick up the kind image with the required Kubernetes version.
260+
// the DockerMachineTemplate belongs to.
261+
// NOTE: this patch is not required anymore after the introduction of the kind mapper in kind, however we keep it
262+
// as example of version aware patches.
261263
func patchDockerMachineTemplate(ctx context.Context, dockerMachineTemplate *infrav1.DockerMachineTemplate, templateVariables map[string]apiextensionsv1.JSON) error {
262264
log := ctrl.LoggerFrom(ctx)
263265

@@ -270,13 +272,14 @@ func patchDockerMachineTemplate(ctx context.Context, dockerMachineTemplate *infr
270272
return errors.Wrap(err, "could not set customImage to control plane dockerMachineTemplate")
271273
}
272274
if found {
273-
_, err := version.ParseMajorMinorPatchTolerant(cpVersion)
275+
semVer, err := version.ParseMajorMinorPatchTolerant(cpVersion)
274276
if err != nil {
275277
return errors.Wrap(err, "could not parse control plane version")
276278
}
277-
customImage := fmt.Sprintf("kindest/node:%s", strings.ReplaceAll(cpVersion, "+", "_"))
278-
log.Info(fmt.Sprintf("Setting MachineDeployment custom image to %q", customImage))
279-
dockerMachineTemplate.Spec.Template.Spec.CustomImage = customImage
279+
kindMapping := kind.GetMapping(semVer, "")
280+
281+
log.Info(fmt.Sprintf("Setting MachineDeployment custom image to %q", kindMapping.Image))
282+
dockerMachineTemplate.Spec.Template.Spec.CustomImage = kindMapping.Image
280283
// return early if we have successfully patched a control plane dockerMachineTemplate
281284
return nil
282285
}
@@ -290,13 +293,14 @@ func patchDockerMachineTemplate(ctx context.Context, dockerMachineTemplate *infr
290293
return errors.Wrap(err, "could not set customImage to MachineDeployment DockerMachineTemplate")
291294
}
292295
if found {
293-
_, err := version.ParseMajorMinorPatchTolerant(mdVersion)
296+
semVer, err := version.ParseMajorMinorPatchTolerant(mdVersion)
294297
if err != nil {
295298
return errors.Wrap(err, "could not parse MachineDeployment version")
296299
}
297-
customImage := fmt.Sprintf("kindest/node:%s", strings.ReplaceAll(mdVersion, "+", "_"))
298-
log.Info(fmt.Sprintf("Setting MachineDeployment customImage to %q", customImage))
299-
dockerMachineTemplate.Spec.Template.Spec.CustomImage = customImage
300+
kindMapping := kind.GetMapping(semVer, "")
301+
302+
log.Info(fmt.Sprintf("Setting MachineDeployment customImage to %q", kindMapping.Image))
303+
dockerMachineTemplate.Spec.Template.Spec.CustomImage = kindMapping.Image
300304
return nil
301305
}
302306

test/infrastructure/container/docker.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import (
4040
"k8s.io/utils/pointer"
4141

4242
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
43+
"sigs.k8s.io/cluster-api/test/infrastructure/kind"
4344
)
4445

4546
const (
@@ -390,6 +391,8 @@ func (d *dockerRuntime) RunContainer(ctx context.Context, runConfig *RunContaine
390391
restartMaximumRetryCount = 1
391392
}
392393

394+
// TODO: check if we can simplify the following code for the CAPD load balancer, which now always has runConfig.KindMode == kind.ModeNone
395+
393396
hostConfig := dockercontainer.HostConfig{
394397
// Running containers in a container requires privileges.
395398
// NOTE: we could try to replicate this with --cap-add, and use less
@@ -406,6 +409,11 @@ func (d *dockerRuntime) RunContainer(ctx context.Context, runConfig *RunContaine
406409
}
407410
networkConfig := network.NetworkingConfig{}
408411

412+
// NOTE: starting from Kind 0.20 kind requires CgroupnsMode to be set to private.
413+
if runConfig.KindMode != kind.ModeNone && runConfig.KindMode != kind.Mode0_19 {
414+
hostConfig.CgroupnsMode = "private"
415+
}
416+
409417
if runConfig.IPFamily == clusterv1.IPv6IPFamily || runConfig.IPFamily == clusterv1.DualStackIPFamily {
410418
hostConfig.Sysctls = map[string]string{
411419
"net.ipv6.conf.all.disable_ipv6": "0",

test/infrastructure/container/interface.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"io"
2323

2424
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
25+
"sigs.k8s.io/cluster-api/test/infrastructure/kind"
2526
)
2627

2728
// providerKey is the key type for accessing the runtime provider in passed contexts.
@@ -98,6 +99,8 @@ type RunContainerInput struct {
9899
// RestartPolicy to use for the container.
99100
// If not set, defaults to "unless-stopped".
100101
RestartPolicy string
102+
// Defines how the kindest/node image must be started.
103+
KindMode kind.Mode
101104
}
102105

103106
// ExecContainerInput contains values for running exec on a container.

test/infrastructure/docker/exp/internal/docker/nodepool.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"strings"
2626
"time"
2727

28+
"github.com/blang/semver"
2829
"github.com/pkg/errors"
2930
corev1 "k8s.io/api/core/v1"
3031
"k8s.io/klog/v2"
@@ -37,8 +38,8 @@ import (
3738
expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
3839
infraexpv1 "sigs.k8s.io/cluster-api/test/infrastructure/docker/exp/api/v1beta1"
3940
"sigs.k8s.io/cluster-api/test/infrastructure/docker/internal/docker"
41+
"sigs.k8s.io/cluster-api/test/infrastructure/kind"
4042
"sigs.k8s.io/cluster-api/util"
41-
"sigs.k8s.io/cluster-api/util/container"
4243
)
4344

4445
const (
@@ -168,15 +169,18 @@ func (np *NodePool) Delete(ctx context.Context) error {
168169
}
169170

170171
func (np *NodePool) isMachineMatchingInfrastructureSpec(machine *docker.Machine) bool {
171-
return imageVersion(machine) == container.SemverToOCIImageTag(*np.machinePool.Spec.Template.Spec.Version)
172-
}
172+
// NOTE: With the current implementation we are checking if the machine is using a kindest/node image for the expected version,
173+
// but not checking if the machine has the expected extra.mounts or pre.loaded images.
174+
175+
semVer, err := semver.Parse(strings.TrimPrefix(*np.machinePool.Spec.Template.Spec.Version, "v"))
176+
if err != nil {
177+
// TODO: consider if to return an error
178+
panic(errors.Wrap(err, "failed to parse DockerMachine version").Error())
179+
}
180+
181+
kindMapping := kind.GetMapping(semVer, np.dockerMachinePool.Spec.Template.CustomImage)
173182

174-
// ImageVersion returns the version of the image used or nil if not specified
175-
// NOTE: Image version might be different from the Kubernetes version, because some characters
176-
// allowed by semver (e.g. +) can't be used for image tags, so they are replaced with "_".
177-
func imageVersion(m *docker.Machine) string {
178-
containerImage := m.ContainerImage()
179-
return containerImage[strings.LastIndex(containerImage, ":")+1:]
183+
return machine.ContainerImage() == kindMapping.Image
180184
}
181185

182186
// machinesMatchingInfrastructureSpec returns all of the docker.Machines which match the machine pool / docker machine pool spec.

test/infrastructure/docker/internal/docker/machine.go

Lines changed: 20 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"strings"
2727
"time"
2828

29+
"github.com/blang/semver"
2930
"github.com/go-logr/logr"
3031
"github.com/pkg/errors"
3132
corev1 "k8s.io/api/core/v1"
@@ -45,22 +46,17 @@ import (
4546
"sigs.k8s.io/cluster-api/test/infrastructure/docker/internal/provisioning"
4647
"sigs.k8s.io/cluster-api/test/infrastructure/docker/internal/provisioning/cloudinit"
4748
"sigs.k8s.io/cluster-api/test/infrastructure/docker/internal/provisioning/ignition"
48-
clusterapicontainer "sigs.k8s.io/cluster-api/util/container"
49+
"sigs.k8s.io/cluster-api/test/infrastructure/kind"
4950
"sigs.k8s.io/cluster-api/util/patch"
5051
)
5152

52-
const (
53-
defaultImageName = "kindest/node"
54-
defaultImageTag = "v1.27.1"
55-
)
56-
5753
var (
5854
cloudProviderTaint = corev1.Taint{Key: "node.cloudprovider.kubernetes.io/uninitialized", Effect: corev1.TaintEffectNoSchedule}
5955
)
6056

6157
type nodeCreator interface {
62-
CreateControlPlaneNode(ctx context.Context, name, image, clusterName, listenAddress string, port int32, mounts []v1alpha4.Mount, portMappings []v1alpha4.PortMapping, labels map[string]string, ipFamily clusterv1.ClusterIPFamily) (node *types.Node, err error)
63-
CreateWorkerNode(ctx context.Context, name, image, clusterName string, mounts []v1alpha4.Mount, portMappings []v1alpha4.PortMapping, labels map[string]string, ipFamily clusterv1.ClusterIPFamily) (node *types.Node, err error)
58+
CreateControlPlaneNode(ctx context.Context, name, clusterName, listenAddress string, port int32, mounts []v1alpha4.Mount, portMappings []v1alpha4.PortMapping, labels map[string]string, ipFamily clusterv1.ClusterIPFamily, kindMapping kind.Mapping) (node *types.Node, err error)
59+
CreateWorkerNode(ctx context.Context, name, clusterName string, mounts []v1alpha4.Mount, portMappings []v1alpha4.PortMapping, labels map[string]string, ipFamily clusterv1.ClusterIPFamily, kindMapping kind.Mapping) (node *types.Node, err error)
6460
}
6561

6662
// Machine implement a service for managing the docker containers hosting a kubernetes nodes.
@@ -212,40 +208,49 @@ func (m *Machine) Create(ctx context.Context, image string, role string, version
212208
if m.container == nil {
213209
var err error
214210

215-
machineImage := m.machineImage(version)
216-
if image != "" {
217-
machineImage = image
211+
// Get the KindMapping for the target K8s version.
212+
// NOTE: The KindMapping allows to select the most recent kindest/node image available, if any, as well as
213+
// provide info about the mode to be used when starting the kindest/node image itself.
214+
if version == nil {
215+
return errors.New("cannot create a DockerMachine for a nil version")
218216
}
219217

218+
semVer, err := semver.Parse(strings.TrimPrefix(*version, "v"))
219+
if err != nil {
220+
return errors.Wrap(err, "failed to parse DockerMachine version")
221+
}
222+
223+
kindMapping := kind.GetMapping(semVer, image)
224+
220225
switch role {
221226
case constants.ControlPlaneNodeRoleValue:
222-
log.Info(fmt.Sprintf("Creating control plane machine container with image %s", machineImage))
227+
log.Info(fmt.Sprintf("Creating control plane machine container with image %s, mode %s", kindMapping.Image, kindMapping.Mode))
223228
m.container, err = m.nodeCreator.CreateControlPlaneNode(
224229
ctx,
225230
m.ContainerName(),
226-
machineImage,
227231
m.cluster,
228232
"127.0.0.1",
229233
0,
230234
kindMounts(mounts),
231235
nil,
232236
labels,
233237
m.ipFamily,
238+
kindMapping,
234239
)
235240
if err != nil {
236241
return errors.WithStack(err)
237242
}
238243
case constants.WorkerNodeRoleValue:
239-
log.Info(fmt.Sprintf("Creating worker machine container with image %s", machineImage))
244+
log.Info(fmt.Sprintf("Creating worker machine container with image %s, mode %s", kindMapping.Image, kindMapping.Mode))
240245
m.container, err = m.nodeCreator.CreateWorkerNode(
241246
ctx,
242247
m.ContainerName(),
243-
machineImage,
244248
m.cluster,
245249
kindMounts(mounts),
246250
nil,
247251
labels,
248252
m.ipFamily,
253+
kindMapping,
249254
)
250255
if err != nil {
251256
return errors.WithStack(err)
@@ -527,26 +532,6 @@ func (m *Machine) Delete(ctx context.Context) error {
527532
return nil
528533
}
529534

530-
// machineImage is the image of the container node with the machine.
531-
func (m *Machine) machineImage(version *string) string {
532-
if version == nil {
533-
defaultImage := fmt.Sprintf("%s:%s", defaultImageName, defaultImageTag)
534-
return defaultImage
535-
}
536-
537-
// TODO(fp) make this smarter
538-
// - allows usage of custom docker repository & image names
539-
// - add v only for semantic versions
540-
versionString := *version
541-
if !strings.HasPrefix(versionString, "v") {
542-
versionString = fmt.Sprintf("v%s", versionString)
543-
}
544-
545-
versionString = clusterapicontainer.SemverToOCIImageTag(versionString)
546-
547-
return fmt.Sprintf("%s:%s", defaultImageName, versionString)
548-
}
549-
550535
func logContainerDebugInfo(ctx context.Context, log logr.Logger, name string) {
551536
containerRuntime, err := container.RuntimeFrom(ctx)
552537
if err != nil {

0 commit comments

Comments
 (0)