Skip to content

Commit b1e7d35

Browse files
authored
chore: clean up kubelet config file logic (#2613)
The logic to write merged config to a file was only used in versions <=1.28. Those are all EOL now, delete the old logic and update some old integration tests which still used the legacy logic. Delete the withPodInfraContainer function for similar reasons. Inject IMDS client as a dependency so that we can have a unit test for GenerateKubeletConfig.
1 parent dc46be1 commit b1e7d35

File tree

27 files changed

+123
-366
lines changed

27 files changed

+123
-366
lines changed

nodeadm/cmd/nodeadm/init/init.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func (c *initCmd) Run(log *zap.Logger, opts *cli.GlobalOptions) error {
103103
resources := system.NewResources(system.RealFileSystem{})
104104
daemons := []daemon.Daemon{
105105
containerd.NewContainerdDaemon(daemonManager, resources),
106-
kubelet.NewKubeletDaemon(daemonManager, resources),
106+
kubelet.NewKubeletDaemon(daemonManager, resources, imds.DefaultClient()),
107107
}
108108

109109
// to handle edge cases where the cached config is stale (because the user

nodeadm/internal/kubelet/config.go

Lines changed: 14 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,6 @@ const (
3535
kubeletConfigPerm = 0644
3636
)
3737

38-
func (k *kubelet) writeKubeletConfig(cfg *api.NodeConfig) error {
39-
// tracking: https://github.com/kubernetes/enhancements/issues/3983
40-
// for enabling drop-in configuration
41-
if semver.Compare(cfg.Status.KubeletVersion, "v1.29.0") < 0 {
42-
return k.writeKubeletConfigToFile(cfg)
43-
} else {
44-
return k.writeKubeletConfigToDir(cfg)
45-
}
46-
}
47-
4838
// kubeletConfig is an internal-only representation of the kubelet configuration
4939
// that is generated using sane defaults for EKS. It is a subset of the upstream
5040
// KubeletConfiguration types:
@@ -233,8 +223,8 @@ func (ksc *kubeletConfig) withNodeLabels(flags map[string]string, nodeLabelFuncs
233223
}
234224
}
235225

236-
func (ksc *kubeletConfig) withNodeIp(cfg *api.NodeConfig, flags map[string]string) error {
237-
nodeIp, err := getNodeIp(context.TODO(), cfg, imds.DefaultClient())
226+
func (ksc *kubeletConfig) withNodeIp(cfg *api.NodeConfig, flags map[string]string, imdsClient imds.IMDSClient) error {
227+
nodeIp, err := getNodeIp(context.TODO(), cfg, imdsClient)
238228
if err != nil {
239229
return err
240230
}
@@ -280,8 +270,7 @@ func (ksc *kubeletConfig) withCloudProvider(cfg *api.NodeConfig, flags map[strin
280270
flags["hostname-override"] = nodeName
281271
}
282272

283-
// When the DefaultReservedResources flag is enabled, override the kubelet
284-
// config with reserved cgroup values on behalf of the user
273+
// Override the kubelet config with reserved cgroup values on behalf of the user
285274
func (ksc *kubeletConfig) withDefaultReservedResources(cfg *api.NodeConfig, resources system.Resources) {
286275
ksc.SystemReservedCgroup = ptr.String("/system")
287276
ksc.KubeReservedCgroup = ptr.String("/runtime")
@@ -298,29 +287,13 @@ func (ksc *kubeletConfig) withDefaultReservedResources(cfg *api.NodeConfig, reso
298287
}
299288
}
300289

301-
// withPodInfraContainerImage determines whether to add the
302-
// '--pod-infra-container-image' flag, which is used to ensure the sandbox image
303-
// is not garbage collected.
304-
//
305-
// TODO: revisit once the minimum supportted version catches up or the container
306-
// runtime is moved to containerd 2.0
307-
func (ksc *kubeletConfig) withPodInfraContainerImage(cfg *api.NodeConfig, flags map[string]string) error {
308-
// the flag is a noop on 1.29+, since the behavior was changed to use the
309-
// CRI image pinning behavior and no longer considers the flag value.
310-
// see: https://github.com/kubernetes/kubernetes/pull/118544
311-
if semver.Compare(cfg.Status.KubeletVersion, "v1.29.0") < 0 {
312-
flags["pod-infra-container-image"] = cfg.Status.Defaults.SandboxImage
313-
}
314-
return nil
315-
}
316-
317290
func (ksc *kubeletConfig) withImageServiceEndpoint(cfg *api.NodeConfig, resources system.Resources) {
318291
if containerd.UseSOCISnapshotter(cfg, resources) {
319292
ksc.ImageServiceEndpoint = "unix:///run/soci-snapshotter-grpc/soci-snapshotter-grpc.sock"
320293
}
321294
}
322295

323-
func (k *kubelet) GenerateKubeletConfig(cfg *api.NodeConfig) (*kubeletConfig, error) {
296+
func (k *kubelet) generateKubeletConfig(cfg *api.NodeConfig) (*kubeletConfig, error) {
324297
kubeletConfig := defaultKubeletSubConfig()
325298

326299
if err := kubeletConfig.withFallbackClusterDns(&cfg.Spec.Cluster); err != nil {
@@ -329,10 +302,7 @@ func (k *kubelet) GenerateKubeletConfig(cfg *api.NodeConfig) (*kubeletConfig, er
329302
if err := kubeletConfig.withOutpostSetup(cfg); err != nil {
330303
return nil, err
331304
}
332-
if err := kubeletConfig.withNodeIp(cfg, k.flags); err != nil {
333-
return nil, err
334-
}
335-
if err := kubeletConfig.withPodInfraContainerImage(cfg, k.flags); err != nil {
305+
if err := kubeletConfig.withNodeIp(cfg, k.flags, k.imdsClient); err != nil {
336306
return nil, err
337307
}
338308

@@ -351,43 +321,11 @@ func (k *kubelet) GenerateKubeletConfig(cfg *api.NodeConfig) (*kubeletConfig, er
351321
return &kubeletConfig, nil
352322
}
353323

354-
// WriteConfig writes the kubelet config to a file.
355-
// This should only be used for kubelet versions < 1.28.
356-
func (k *kubelet) writeKubeletConfigToFile(cfg *api.NodeConfig) error {
357-
kubeletConfig, err := k.GenerateKubeletConfig(cfg)
358-
if err != nil {
359-
return err
360-
}
361-
362-
var kubeletConfigBytes []byte
363-
if len(cfg.Spec.Kubelet.Config) > 0 {
364-
mergedMap, err := util.Merge(kubeletConfig, cfg.Spec.Kubelet.Config, json.Marshal, json.Unmarshal)
365-
if err != nil {
366-
return err
367-
}
368-
if kubeletConfigBytes, err = json.MarshalIndent(mergedMap, "", strings.Repeat(" ", 4)); err != nil {
369-
return err
370-
}
371-
} else {
372-
var err error
373-
if kubeletConfigBytes, err = json.MarshalIndent(kubeletConfig, "", strings.Repeat(" ", 4)); err != nil {
374-
return err
375-
}
376-
}
377-
378-
configPath := path.Join(kubeletConfigRoot, kubeletConfigFile)
379-
k.flags["config"] = configPath
380-
381-
zap.L().Info("Writing kubelet config to file..", zap.String("path", configPath))
382-
return util.WriteFileWithDir(configPath, kubeletConfigBytes, kubeletConfigPerm)
383-
}
384-
385-
// WriteKubeletConfigToDir writes nodeadm's generated kubelet config to the
324+
// writeKubeletConfig writes nodeadm's generated kubelet config to the
386325
// standard config file and writes the user's provided config to a directory for
387-
// drop-in support. This is only supported on kubelet versions >= 1.28. see:
388-
// https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/#kubelet-conf-d
389-
func (k *kubelet) writeKubeletConfigToDir(cfg *api.NodeConfig) error {
390-
kubeletConfig, err := k.GenerateKubeletConfig(cfg)
326+
// drop-in support.
327+
func (k *kubelet) writeKubeletConfig(cfg *api.NodeConfig) error {
328+
kubeletConfig, err := k.generateKubeletConfig(cfg)
391329
if err != nil {
392330
return err
393331
}
@@ -407,10 +345,10 @@ func (k *kubelet) writeKubeletConfigToDir(cfg *api.NodeConfig) error {
407345
if len(cfg.Spec.Kubelet.Config) > 0 {
408346
dirPath := path.Join(kubeletConfigRoot, kubeletConfigDir)
409347
k.flags["config-dir"] = dirPath
410-
411-
zap.L().Info("Enabling kubelet config drop-in dir..")
412-
k.environment["KUBELET_CONFIG_DROPIN_DIR_ALPHA"] = "on"
413-
filePath := path.Join(dirPath, "40-nodeadm.conf")
348+
if semver.Compare(cfg.Status.KubeletVersion, "v1.30.0") < 0 {
349+
zap.L().Info("Enabling kubelet config drop-in dir..")
350+
k.environment["KUBELET_CONFIG_DROPIN_DIR_ALPHA"] = "on"
351+
}
414352

415353
// merge in default type metadata like kind and apiVersion in case the
416354
// user has not specified this, as it is required to qualify a drop-in
@@ -423,6 +361,7 @@ func (k *kubelet) writeKubeletConfigToDir(cfg *api.NodeConfig) error {
423361
if err != nil {
424362
return err
425363
}
364+
filePath := path.Join(dirPath, "40-nodeadm.conf")
426365
zap.L().Info("Writing user kubelet config to drop-in file..", zap.String("path", filePath))
427366
if err := util.WriteFileWithDir(filePath, userKubeletConfigBytes, kubeletConfigPerm); err != nil {
428367
return err

nodeadm/internal/kubelet/config_test.go

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package kubelet
22

33
import (
4+
"context"
45
"testing"
56

67
"github.com/awslabs/amazon-eks-ami/nodeadm/internal/api"
8+
"github.com/awslabs/amazon-eks-ami/nodeadm/internal/aws/imds"
79
"github.com/awslabs/amazon-eks-ami/nodeadm/internal/containerd"
10+
"github.com/awslabs/amazon-eks-ami/nodeadm/internal/system"
811
"github.com/stretchr/testify/assert"
912
)
1013

@@ -13,7 +16,7 @@ func TestKubeletCredentialProvidersFeatureFlag(t *testing.T) {
1316
kubeletVersion string
1417
expectedValue *bool
1518
}{
16-
{kubeletVersion: "v1.28.0"},
19+
{kubeletVersion: "v1.35.0"},
1720
}
1821

1922
for _, test := range tests {
@@ -103,3 +106,42 @@ func TestMutableCSINodeAllocatableCountFeatureGate(t *testing.T) {
103106
}
104107
}
105108
}
109+
110+
func TestGenerateKubeletConfig(t *testing.T) {
111+
mockIMDS := &imds.FakeIMDSClient{
112+
GetPropertyFunc: func(ctx context.Context, prop imds.IMDSProperty) (string, error) {
113+
if prop == imds.LocalIPv4 {
114+
return "10.0.0.1", nil
115+
}
116+
return "", nil
117+
},
118+
}
119+
k := &kubelet{
120+
imdsClient: mockIMDS,
121+
resources: system.NewResources(system.FakeFileSystem{}),
122+
flags: make(map[string]string),
123+
environment: make(map[string]string),
124+
}
125+
nodeConfig := &api.NodeConfig{
126+
Spec: api.NodeConfigSpec{
127+
Cluster: api.ClusterDetails{
128+
CIDR: "10.100.0.0/16",
129+
},
130+
},
131+
Status: api.NodeConfigStatus{
132+
KubeletVersion: "v1.33.0",
133+
Instance: api.InstanceDetails{
134+
AvailabilityZone: "us-west-2a",
135+
ID: "i-1234567890abcdef0",
136+
PrivateDNSName: "ip-10-0-0-1.us-west-2.compute.internal",
137+
},
138+
},
139+
}
140+
141+
cfg, err := k.generateKubeletConfig(nodeConfig)
142+
assert.NoError(t, err)
143+
144+
assert.Equal(t, "10.0.0.1", k.flags["node-ip"])
145+
assert.Equal(t, "external", k.flags["cloud-provider"])
146+
assert.Equal(t, "aws:///us-west-2a/i-1234567890abcdef0", *cfg.ProviderID)
147+
}

nodeadm/internal/kubelet/daemon.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package kubelet
22

33
import (
44
"github.com/awslabs/amazon-eks-ami/nodeadm/internal/api"
5+
"github.com/awslabs/amazon-eks-ami/nodeadm/internal/aws/imds"
56
"github.com/awslabs/amazon-eks-ami/nodeadm/internal/daemon"
67
"github.com/awslabs/amazon-eks-ami/nodeadm/internal/system"
78
)
@@ -13,16 +14,18 @@ var _ daemon.Daemon = &kubelet{}
1314
type kubelet struct {
1415
daemonManager daemon.DaemonManager
1516
resources system.Resources
17+
imdsClient imds.IMDSClient
1618
// environment variables to write for kubelet
1719
environment map[string]string
1820
// kubelet config flags without leading dashes
1921
flags map[string]string
2022
}
2123

22-
func NewKubeletDaemon(daemonManager daemon.DaemonManager, resources system.Resources) daemon.Daemon {
24+
func NewKubeletDaemon(daemonManager daemon.DaemonManager, resources system.Resources, imdsClient imds.IMDSClient) daemon.Daemon {
2325
return &kubelet{
2426
daemonManager: daemonManager,
2527
resources: resources,
28+
imdsClient: imdsClient,
2629
environment: make(map[string]string),
2730
flags: make(map[string]string),
2831
}

nodeadm/test/e2e/cases/custom-max-pods-expression/run.sh

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,3 @@ for SCENARIO in scenarios/*; do
1818
assert::json-files-equal /etc/kubernetes/kubelet/config.json.d/40-nodeadm.conf "${SCENARIO}/expected-dropin.json"
1919
fi
2020
done
21-
22-
# for <= 1.28, user kubelet config was merged into the same final config as the default (rather than written to)
23-
# a drop-in. confirms that the user maxPods value overrides the result of maxPodsExpression
24-
mock::kubelet 1.28.0
25-
26-
for SCENARIO in scenarios/*; do
27-
nodeadm init --skip run --config-source "file://${SCENARIO}/config.yaml"
28-
29-
assert::json-files-equal /etc/kubernetes/kubelet/config.json "${SCENARIO}/expected-1-28.json"
30-
done

nodeadm/test/e2e/cases/custom-max-pods-expression/scenarios/custom-networking/expected-1-28.json

Lines changed: 0 additions & 66 deletions
This file was deleted.

0 commit comments

Comments
 (0)