mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 05:27:21 +00:00
Merge pull request #99735 from bobbypage/beta-graceful-shutdown
Promote kubelet graceful node shutdown to beta
This commit is contained in:
commit
7125496e66
@ -657,6 +657,7 @@ const (
|
|||||||
|
|
||||||
// owner: @bobbypage
|
// owner: @bobbypage
|
||||||
// alpha: v1.20
|
// alpha: v1.20
|
||||||
|
// beta: v1.21
|
||||||
// Adds support for kubelet to detect node shutdown and gracefully terminate pods prior to the node being shutdown.
|
// Adds support for kubelet to detect node shutdown and gracefully terminate pods prior to the node being shutdown.
|
||||||
GracefulNodeShutdown featuregate.Feature = "GracefulNodeShutdown"
|
GracefulNodeShutdown featuregate.Feature = "GracefulNodeShutdown"
|
||||||
|
|
||||||
@ -787,7 +788,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
|||||||
SizeMemoryBackedVolumes: {Default: false, PreRelease: featuregate.Alpha},
|
SizeMemoryBackedVolumes: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
ExecProbeTimeout: {Default: true, PreRelease: featuregate.GA}, // lock to default in v1.21 and remove in v1.22
|
ExecProbeTimeout: {Default: true, PreRelease: featuregate.GA}, // lock to default in v1.21 and remove in v1.22
|
||||||
KubeletCredentialProviders: {Default: false, PreRelease: featuregate.Alpha},
|
KubeletCredentialProviders: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
GracefulNodeShutdown: {Default: false, PreRelease: featuregate.Alpha},
|
GracefulNodeShutdown: {Default: true, PreRelease: featuregate.Beta},
|
||||||
ServiceLBNodePortControl: {Default: false, PreRelease: featuregate.Alpha},
|
ServiceLBNodePortControl: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
MixedProtocolLBService: {Default: false, PreRelease: featuregate.Alpha},
|
MixedProtocolLBService: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
VolumeCapacityPriority: {Default: false, PreRelease: featuregate.Alpha},
|
VolumeCapacityPriority: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
|
@ -379,11 +379,15 @@ type KubeletConfiguration struct {
|
|||||||
// EnableSystemLogHandler enables /logs handler.
|
// EnableSystemLogHandler enables /logs handler.
|
||||||
EnableSystemLogHandler bool
|
EnableSystemLogHandler bool
|
||||||
// ShutdownGracePeriod specifies the total duration that the node should delay the shutdown and total grace period for pod termination during a node shutdown.
|
// ShutdownGracePeriod specifies the total duration that the node should delay the shutdown and total grace period for pod termination during a node shutdown.
|
||||||
// Defaults to 30 seconds, requires GracefulNodeShutdown feature gate to be enabled.
|
// Defaults to 0 seconds.
|
||||||
|
// +featureGate=GracefulNodeShutdown
|
||||||
|
// +optional
|
||||||
ShutdownGracePeriod metav1.Duration
|
ShutdownGracePeriod metav1.Duration
|
||||||
// ShutdownGracePeriodCriticalPods specifies the duration used to terminate critical pods during a node shutdown. This should be less than ShutdownGracePeriod.
|
// ShutdownGracePeriodCriticalPods specifies the duration used to terminate critical pods during a node shutdown. This should be less than ShutdownGracePeriod.
|
||||||
// Defaults to 10 seconds, requires GracefulNodeShutdown feature gate to be enabled.
|
// Defaults to 0 seconds.
|
||||||
// For example, if ShutdownGracePeriod=30s, and ShutdownGracePeriodCriticalPods=10s, during a node shutdown the first 20 seconds would be reserved for gracefully terminating normal pods, and the last 10 seconds would be reserved for terminating critical pods.
|
// For example, if ShutdownGracePeriod=30s, and ShutdownGracePeriodCriticalPods=10s, during a node shutdown the first 20 seconds would be reserved for gracefully terminating normal pods, and the last 10 seconds would be reserved for terminating critical pods.
|
||||||
|
// +featureGate=GracefulNodeShutdown
|
||||||
|
// +optional
|
||||||
ShutdownGracePeriodCriticalPods metav1.Duration
|
ShutdownGracePeriodCriticalPods metav1.Duration
|
||||||
// ReservedMemory specifies a comma-separated list of memory reservations for NUMA nodes.
|
// ReservedMemory specifies a comma-separated list of memory reservations for NUMA nodes.
|
||||||
// The parameter makes sense only in the context of the memory manager feature. The memory manager will not allocate reserved memory for container workloads.
|
// The parameter makes sense only in the context of the memory manager feature. The memory manager will not allocate reserved memory for container workloads.
|
||||||
|
@ -100,7 +100,6 @@ func TestValidateKubeletConfiguration(t *testing.T) {
|
|||||||
ShutdownGracePeriodCriticalPods: metav1.Duration{Duration: 0},
|
ShutdownGracePeriodCriticalPods: metav1.Duration{Duration: 0},
|
||||||
FeatureGates: map[string]bool{
|
FeatureGates: map[string]bool{
|
||||||
"CustomCPUCFSQuotaPeriod": true,
|
"CustomCPUCFSQuotaPeriod": true,
|
||||||
"GracefulNodeShutdown": true,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if allErrors := ValidateKubeletConfiguration(successCase2); allErrors != nil {
|
if allErrors := ValidateKubeletConfiguration(successCase2); allErrors != nil {
|
||||||
@ -133,7 +132,7 @@ func TestValidateKubeletConfiguration(t *testing.T) {
|
|||||||
NodeLeaseDurationSeconds: -1,
|
NodeLeaseDurationSeconds: -1,
|
||||||
CPUCFSQuotaPeriod: metav1.Duration{Duration: 100 * time.Millisecond},
|
CPUCFSQuotaPeriod: metav1.Duration{Duration: 100 * time.Millisecond},
|
||||||
ShutdownGracePeriod: metav1.Duration{Duration: 30 * time.Second},
|
ShutdownGracePeriod: metav1.Duration{Duration: 30 * time.Second},
|
||||||
ShutdownGracePeriodCriticalPods: metav1.Duration{Duration: 10 * time.Second},
|
ShutdownGracePeriodCriticalPods: metav1.Duration{Duration: 60 * time.Second},
|
||||||
}
|
}
|
||||||
const numErrsErrorCase1 = 28
|
const numErrsErrorCase1 = 28
|
||||||
if allErrors := ValidateKubeletConfiguration(errorCase1); len(allErrors.(utilerrors.Aggregate).Errors()) != numErrsErrorCase1 {
|
if allErrors := ValidateKubeletConfiguration(errorCase1); len(allErrors.(utilerrors.Aggregate).Errors()) != numErrsErrorCase1 {
|
||||||
|
@ -53,6 +53,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/kubelet/lifecycle"
|
"k8s.io/kubernetes/pkg/kubelet/lifecycle"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/logs"
|
"k8s.io/kubernetes/pkg/kubelet/logs"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/network/dns"
|
"k8s.io/kubernetes/pkg/kubelet/network/dns"
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/nodeshutdown"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/pleg"
|
"k8s.io/kubernetes/pkg/kubelet/pleg"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/pluginmanager"
|
"k8s.io/kubernetes/pkg/kubelet/pluginmanager"
|
||||||
kubepod "k8s.io/kubernetes/pkg/kubelet/pod"
|
kubepod "k8s.io/kubernetes/pkg/kubelet/pod"
|
||||||
@ -307,6 +308,12 @@ func newTestKubeletWithImageList(
|
|||||||
|
|
||||||
kubelet.evictionManager = evictionManager
|
kubelet.evictionManager = evictionManager
|
||||||
kubelet.admitHandlers.AddPodAdmitHandler(evictionAdmitHandler)
|
kubelet.admitHandlers.AddPodAdmitHandler(evictionAdmitHandler)
|
||||||
|
|
||||||
|
// setup shutdown manager
|
||||||
|
shutdownManager, shutdownAdmitHandler := nodeshutdown.NewManager(kubelet.podManager.GetPods, killPodNow(kubelet.podWorkers, fakeRecorder), func() {}, 0 /* shutdownGracePeriodRequested*/, 0 /*shutdownGracePeriodCriticalPods */)
|
||||||
|
kubelet.shutdownManager = shutdownManager
|
||||||
|
kubelet.admitHandlers.AddPodAdmitHandler(shutdownAdmitHandler)
|
||||||
|
|
||||||
// Add this as cleanup predicate pod admitter
|
// Add this as cleanup predicate pod admitter
|
||||||
kubelet.admitHandlers.AddPodAdmitHandler(lifecycle.NewPredicateAdmitHandler(kubelet.getNodeAnyWay, lifecycle.NewAdmissionFailureHandlerStub(), kubelet.containerManager.UpdatePluginResources))
|
kubelet.admitHandlers.AddPodAdmitHandler(lifecycle.NewPredicateAdmitHandler(kubelet.getNodeAnyWay, lifecycle.NewAdmissionFailureHandlerStub(), kubelet.containerManager.UpdatePluginResources))
|
||||||
|
|
||||||
|
@ -107,10 +107,7 @@ func (m *Manager) Admit(attrs *lifecycle.PodAdmitAttributes) lifecycle.PodAdmitR
|
|||||||
|
|
||||||
// Start starts the node shutdown manager and will start watching the node for shutdown events.
|
// Start starts the node shutdown manager and will start watching the node for shutdown events.
|
||||||
func (m *Manager) Start() error {
|
func (m *Manager) Start() error {
|
||||||
if !utilfeature.DefaultFeatureGate.Enabled(features.GracefulNodeShutdown) {
|
if !m.isFeatureEnabled() {
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if m.shutdownGracePeriodRequested == 0 {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,9 +199,14 @@ func (m *Manager) aquireInhibitLock() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns if the feature is enabled
|
||||||
|
func (m *Manager) isFeatureEnabled() bool {
|
||||||
|
return utilfeature.DefaultFeatureGate.Enabled(features.GracefulNodeShutdown) && m.shutdownGracePeriodRequested > 0
|
||||||
|
}
|
||||||
|
|
||||||
// ShutdownStatus will return an error if the node is currently shutting down.
|
// ShutdownStatus will return an error if the node is currently shutting down.
|
||||||
func (m *Manager) ShutdownStatus() error {
|
func (m *Manager) ShutdownStatus() error {
|
||||||
if !utilfeature.DefaultFeatureGate.Enabled(features.GracefulNodeShutdown) {
|
if !m.isFeatureEnabled() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,3 +261,47 @@ func TestManager(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFeatureEnabled(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
desc string
|
||||||
|
shutdownGracePeriodRequested time.Duration
|
||||||
|
featureGateEnabled bool
|
||||||
|
expectEnabled bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "shutdownGracePeriodRequested 0; disables feature",
|
||||||
|
shutdownGracePeriodRequested: time.Duration(0 * time.Second),
|
||||||
|
featureGateEnabled: true,
|
||||||
|
expectEnabled: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "feature gate disabled; disables feature",
|
||||||
|
shutdownGracePeriodRequested: time.Duration(100 * time.Second),
|
||||||
|
featureGateEnabled: false,
|
||||||
|
expectEnabled: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "feature gate enabled; shutdownGracePeriodRequested > 0; enables feature",
|
||||||
|
shutdownGracePeriodRequested: time.Duration(100 * time.Second),
|
||||||
|
featureGateEnabled: true,
|
||||||
|
expectEnabled: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
activePodsFunc := func() []*v1.Pod {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
killPodsFunc := func(pod *v1.Pod, status v1.PodStatus, gracePeriodOverride *int64) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.GracefulNodeShutdown, tc.featureGateEnabled)()
|
||||||
|
|
||||||
|
manager, _ := NewManager(activePodsFunc, killPodsFunc, func() {}, tc.shutdownGracePeriodRequested, 0 /*shutdownGracePeriodCriticalPods*/)
|
||||||
|
manager.clock = clock.NewFakeClock(time.Now())
|
||||||
|
|
||||||
|
assert.Equal(t, tc.expectEnabled, manager.isFeatureEnabled())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -830,12 +830,14 @@ type KubeletConfiguration struct {
|
|||||||
// +optional
|
// +optional
|
||||||
EnableSystemLogHandler *bool `json:"enableSystemLogHandler,omitempty"`
|
EnableSystemLogHandler *bool `json:"enableSystemLogHandler,omitempty"`
|
||||||
// ShutdownGracePeriod specifies the total duration that the node should delay the shutdown and total grace period for pod termination during a node shutdown.
|
// ShutdownGracePeriod specifies the total duration that the node should delay the shutdown and total grace period for pod termination during a node shutdown.
|
||||||
// Default: "30s"
|
// Default: "0s"
|
||||||
|
// +featureGate=GracefulNodeShutdown
|
||||||
// +optional
|
// +optional
|
||||||
ShutdownGracePeriod metav1.Duration `json:"shutdownGracePeriod,omitempty"`
|
ShutdownGracePeriod metav1.Duration `json:"shutdownGracePeriod,omitempty"`
|
||||||
// ShutdownGracePeriodCriticalPods specifies the duration used to terminate critical pods during a node shutdown. This should be less than ShutdownGracePeriod.
|
// ShutdownGracePeriodCriticalPods specifies the duration used to terminate critical pods during a node shutdown. This should be less than ShutdownGracePeriod.
|
||||||
// For example, if ShutdownGracePeriod=30s, and ShutdownGracePeriodCriticalPods=10s, during a node shutdown the first 20 seconds would be reserved for gracefully terminating normal pods, and the last 10 seconds would be reserved for terminating critical pods.
|
// For example, if ShutdownGracePeriod=30s, and ShutdownGracePeriodCriticalPods=10s, during a node shutdown the first 20 seconds would be reserved for gracefully terminating normal pods, and the last 10 seconds would be reserved for terminating critical pods.
|
||||||
// Default: "10s"
|
// Default: "0s"
|
||||||
|
// +featureGate=GracefulNodeShutdown
|
||||||
// +optional
|
// +optional
|
||||||
ShutdownGracePeriodCriticalPods metav1.Duration `json:"shutdownGracePeriodCriticalPods,omitempty"`
|
ShutdownGracePeriodCriticalPods metav1.Duration `json:"shutdownGracePeriodCriticalPods,omitempty"`
|
||||||
// ReservedMemory specifies a comma-separated list of memory reservations for NUMA nodes.
|
// ReservedMemory specifies a comma-separated list of memory reservations for NUMA nodes.
|
||||||
|
Loading…
Reference in New Issue
Block a user