mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-31 15:25:57 +00:00
Merge pull request #126981 from kannon92/stable-empty-dir-promotion
KEP-1967: promote size backed memory volumes to stable
This commit is contained in:
commit
685b8b3ba1
@ -602,6 +602,8 @@ const (
|
||||
// owner: @derekwaynecarr
|
||||
//
|
||||
// Enables kubelet support to size memory backed volumes
|
||||
// This is a kubelet only feature gate.
|
||||
// Code can be removed in 1.35 without any consideration for emulated versions.
|
||||
SizeMemoryBackedVolumes featuregate.Feature = "SizeMemoryBackedVolumes"
|
||||
|
||||
// owner: @mattcary
|
||||
|
@ -683,6 +683,7 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
|
||||
SizeMemoryBackedVolumes: {
|
||||
{Version: version.MustParse("1.20"), Default: false, PreRelease: featuregate.Alpha},
|
||||
{Version: version.MustParse("1.22"), Default: true, PreRelease: featuregate.Beta},
|
||||
{Version: version.MustParse("1.32"), Default: true, LockToDefault: true, PreRelease: featuregate.GA},
|
||||
},
|
||||
|
||||
StatefulSetAutoDeletePVC: {
|
||||
|
@ -21,20 +21,18 @@ package emptydir
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"k8s.io/kubernetes/pkg/kubelet/util/swap"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubelet/util/swap"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
utiltesting "k8s.io/client-go/util/testing"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
volumetest "k8s.io/kubernetes/pkg/volume/testing"
|
||||
volumeutil "k8s.io/kubernetes/pkg/volume/util"
|
||||
@ -963,27 +961,7 @@ func TestCalculateEmptyDirMemorySize(t *testing.T) {
|
||||
nodeAllocatableMemory resource.Quantity
|
||||
emptyDirSizeLimit resource.Quantity
|
||||
expectedResult resource.Quantity
|
||||
featureGateEnabled bool
|
||||
}{
|
||||
"SizeMemoryBackedVolumesDisabled": {
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName("memory"): resource.MustParse("10Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
nodeAllocatableMemory: resource.MustParse("16Gi"),
|
||||
emptyDirSizeLimit: resource.MustParse("1Gi"),
|
||||
expectedResult: resource.MustParse("0"),
|
||||
featureGateEnabled: false,
|
||||
},
|
||||
"EmptyDirLocalLimit": {
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
@ -1001,7 +979,6 @@ func TestCalculateEmptyDirMemorySize(t *testing.T) {
|
||||
nodeAllocatableMemory: resource.MustParse("16Gi"),
|
||||
emptyDirSizeLimit: resource.MustParse("1Gi"),
|
||||
expectedResult: resource.MustParse("1Gi"),
|
||||
featureGateEnabled: true,
|
||||
},
|
||||
"PodLocalLimit": {
|
||||
pod: &v1.Pod{
|
||||
@ -1020,7 +997,6 @@ func TestCalculateEmptyDirMemorySize(t *testing.T) {
|
||||
nodeAllocatableMemory: resource.MustParse("16Gi"),
|
||||
emptyDirSizeLimit: resource.MustParse("0"),
|
||||
expectedResult: resource.MustParse("10Gi"),
|
||||
featureGateEnabled: true,
|
||||
},
|
||||
"NodeAllocatableLimit": {
|
||||
pod: &v1.Pod{
|
||||
@ -1039,13 +1015,11 @@ func TestCalculateEmptyDirMemorySize(t *testing.T) {
|
||||
nodeAllocatableMemory: resource.MustParse("16Gi"),
|
||||
emptyDirSizeLimit: resource.MustParse("0"),
|
||||
expectedResult: resource.MustParse("16Gi"),
|
||||
featureGateEnabled: true,
|
||||
},
|
||||
}
|
||||
|
||||
for testCaseName, testCase := range testCases {
|
||||
t.Run(testCaseName, func(t *testing.T) {
|
||||
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SizeMemoryBackedVolumes, testCase.featureGateEnabled)
|
||||
spec := &volume.Spec{
|
||||
Volume: &v1.Volume{
|
||||
VolumeSource: v1.VolumeSource{
|
||||
|
@ -288,51 +288,6 @@ var _ = SIGDescribe("LocalStorageSoftEvictionNotOverwriteTerminationGracePeriodS
|
||||
})
|
||||
})
|
||||
|
||||
// This test validates that in-memory EmptyDir's are evicted when the Kubelet does
|
||||
// not have Sized Memory Volumes enabled. When Sized volumes are enabled, it's
|
||||
// not possible to exhaust the quota.
|
||||
var _ = SIGDescribe("LocalStorageCapacityIsolationMemoryBackedVolumeEviction", framework.WithSlow(), framework.WithSerial(), framework.WithDisruptive(), feature.LocalStorageCapacityIsolation, nodefeature.Eviction, func() {
|
||||
f := framework.NewDefaultFramework("localstorage-eviction-test")
|
||||
f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
|
||||
evictionTestTimeout := 7 * time.Minute
|
||||
ginkgo.Context(fmt.Sprintf(testContextFmt, "evictions due to pod local storage violations"), func() {
|
||||
tempSetCurrentKubeletConfig(f, func(ctx context.Context, initialConfig *kubeletconfig.KubeletConfiguration) {
|
||||
// setting a threshold to 0% disables; non-empty map overrides default value (necessary due to omitempty)
|
||||
initialConfig.EvictionHard = map[string]string{string(evictionapi.SignalMemoryAvailable): "0%"}
|
||||
if initialConfig.FeatureGates == nil {
|
||||
initialConfig.FeatureGates = make(map[string]bool)
|
||||
}
|
||||
initialConfig.FeatureGates["SizeMemoryBackedVolumes"] = false
|
||||
})
|
||||
|
||||
sizeLimit := resource.MustParse("100Mi")
|
||||
useOverLimit := 200 /* Mb */
|
||||
useUnderLimit := 80 /* Mb */
|
||||
containerLimit := v1.ResourceList{v1.ResourceEphemeralStorage: sizeLimit}
|
||||
|
||||
runEvictionTest(f, evictionTestTimeout, noPressure, noStarvedResource, logDiskMetrics, []podEvictSpec{
|
||||
{
|
||||
evictionPriority: 1, // Should be evicted due to disk limit
|
||||
pod: diskConsumingPod("emptydir-memory-over-volume-sizelimit", useOverLimit, &v1.VolumeSource{
|
||||
EmptyDir: &v1.EmptyDirVolumeSource{Medium: "Memory", SizeLimit: &sizeLimit},
|
||||
}, v1.ResourceRequirements{}),
|
||||
},
|
||||
{
|
||||
evictionPriority: 0, // Should not be evicted, as container limits do not account for memory backed volumes
|
||||
pod: diskConsumingPod("emptydir-memory-over-container-sizelimit", useOverLimit, &v1.VolumeSource{
|
||||
EmptyDir: &v1.EmptyDirVolumeSource{Medium: "Memory"},
|
||||
}, v1.ResourceRequirements{Limits: containerLimit}),
|
||||
},
|
||||
{
|
||||
evictionPriority: 0,
|
||||
pod: diskConsumingPod("emptydir-memory-innocent", useUnderLimit, &v1.VolumeSource{
|
||||
EmptyDir: &v1.EmptyDirVolumeSource{Medium: "Memory", SizeLimit: &sizeLimit},
|
||||
}, v1.ResourceRequirements{}),
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// LocalStorageCapacityIsolationEviction tests that container and volume local storage limits are enforced through evictions
|
||||
var _ = SIGDescribe("LocalStorageCapacityIsolationEviction", framework.WithSlow(), framework.WithSerial(), framework.WithDisruptive(), feature.LocalStorageCapacityIsolation, nodefeature.Eviction, func() {
|
||||
f := framework.NewDefaultFramework("localstorage-eviction-test")
|
||||
|
@ -1148,6 +1148,10 @@
|
||||
lockToDefault: false
|
||||
preRelease: Beta
|
||||
version: "1.22"
|
||||
- default: true
|
||||
lockToDefault: true
|
||||
preRelease: GA
|
||||
version: "1.32"
|
||||
- name: StatefulSetAutoDeletePVC
|
||||
versionedSpecs:
|
||||
- default: false
|
||||
|
Loading…
Reference in New Issue
Block a user