Skip to content

Commit 6e7486f

Browse files
committed
fix: allow graceful node shutdown to be overridden
The problem is that these values needs to be set to zero if the kubelet feature gate is disabled, so we can't assume that we can override zero value with the proper config, so we have to do an extra check on the supplied configuration. Also creates KB article on disabling this feature gate. Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
1 parent 867d38f commit 6e7486f

File tree

3 files changed

+105
-54
lines changed

3 files changed

+105
-54
lines changed

internal/app/machined/pkg/controllers/k8s/kubelet_spec.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,11 +294,11 @@ func NewKubeletConfiguration(clusterDNS []string, dnsDomain string, extraConfig
294294
config.Logging.Format = "json"
295295
}
296296

297-
if config.ShutdownGracePeriod.Duration == 0 {
297+
if _, overridden := extraConfig["shutdownGracePeriod"]; !overridden && config.ShutdownGracePeriod.Duration == 0 {
298298
config.ShutdownGracePeriod = metav1.Duration{Duration: constants.KubeletShutdownGracePeriod}
299299
}
300300

301-
if config.ShutdownGracePeriodCriticalPods.Duration == 0 {
301+
if _, overridden := extraConfig["shutdownGracePeriodCriticalPods"]; !overridden && config.ShutdownGracePeriodCriticalPods.Duration == 0 {
302302
config.ShutdownGracePeriodCriticalPods = metav1.Duration{Duration: constants.KubeletShutdownGracePeriodCriticalPods}
303303
}
304304

internal/app/machined/pkg/controllers/k8s/kubelet_spec_test.go

Lines changed: 82 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -322,63 +322,93 @@ func TestNewKubeletConfigurationFail(t *testing.T) {
322322
}
323323
}
324324

325-
func TestNewKubeletConfigurationSuccess(t *testing.T) {
326-
config, err := k8sctrl.NewKubeletConfiguration(
327-
[]string{"10.0.0.5"}, "cluster.local", map[string]interface{}{
328-
"oomScoreAdj": -300,
329-
"enableDebuggingHandlers": true,
325+
func TestNewKubeletConfigurationMerge(t *testing.T) {
326+
defaultKubeletConfig := kubeletconfig.KubeletConfiguration{
327+
TypeMeta: metav1.TypeMeta{
328+
APIVersion: kubeletconfig.SchemeGroupVersion.String(),
329+
Kind: "KubeletConfiguration",
330330
},
331-
)
332-
require.NoError(t, err)
333-
334-
assert.Equal(
335-
t, &kubeletconfig.KubeletConfiguration{
336-
TypeMeta: metav1.TypeMeta{
337-
APIVersion: kubeletconfig.SchemeGroupVersion.String(),
338-
Kind: "KubeletConfiguration",
331+
StaticPodPath: constants.ManifestsDirectory,
332+
Port: constants.KubeletPort,
333+
Authentication: kubeletconfig.KubeletAuthentication{
334+
X509: kubeletconfig.KubeletX509Authentication{
335+
ClientCAFile: constants.KubernetesCACert,
339336
},
340-
StaticPodPath: constants.ManifestsDirectory,
341-
Port: constants.KubeletPort,
342-
Authentication: kubeletconfig.KubeletAuthentication{
343-
X509: kubeletconfig.KubeletX509Authentication{
344-
ClientCAFile: constants.KubernetesCACert,
345-
},
346-
Webhook: kubeletconfig.KubeletWebhookAuthentication{
347-
Enabled: pointer.ToBool(true),
348-
},
349-
Anonymous: kubeletconfig.KubeletAnonymousAuthentication{
350-
Enabled: pointer.ToBool(false),
351-
},
337+
Webhook: kubeletconfig.KubeletWebhookAuthentication{
338+
Enabled: pointer.ToBool(true),
352339
},
353-
Authorization: kubeletconfig.KubeletAuthorization{
354-
Mode: kubeletconfig.KubeletAuthorizationModeWebhook,
340+
Anonymous: kubeletconfig.KubeletAnonymousAuthentication{
341+
Enabled: pointer.ToBool(false),
355342
},
356-
CgroupRoot: "/",
357-
SystemCgroups: constants.CgroupSystem,
358-
KubeletCgroups: constants.CgroupKubelet,
359-
RotateCertificates: true,
360-
ProtectKernelDefaults: true,
361-
Address: "0.0.0.0",
362-
OOMScoreAdj: pointer.ToInt32(-300),
363-
ClusterDomain: "cluster.local",
364-
ClusterDNS: []string{"10.0.0.5"},
365-
SerializeImagePulls: pointer.ToBool(false),
366-
FailSwapOn: pointer.ToBool(false),
367-
SystemReserved: map[string]string{
368-
"cpu": constants.KubeletSystemReservedCPU,
369-
"memory": constants.KubeletSystemReservedMemory,
370-
"pid": constants.KubeletSystemReservedPid,
371-
"ephemeral-storage": constants.KubeletSystemReservedEphemeralStorage,
343+
},
344+
Authorization: kubeletconfig.KubeletAuthorization{
345+
Mode: kubeletconfig.KubeletAuthorizationModeWebhook,
346+
},
347+
CgroupRoot: "/",
348+
SystemCgroups: constants.CgroupSystem,
349+
KubeletCgroups: constants.CgroupKubelet,
350+
RotateCertificates: true,
351+
ProtectKernelDefaults: true,
352+
Address: "0.0.0.0",
353+
OOMScoreAdj: pointer.ToInt32(constants.KubeletOOMScoreAdj),
354+
ClusterDomain: "cluster.local",
355+
ClusterDNS: []string{"10.0.0.5"},
356+
SerializeImagePulls: pointer.ToBool(false),
357+
FailSwapOn: pointer.ToBool(false),
358+
SystemReserved: map[string]string{
359+
"cpu": constants.KubeletSystemReservedCPU,
360+
"memory": constants.KubeletSystemReservedMemory,
361+
"pid": constants.KubeletSystemReservedPid,
362+
"ephemeral-storage": constants.KubeletSystemReservedEphemeralStorage,
363+
},
364+
Logging: v1alpha1.LoggingConfiguration{
365+
Format: "json",
366+
},
367+
ShutdownGracePeriod: metav1.Duration{Duration: constants.KubeletShutdownGracePeriod},
368+
ShutdownGracePeriodCriticalPods: metav1.Duration{Duration: constants.KubeletShutdownGracePeriodCriticalPods},
369+
StreamingConnectionIdleTimeout: metav1.Duration{Duration: 5 * time.Minute},
370+
TLSMinVersion: "VersionTLS13",
371+
}
372+
373+
for _, tt := range []struct {
374+
name string
375+
extraConfig map[string]interface{}
376+
expectedOverrides func(*kubeletconfig.KubeletConfiguration)
377+
}{
378+
{
379+
name: "override some",
380+
extraConfig: map[string]interface{}{
381+
"oomScoreAdj": -300,
382+
"enableDebuggingHandlers": true,
372383
},
373-
Logging: v1alpha1.LoggingConfiguration{
374-
Format: "json",
384+
expectedOverrides: func(kc *kubeletconfig.KubeletConfiguration) {
385+
kc.OOMScoreAdj = pointer.ToInt32(-300)
386+
kc.EnableDebuggingHandlers = pointer.ToBool(true)
375387
},
376-
ShutdownGracePeriod: metav1.Duration{Duration: constants.KubeletShutdownGracePeriod},
377-
ShutdownGracePeriodCriticalPods: metav1.Duration{Duration: constants.KubeletShutdownGracePeriodCriticalPods},
378-
StreamingConnectionIdleTimeout: metav1.Duration{Duration: 5 * time.Minute},
379-
TLSMinVersion: "VersionTLS13",
380-
EnableDebuggingHandlers: pointer.ToBool(true),
381388
},
382-
config,
383-
)
389+
{
390+
name: "disable graceful shutdown",
391+
extraConfig: map[string]interface{}{
392+
"shutdownGracePeriod": "0s",
393+
"shutdownGracePeriodCriticalPods": "0s",
394+
},
395+
expectedOverrides: func(kc *kubeletconfig.KubeletConfiguration) {
396+
kc.ShutdownGracePeriod = metav1.Duration{}
397+
kc.ShutdownGracePeriodCriticalPods = metav1.Duration{}
398+
},
399+
},
400+
} {
401+
tt := tt
402+
403+
t.Run(tt.name, func(t *testing.T) {
404+
expected := defaultKubeletConfig
405+
tt.expectedOverrides(&expected)
406+
407+
config, err := k8sctrl.NewKubeletConfiguration([]string{"10.0.0.5"}, "cluster.local", tt.extraConfig)
408+
409+
require.NoError(t, err)
410+
411+
assert.Equal(t, &expected, config)
412+
})
413+
}
384414
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
title: "Knowledge Base"
3+
weight: 1999
4+
description: "Recipes for common configuration tasks with Talos Linux."
5+
---
6+
7+
## Disabling `GracefulNodeShutdown` on a node
8+
9+
Talos Linux enables [Graceful Node Shutdown](https://kubernetes.io/docs/concepts/architecture/nodes/#graceful-node-shutdown) Kubernetes feature by default.
10+
11+
If this feature should be disabled, modify the `kubelet` part of the machine configuration with:
12+
13+
```yaml
14+
machine:
15+
kubelet:
16+
extraArgs:
17+
feature-gates: GracefulNodeShutdown=false
18+
extraConfig:
19+
shutdownGracePeriod: 0s
20+
shutdownGracePeriodCriticalPods: 0s
21+
```

0 commit comments

Comments
 (0)