Merge pull request #59681 from mtaufen/kc-empty-eviction-hard

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Ignore 0% and 100% eviction thresholds

Primarily, this gives a way to explicitly disable eviction, which is
necessary to use omitempty on EvictionHard.
See: https://github.com/kubernetes/kubernetes/pull/53833#discussion_r166672137

As justification for this approach, neither 0% nor 100% make sense as
eviction thresholds; in the "less-than" case, you can't have less than
0% of a resource and 100% perpetually evicts; in the
"greater-than" case (assuming we ever add a resource with this
semantic), the reasoning is the reverse (not more than 100%, 0%
perpetually evicts).

```release-note
Eviction thresholds set to 0% or 100% are now ignored.
```
pull/6/head
Kubernetes Submit Queue 2018-02-13 09:48:11 -08:00 committed by GitHub
commit 9de5839944
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 41 additions and 16 deletions

View File

@ -209,10 +209,10 @@ type KubeletConfiguration struct {
SerializeImagePulls *bool `json:"serializeImagePulls"`
// Map of signal names to quantities that defines hard eviction thresholds. For example: {"memory.available": "300Mi"}.
// +optional
EvictionHard map[string]string `json:"evictionHard"`
EvictionHard map[string]string `json:"evictionHard,omitempty"`
// Map of signal names to quantities that defines soft eviction thresholds. For example: {"memory.available": "300Mi"}.
// +optional
EvictionSoft map[string]string `json:"evictionSoft"`
EvictionSoft map[string]string `json:"evictionSoft,omitempty"`
// Map of signal names to quantities that defines grace periods for each soft eviction signal. For example: {"memory.available": "30s"}.
// +optional
EvictionSoftGracePeriod map[string]string `json:"evictionSoftGracePeriod"`

View File

@ -107,7 +107,6 @@ func ParseThresholdConfig(allocatableConfig []string, evictionHard, evictionSoft
return nil, err
}
results = append(results, hardThresholds...)
softThresholds, err := parseThresholdStatements(evictionSoft)
if err != nil {
return nil, err
@ -151,26 +150,36 @@ func parseThresholdStatements(statements map[string]string) ([]evictionapi.Thres
if err != nil {
return nil, err
}
results = append(results, result)
if result != nil {
results = append(results, *result)
}
}
return results, nil
}
// parseThresholdStatement parses a threshold statement.
func parseThresholdStatement(signal evictionapi.Signal, val string) (evictionapi.Threshold, error) {
// parseThresholdStatement parses a threshold statement and returns a threshold,
// or nil if the threshold should be ignored.
func parseThresholdStatement(signal evictionapi.Signal, val string) (*evictionapi.Threshold, error) {
if !validSignal(signal) {
return evictionapi.Threshold{}, fmt.Errorf(unsupportedEvictionSignal, signal)
return nil, fmt.Errorf(unsupportedEvictionSignal, signal)
}
operator := evictionapi.OpForSignal[signal]
if strings.HasSuffix(val, "%") {
// ignore 0% and 100%
if val == "0%" || val == "100%" {
return nil, nil
}
percentage, err := parsePercentage(val)
if err != nil {
return evictionapi.Threshold{}, err
return nil, err
}
if percentage <= 0 {
return evictionapi.Threshold{}, fmt.Errorf("eviction percentage threshold %v must be positive: %s", signal, val)
if percentage < 0 {
return nil, fmt.Errorf("eviction percentage threshold %v must be >= 0%%: %s", signal, val)
}
return evictionapi.Threshold{
if percentage > 100 {
return nil, fmt.Errorf("eviction percentage threshold %v must be <= 100%%: %s", signal, val)
}
return &evictionapi.Threshold{
Signal: signal,
Operator: operator,
Value: evictionapi.ThresholdValue{
@ -180,12 +189,12 @@ func parseThresholdStatement(signal evictionapi.Signal, val string) (evictionapi
}
quantity, err := resource.ParseQuantity(val)
if err != nil {
return evictionapi.Threshold{}, err
return nil, err
}
if quantity.Sign() < 0 || quantity.IsZero() {
return evictionapi.Threshold{}, fmt.Errorf("eviction threshold %v must be positive: %s", signal, &quantity)
return nil, fmt.Errorf("eviction threshold %v must be positive: %s", signal, &quantity)
}
return evictionapi.Threshold{
return &evictionapi.Threshold{
Signal: signal,
Operator: operator,
Value: evictionapi.ThresholdValue{

View File

@ -288,6 +288,20 @@ func TestParseThresholdConfig(t *testing.T) {
},
},
},
"disable via 0%": {
allocatableConfig: []string{},
evictionHard: map[string]string{"memory.available": "0%"},
evictionSoft: map[string]string{"memory.available": "0%"},
expectErr: false,
expectThresholds: []evictionapi.Threshold{},
},
"disable via 100%": {
allocatableConfig: []string{},
evictionHard: map[string]string{"memory.available": "100%"},
evictionSoft: map[string]string{"memory.available": "100%"},
expectErr: false,
expectThresholds: []evictionapi.Threshold{},
},
"invalid-signal": {
allocatableConfig: []string{},
evictionHard: map[string]string{"mem.available": "150Mi"},

View File

@ -170,7 +170,8 @@ var _ = framework.KubeDescribe("LocalStorageSoftEviction [Slow] [Serial] [Disrup
initialConfig.EvictionMaxPodGracePeriod = 30
initialConfig.EvictionMinimumReclaim = map[string]string{}
// Ensure that pods are not evicted because of the eviction-hard threshold
initialConfig.EvictionHard = map[string]string{}
// setting a threshold to 0% disables; non-empty map overrides default value (necessary due to omitempty)
initialConfig.EvictionHard = map[string]string{"memory.available": "0%"}
})
runEvictionTest(f, pressureTimeout, expectedNodeCondition, logDiskMetrics, []podEvictSpec{
{
@ -192,7 +193,8 @@ var _ = framework.KubeDescribe("LocalStorageCapacityIsolationEviction [Slow] [Se
Context(fmt.Sprintf(testContextFmt, "evictions due to pod local storage violations"), func() {
tempSetCurrentKubeletConfig(f, func(initialConfig *kubeletconfig.KubeletConfiguration) {
initialConfig.FeatureGates[string(features.LocalStorageCapacityIsolation)] = true
initialConfig.EvictionHard = map[string]string{}
// setting a threshold to 0% disables; non-empty map overrides default value (necessary due to omitempty)
initialConfig.EvictionHard = map[string]string{"memory.available": "0%"}
})
sizeLimit := resource.MustParse("100Mi")
useOverLimit := 101 /* Mb */