mirror of
https://github.com/kubernetes-sigs/descheduler.git
synced 2026-01-26 05:14:13 +01:00
feature(descheduler): add grace_period_seconds for DeschedulerPolicy
This commit is contained in:
20
README.md
20
README.md
@@ -118,15 +118,16 @@ The Descheduler Policy is configurable and includes default strategy plugins tha
|
|||||||
|
|
||||||
These are top level keys in the Descheduler Policy that you can use to configure all evictions.
|
These are top level keys in the Descheduler Policy that you can use to configure all evictions.
|
||||||
|
|
||||||
| Name | type | Default Value | Description |
|
| Name | type | Default Value | Description |
|
||||||
|------------------------------------|--------|---------------|----------------------------------------------------------------------------------------------------------------------------|
|
|------------------------------------|----------|---------------|----------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `nodeSelector` | `string` | `nil` | Limiting the nodes which are processed. Only used when `nodeFit`=`true` and only by the PreEvictionFilter Extension Point. |
|
| `nodeSelector` | `string` | `nil` | Limiting the nodes which are processed. Only used when `nodeFit`=`true` and only by the PreEvictionFilter Extension Point. |
|
||||||
| `maxNoOfPodsToEvictPerNode` | `int` | `nil` | Maximum number of pods evicted from each node (summed through all strategies). |
|
| `maxNoOfPodsToEvictPerNode` | `int` | `nil` | Maximum number of pods evicted from each node (summed through all strategies). |
|
||||||
| `maxNoOfPodsToEvictPerNamespace` | `int` | `nil` | Maximum number of pods evicted from each namespace (summed through all strategies). |
|
| `maxNoOfPodsToEvictPerNamespace` | `int` | `nil` | Maximum number of pods evicted from each namespace (summed through all strategies). |
|
||||||
| `maxNoOfPodsToEvictTotal` | `int` | `nil` | Maximum number of pods evicted per rescheduling cycle (summed through all strategies). |
|
| `maxNoOfPodsToEvictTotal` | `int` | `nil` | Maximum number of pods evicted per rescheduling cycle (summed through all strategies). |
|
||||||
| `metricsCollector` | `object` | `nil` | Configures collection of metrics for actual resource utilization. |
|
| `metricsCollector` | `object` | `nil` | Configures collection of metrics for actual resource utilization. |
|
||||||
| `metricsCollector.enabled` | `bool` | `false` | Enables Kubernetes [Metrics Server](https://kubernetes-sigs.github.io/metrics-server/) collection. |
|
| `metricsCollector.enabled` | `bool` | `false` | Enables Kubernetes [Metrics Server](https://kubernetes-sigs.github.io/metrics-server/) collection. |
|
||||||
| `evictionFailureEventNotification` | `bool` | `false` | Enables eviction failure event notification. |
|
| `evictionFailureEventNotification` | `bool` | `false` | Enables eviction failure event notification. |
|
||||||
|
| `gracePeriodSeconds` | `int` | `0` | The duration in seconds before the object should be deleted. The value zero indicates delete immediately. |
|
||||||
|
|
||||||
### Evictor Plugin configuration (Default Evictor)
|
### Evictor Plugin configuration (Default Evictor)
|
||||||
|
|
||||||
@@ -161,6 +162,7 @@ nodeSelector: "node=node1" # you don't need to set this, if not set all will be
|
|||||||
maxNoOfPodsToEvictPerNode: 5000 # you don't need to set this, unlimited if not set
|
maxNoOfPodsToEvictPerNode: 5000 # you don't need to set this, unlimited if not set
|
||||||
maxNoOfPodsToEvictPerNamespace: 5000 # you don't need to set this, unlimited if not set
|
maxNoOfPodsToEvictPerNamespace: 5000 # you don't need to set this, unlimited if not set
|
||||||
maxNoOfPodsToEvictTotal: 5000 # you don't need to set this, unlimited if not set
|
maxNoOfPodsToEvictTotal: 5000 # you don't need to set this, unlimited if not set
|
||||||
|
gracePeriodSeconds: 60 # you don't need to set this, 0 if not set
|
||||||
metricsCollector:
|
metricsCollector:
|
||||||
enabled: true # you don't need to set this, metrics are not collected if not set
|
enabled: true # you don't need to set this, metrics are not collected if not set
|
||||||
profiles:
|
profiles:
|
||||||
|
|||||||
@@ -48,6 +48,12 @@ type DeschedulerPolicy struct {
|
|||||||
|
|
||||||
// MetricsCollector configures collection of metrics about actual resource utilization
|
// MetricsCollector configures collection of metrics about actual resource utilization
|
||||||
MetricsCollector MetricsCollector
|
MetricsCollector MetricsCollector
|
||||||
|
|
||||||
|
// GracePeriodSeconds The duration in seconds before the object should be deleted. Value must be non-negative integer.
|
||||||
|
// The value zero indicates delete immediately. If this value is nil, the default grace period for the
|
||||||
|
// specified type will be used.
|
||||||
|
// Defaults to a per object value if not specified. zero means delete immediately.
|
||||||
|
GracePeriodSeconds *int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// Namespaces carries a list of included/excluded namespaces
|
// Namespaces carries a list of included/excluded namespaces
|
||||||
|
|||||||
@@ -47,6 +47,12 @@ type DeschedulerPolicy struct {
|
|||||||
|
|
||||||
// MetricsCollector configures collection of metrics for actual resource utilization
|
// MetricsCollector configures collection of metrics for actual resource utilization
|
||||||
MetricsCollector MetricsCollector `json:"metricsCollector,omitempty"`
|
MetricsCollector MetricsCollector `json:"metricsCollector,omitempty"`
|
||||||
|
|
||||||
|
// GracePeriodSeconds The duration in seconds before the object should be deleted. Value must be non-negative integer.
|
||||||
|
// The value zero indicates delete immediately. If this value is nil, the default grace period for the
|
||||||
|
// specified type will be used.
|
||||||
|
// Defaults to a per object value if not specified. zero means delete immediately.
|
||||||
|
GracePeriodSeconds *int64 `json:"gracePeriodSeconds,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeschedulerProfile struct {
|
type DeschedulerProfile struct {
|
||||||
|
|||||||
2
pkg/api/v1alpha2/zz_generated.conversion.go
generated
2
pkg/api/v1alpha2/zz_generated.conversion.go
generated
@@ -119,6 +119,7 @@ func autoConvert_v1alpha2_DeschedulerPolicy_To_api_DeschedulerPolicy(in *Desched
|
|||||||
if err := Convert_v1alpha2_MetricsCollector_To_api_MetricsCollector(&in.MetricsCollector, &out.MetricsCollector, s); err != nil {
|
if err := Convert_v1alpha2_MetricsCollector_To_api_MetricsCollector(&in.MetricsCollector, &out.MetricsCollector, s); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
out.GracePeriodSeconds = (*int64)(unsafe.Pointer(in.GracePeriodSeconds))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,6 +143,7 @@ func autoConvert_api_DeschedulerPolicy_To_v1alpha2_DeschedulerPolicy(in *api.Des
|
|||||||
if err := Convert_api_MetricsCollector_To_v1alpha2_MetricsCollector(&in.MetricsCollector, &out.MetricsCollector, s); err != nil {
|
if err := Convert_api_MetricsCollector_To_v1alpha2_MetricsCollector(&in.MetricsCollector, &out.MetricsCollector, s); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
out.GracePeriodSeconds = (*int64)(unsafe.Pointer(in.GracePeriodSeconds))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
5
pkg/api/v1alpha2/zz_generated.deepcopy.go
generated
5
pkg/api/v1alpha2/zz_generated.deepcopy.go
generated
@@ -62,6 +62,11 @@ func (in *DeschedulerPolicy) DeepCopyInto(out *DeschedulerPolicy) {
|
|||||||
**out = **in
|
**out = **in
|
||||||
}
|
}
|
||||||
out.MetricsCollector = in.MetricsCollector
|
out.MetricsCollector = in.MetricsCollector
|
||||||
|
if in.GracePeriodSeconds != nil {
|
||||||
|
in, out := &in.GracePeriodSeconds, &out.GracePeriodSeconds
|
||||||
|
*out = new(int64)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
5
pkg/api/zz_generated.deepcopy.go
generated
5
pkg/api/zz_generated.deepcopy.go
generated
@@ -62,6 +62,11 @@ func (in *DeschedulerPolicy) DeepCopyInto(out *DeschedulerPolicy) {
|
|||||||
**out = **in
|
**out = **in
|
||||||
}
|
}
|
||||||
out.MetricsCollector = in.MetricsCollector
|
out.MetricsCollector = in.MetricsCollector
|
||||||
|
if in.GracePeriodSeconds != nil {
|
||||||
|
in, out := &in.GracePeriodSeconds, &out.GracePeriodSeconds
|
||||||
|
*out = new(int64)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ func newDescheduler(ctx context.Context, rs *options.DeschedulerServer, deschedu
|
|||||||
WithMaxPodsToEvictPerNamespace(deschedulerPolicy.MaxNoOfPodsToEvictPerNamespace).
|
WithMaxPodsToEvictPerNamespace(deschedulerPolicy.MaxNoOfPodsToEvictPerNamespace).
|
||||||
WithMaxPodsToEvictTotal(deschedulerPolicy.MaxNoOfPodsToEvictTotal).
|
WithMaxPodsToEvictTotal(deschedulerPolicy.MaxNoOfPodsToEvictTotal).
|
||||||
WithEvictionFailureEventNotification(deschedulerPolicy.EvictionFailureEventNotification).
|
WithEvictionFailureEventNotification(deschedulerPolicy.EvictionFailureEventNotification).
|
||||||
|
WithGracePeriodSeconds(deschedulerPolicy.GracePeriodSeconds).
|
||||||
WithDryRun(rs.DryRun).
|
WithDryRun(rs.DryRun).
|
||||||
WithMetricsEnabled(!rs.DisableMetrics),
|
WithMetricsEnabled(!rs.DisableMetrics),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -214,6 +214,7 @@ type PodEvictor struct {
|
|||||||
maxPodsToEvictPerNode *uint
|
maxPodsToEvictPerNode *uint
|
||||||
maxPodsToEvictPerNamespace *uint
|
maxPodsToEvictPerNamespace *uint
|
||||||
maxPodsToEvictTotal *uint
|
maxPodsToEvictTotal *uint
|
||||||
|
gracePeriodSeconds *int64
|
||||||
nodePodCount nodePodEvictedCount
|
nodePodCount nodePodEvictedCount
|
||||||
namespacePodCount namespacePodEvictCount
|
namespacePodCount namespacePodEvictCount
|
||||||
totalPodCount uint
|
totalPodCount uint
|
||||||
@@ -247,6 +248,7 @@ func NewPodEvictor(
|
|||||||
maxPodsToEvictPerNode: options.maxPodsToEvictPerNode,
|
maxPodsToEvictPerNode: options.maxPodsToEvictPerNode,
|
||||||
maxPodsToEvictPerNamespace: options.maxPodsToEvictPerNamespace,
|
maxPodsToEvictPerNamespace: options.maxPodsToEvictPerNamespace,
|
||||||
maxPodsToEvictTotal: options.maxPodsToEvictTotal,
|
maxPodsToEvictTotal: options.maxPodsToEvictTotal,
|
||||||
|
gracePeriodSeconds: options.gracePeriodSeconds,
|
||||||
metricsEnabled: options.metricsEnabled,
|
metricsEnabled: options.metricsEnabled,
|
||||||
nodePodCount: make(nodePodEvictedCount),
|
nodePodCount: make(nodePodEvictedCount),
|
||||||
namespacePodCount: make(namespacePodEvictCount),
|
namespacePodCount: make(namespacePodEvictCount),
|
||||||
@@ -563,7 +565,9 @@ func (pe *PodEvictor) EvictPod(ctx context.Context, pod *v1.Pod, opts EvictOptio
|
|||||||
|
|
||||||
// return (ignore, err)
|
// return (ignore, err)
|
||||||
func (pe *PodEvictor) evictPod(ctx context.Context, pod *v1.Pod) (bool, error) {
|
func (pe *PodEvictor) evictPod(ctx context.Context, pod *v1.Pod) (bool, error) {
|
||||||
deleteOptions := &metav1.DeleteOptions{}
|
deleteOptions := &metav1.DeleteOptions{
|
||||||
|
GracePeriodSeconds: pe.gracePeriodSeconds,
|
||||||
|
}
|
||||||
// GracePeriodSeconds ?
|
// GracePeriodSeconds ?
|
||||||
eviction := &policy.Eviction{
|
eviction := &policy.Eviction{
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ type Options struct {
|
|||||||
maxPodsToEvictTotal *uint
|
maxPodsToEvictTotal *uint
|
||||||
evictionFailureEventNotification bool
|
evictionFailureEventNotification bool
|
||||||
metricsEnabled bool
|
metricsEnabled bool
|
||||||
|
gracePeriodSeconds *int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOptions returns an Options with default values.
|
// NewOptions returns an Options with default values.
|
||||||
@@ -46,6 +47,11 @@ func (o *Options) WithMaxPodsToEvictTotal(maxPodsToEvictTotal *uint) *Options {
|
|||||||
return o
|
return o
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *Options) WithGracePeriodSeconds(gracePeriodSeconds *int64) *Options {
|
||||||
|
o.gracePeriodSeconds = gracePeriodSeconds
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
func (o *Options) WithMetricsEnabled(metricsEnabled bool) *Options {
|
func (o *Options) WithMetricsEnabled(metricsEnabled bool) *Options {
|
||||||
o.metricsEnabled = metricsEnabled
|
o.metricsEnabled = metricsEnabled
|
||||||
return o
|
return o
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ import (
|
|||||||
|
|
||||||
const deploymentReplicas = 4
|
const deploymentReplicas = 4
|
||||||
|
|
||||||
func tooManyRestartsPolicy(targetNamespace string, podRestartThresholds int32, includingInitContainers bool) *apiv1alpha2.DeschedulerPolicy {
|
func tooManyRestartsPolicy(targetNamespace string, podRestartThresholds int32, includingInitContainers bool, gracePeriodSeconds int64) *apiv1alpha2.DeschedulerPolicy {
|
||||||
return &apiv1alpha2.DeschedulerPolicy{
|
return &apiv1alpha2.DeschedulerPolicy{
|
||||||
Profiles: []apiv1alpha2.DeschedulerProfile{
|
Profiles: []apiv1alpha2.DeschedulerProfile{
|
||||||
{
|
{
|
||||||
@@ -84,6 +84,7 @@ func tooManyRestartsPolicy(targetNamespace string, podRestartThresholds int32, i
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
GracePeriodSeconds: &gracePeriodSeconds,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,16 +128,23 @@ func TestTooManyRestarts(t *testing.T) {
|
|||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
policy *apiv1alpha2.DeschedulerPolicy
|
policy *apiv1alpha2.DeschedulerPolicy
|
||||||
|
enableGracePeriod bool
|
||||||
expectedEvictedPodCount uint
|
expectedEvictedPodCount uint
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "test-no-evictions",
|
name: "test-no-evictions",
|
||||||
policy: tooManyRestartsPolicy(testNamespace.Name, 10000, true),
|
policy: tooManyRestartsPolicy(testNamespace.Name, 10000, true, 0),
|
||||||
expectedEvictedPodCount: 0,
|
expectedEvictedPodCount: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test-one-evictions",
|
name: "test-one-evictions",
|
||||||
policy: tooManyRestartsPolicy(testNamespace.Name, 3, true),
|
policy: tooManyRestartsPolicy(testNamespace.Name, 3, true, 0),
|
||||||
|
expectedEvictedPodCount: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "test-one-evictions-use-gracePeriodSeconds",
|
||||||
|
policy: tooManyRestartsPolicy(testNamespace.Name, 3, true, 60),
|
||||||
|
enableGracePeriod: true,
|
||||||
expectedEvictedPodCount: 4,
|
expectedEvictedPodCount: 4,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -197,8 +205,32 @@ func TestTooManyRestarts(t *testing.T) {
|
|||||||
deschedulerPodName = deschedulerPods[0].Name
|
deschedulerPodName = deschedulerPods[0].Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if grace period is enabled and wait accordingly
|
||||||
|
if tc.enableGracePeriod {
|
||||||
|
// Ensure no pods are evicted during the grace period
|
||||||
|
// Wait for 55 seconds to ensure that the pods are not evicted during the grace period
|
||||||
|
// We do not want to use an extreme waiting time, such as 59 seconds,
|
||||||
|
// because the grace period is set to 60 seconds.
|
||||||
|
// In order to avoid unnecessary flake failures,
|
||||||
|
// we only need to make sure that the pod is not evicted within a certain range.
|
||||||
|
t.Logf("Waiting for grace period of %d seconds", 55)
|
||||||
|
if err := wait.PollUntilContextTimeout(ctx, 1*time.Second, time.Duration(55)*time.Second, true, func(ctx context.Context) (bool, error) {
|
||||||
|
currentRunNames := sets.NewString(getCurrentPodNames(ctx, clientSet, testNamespace.Name, t)...)
|
||||||
|
actualEvictedPod := preRunNames.Difference(currentRunNames)
|
||||||
|
actualEvictedPodCount := uint(actualEvictedPod.Len())
|
||||||
|
t.Logf("preRunNames: %v, currentRunNames: %v, actualEvictedPodCount: %v\n", preRunNames.List(), currentRunNames.List(), actualEvictedPodCount)
|
||||||
|
if actualEvictedPodCount > 0 {
|
||||||
|
t.Fatalf("Pods were evicted during grace period; expected 0, got %v", actualEvictedPodCount)
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatalf("Error waiting during grace period: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Run RemovePodsHavingTooManyRestarts strategy
|
// Run RemovePodsHavingTooManyRestarts strategy
|
||||||
if err := wait.PollUntilContextTimeout(ctx, 1*time.Second, 20*time.Second, true, func(ctx context.Context) (bool, error) {
|
if err := wait.PollUntilContextTimeout(ctx, 1*time.Second, 50*time.Second, true, func(ctx context.Context) (bool, error) {
|
||||||
currentRunNames := sets.NewString(getCurrentPodNames(ctx, clientSet, testNamespace.Name, t)...)
|
currentRunNames := sets.NewString(getCurrentPodNames(ctx, clientSet, testNamespace.Name, t)...)
|
||||||
actualEvictedPod := preRunNames.Difference(currentRunNames)
|
actualEvictedPod := preRunNames.Difference(currentRunNames)
|
||||||
actualEvictedPodCount := uint(actualEvictedPod.Len())
|
actualEvictedPodCount := uint(actualEvictedPod.Len())
|
||||||
@@ -210,7 +242,7 @@ func TestTooManyRestarts(t *testing.T) {
|
|||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
t.Errorf("Error waiting for descheduler running: %v", err)
|
t.Fatalf("Error waiting for descheduler running: %v", err)
|
||||||
}
|
}
|
||||||
waitForTerminatingPodsToDisappear(ctx, t, clientSet, testNamespace.Name)
|
waitForTerminatingPodsToDisappear(ctx, t, clientSet, testNamespace.Name)
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user