In-place Pod Vertical Scaling - core implementation
1. Core Kubelet changes to implement In-place Pod Vertical Scaling. 2. E2E tests for In-place Pod Vertical Scaling. 3. Refactor kubelet code and add missing tests (Derek's kubelet review) 4. Add a new hash over container fields without Resources field to allow feature gate toggling without restarting containers not using the feature. 5. Fix corner-case where resize A->B->A gets ignored 6. Add cgroup v2 support to pod resize E2E test. KEP: /enhancements/keps/sig-node/1287-in-place-update-pod-resources Co-authored-by: Chen Wang <Chen.Wang1@ibm.com>
This commit is contained in:

committed by
vinay kulkarni

parent
231849a908
commit
f2bd94a0de
@@ -31,6 +31,7 @@ import (
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
|
||||
@@ -712,3 +713,167 @@ func TestGenerateLinuxContainerConfigSwap(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateLinuxContainerResources(t *testing.T) {
|
||||
_, _, m, err := createTestRuntimeManager()
|
||||
assert.NoError(t, err)
|
||||
m.machineInfo.MemoryCapacity = 17179860387 // 16GB
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
UID: "12345678",
|
||||
Name: "foo",
|
||||
Namespace: "bar",
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "c1",
|
||||
Image: "busybox",
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: v1.PodStatus{},
|
||||
}
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
scalingFg bool
|
||||
limits v1.ResourceList
|
||||
requests v1.ResourceList
|
||||
cStatus []v1.ContainerStatus
|
||||
expected *runtimeapi.LinuxContainerResources
|
||||
}{
|
||||
{
|
||||
"requests & limits, cpu & memory, guaranteed qos - no container status",
|
||||
true,
|
||||
v1.ResourceList{v1.ResourceCPU: resource.MustParse("250m"), v1.ResourceMemory: resource.MustParse("500Mi")},
|
||||
v1.ResourceList{v1.ResourceCPU: resource.MustParse("250m"), v1.ResourceMemory: resource.MustParse("500Mi")},
|
||||
[]v1.ContainerStatus{},
|
||||
&runtimeapi.LinuxContainerResources{CpuShares: 256, MemoryLimitInBytes: 524288000, OomScoreAdj: -997},
|
||||
},
|
||||
{
|
||||
"requests & limits, cpu & memory, burstable qos - no container status",
|
||||
true,
|
||||
v1.ResourceList{v1.ResourceCPU: resource.MustParse("500m"), v1.ResourceMemory: resource.MustParse("750Mi")},
|
||||
v1.ResourceList{v1.ResourceCPU: resource.MustParse("250m"), v1.ResourceMemory: resource.MustParse("500Mi")},
|
||||
[]v1.ContainerStatus{},
|
||||
&runtimeapi.LinuxContainerResources{CpuShares: 256, MemoryLimitInBytes: 786432000, OomScoreAdj: 970},
|
||||
},
|
||||
{
|
||||
"best-effort qos - no container status",
|
||||
true,
|
||||
nil,
|
||||
nil,
|
||||
[]v1.ContainerStatus{},
|
||||
&runtimeapi.LinuxContainerResources{CpuShares: 2, OomScoreAdj: 1000},
|
||||
},
|
||||
{
|
||||
"requests & limits, cpu & memory, guaranteed qos - empty resources container status",
|
||||
true,
|
||||
v1.ResourceList{v1.ResourceCPU: resource.MustParse("250m"), v1.ResourceMemory: resource.MustParse("500Mi")},
|
||||
v1.ResourceList{v1.ResourceCPU: resource.MustParse("250m"), v1.ResourceMemory: resource.MustParse("500Mi")},
|
||||
[]v1.ContainerStatus{{Name: "c1"}},
|
||||
&runtimeapi.LinuxContainerResources{CpuShares: 256, MemoryLimitInBytes: 524288000, OomScoreAdj: -997},
|
||||
},
|
||||
{
|
||||
"requests & limits, cpu & memory, burstable qos - empty resources container status",
|
||||
true,
|
||||
v1.ResourceList{v1.ResourceCPU: resource.MustParse("500m"), v1.ResourceMemory: resource.MustParse("750Mi")},
|
||||
v1.ResourceList{v1.ResourceCPU: resource.MustParse("250m"), v1.ResourceMemory: resource.MustParse("500Mi")},
|
||||
[]v1.ContainerStatus{{Name: "c1"}},
|
||||
&runtimeapi.LinuxContainerResources{CpuShares: 256, MemoryLimitInBytes: 786432000, OomScoreAdj: 999},
|
||||
},
|
||||
{
|
||||
"best-effort qos - empty resources container status",
|
||||
true,
|
||||
nil,
|
||||
nil,
|
||||
[]v1.ContainerStatus{{Name: "c1"}},
|
||||
&runtimeapi.LinuxContainerResources{CpuShares: 2, OomScoreAdj: 1000},
|
||||
},
|
||||
{
|
||||
"requests & limits, cpu & memory, guaranteed qos - container status with resourcesAllocated",
|
||||
true,
|
||||
v1.ResourceList{v1.ResourceCPU: resource.MustParse("200m"), v1.ResourceMemory: resource.MustParse("500Mi")},
|
||||
v1.ResourceList{v1.ResourceCPU: resource.MustParse("200m"), v1.ResourceMemory: resource.MustParse("500Mi")},
|
||||
[]v1.ContainerStatus{
|
||||
{
|
||||
Name: "c1",
|
||||
ResourcesAllocated: v1.ResourceList{v1.ResourceCPU: resource.MustParse("200m"), v1.ResourceMemory: resource.MustParse("500Mi")},
|
||||
},
|
||||
},
|
||||
&runtimeapi.LinuxContainerResources{CpuShares: 204, MemoryLimitInBytes: 524288000, OomScoreAdj: -997},
|
||||
},
|
||||
{
|
||||
"requests & limits, cpu & memory, burstable qos - container status with resourcesAllocated",
|
||||
true,
|
||||
v1.ResourceList{v1.ResourceCPU: resource.MustParse("500m"), v1.ResourceMemory: resource.MustParse("750Mi")},
|
||||
v1.ResourceList{v1.ResourceCPU: resource.MustParse("250m"), v1.ResourceMemory: resource.MustParse("500Mi")},
|
||||
[]v1.ContainerStatus{
|
||||
{
|
||||
Name: "c1",
|
||||
ResourcesAllocated: v1.ResourceList{v1.ResourceCPU: resource.MustParse("250m"), v1.ResourceMemory: resource.MustParse("500Mi")},
|
||||
},
|
||||
},
|
||||
&runtimeapi.LinuxContainerResources{CpuShares: 256, MemoryLimitInBytes: 786432000, OomScoreAdj: 970},
|
||||
},
|
||||
{
|
||||
"requests & limits, cpu & memory, guaranteed qos - no container status",
|
||||
false,
|
||||
v1.ResourceList{v1.ResourceCPU: resource.MustParse("250m"), v1.ResourceMemory: resource.MustParse("500Mi")},
|
||||
v1.ResourceList{v1.ResourceCPU: resource.MustParse("250m"), v1.ResourceMemory: resource.MustParse("500Mi")},
|
||||
[]v1.ContainerStatus{},
|
||||
&runtimeapi.LinuxContainerResources{CpuShares: 256, MemoryLimitInBytes: 524288000, OomScoreAdj: -997},
|
||||
},
|
||||
{
|
||||
"requests & limits, cpu & memory, burstable qos - container status with resourcesAllocated",
|
||||
false,
|
||||
v1.ResourceList{v1.ResourceCPU: resource.MustParse("500m"), v1.ResourceMemory: resource.MustParse("750Mi")},
|
||||
v1.ResourceList{v1.ResourceCPU: resource.MustParse("250m"), v1.ResourceMemory: resource.MustParse("500Mi")},
|
||||
[]v1.ContainerStatus{
|
||||
{
|
||||
Name: "c1",
|
||||
ResourcesAllocated: v1.ResourceList{v1.ResourceCPU: resource.MustParse("250m"), v1.ResourceMemory: resource.MustParse("500Mi")},
|
||||
},
|
||||
},
|
||||
&runtimeapi.LinuxContainerResources{CpuShares: 256, MemoryLimitInBytes: 786432000, OomScoreAdj: 970},
|
||||
},
|
||||
{
|
||||
"requests & limits, cpu & memory, guaranteed qos - container status with resourcesAllocated",
|
||||
false,
|
||||
v1.ResourceList{v1.ResourceCPU: resource.MustParse("200m"), v1.ResourceMemory: resource.MustParse("500Mi")},
|
||||
v1.ResourceList{v1.ResourceCPU: resource.MustParse("200m"), v1.ResourceMemory: resource.MustParse("500Mi")},
|
||||
[]v1.ContainerStatus{
|
||||
{
|
||||
Name: "c1",
|
||||
ResourcesAllocated: v1.ResourceList{v1.ResourceCPU: resource.MustParse("200m"), v1.ResourceMemory: resource.MustParse("500Mi")},
|
||||
},
|
||||
},
|
||||
&runtimeapi.LinuxContainerResources{CpuShares: 204, MemoryLimitInBytes: 524288000, OomScoreAdj: -997},
|
||||
},
|
||||
{
|
||||
"best-effort qos - no container status",
|
||||
false,
|
||||
nil,
|
||||
nil,
|
||||
[]v1.ContainerStatus{},
|
||||
&runtimeapi.LinuxContainerResources{CpuShares: 2, OomScoreAdj: 1000},
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if tc.scalingFg {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.InPlacePodVerticalScaling, true)()
|
||||
}
|
||||
tc.expected.HugepageLimits = []*runtimeapi.HugepageLimit{{PageSize: "2MB", Limit: 0}, {PageSize: "1GB", Limit: 0}}
|
||||
pod.Spec.Containers[0].Resources = v1.ResourceRequirements{Limits: tc.limits, Requests: tc.requests}
|
||||
if len(tc.cStatus) > 0 {
|
||||
pod.Status.ContainerStatuses = tc.cStatus
|
||||
}
|
||||
resources := m.generateLinuxContainerResources(pod, &pod.Spec.Containers[0], false)
|
||||
if diff.ObjectDiff(resources, tc.expected) != "" {
|
||||
t.Errorf("Test %s: expected resources %+v, but got %+v", tc.name, tc.expected, resources)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user