Skip to content

Commit f816be0

Browse files
authored
Merge pull request kubernetes#129216 from tallclair/ippr-supported
[FG:InPlacePodVerticalScaling] Never attempt a resize of windows pods and always use allocated resources for unsupported resize pods
2 parents 0156f6e + cb5c8d1 commit f816be0

File tree

8 files changed

+108
-31
lines changed

8 files changed

+108
-31
lines changed

pkg/kubelet/kubelet.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1883,7 +1883,7 @@ func (kl *Kubelet) SyncPod(ctx context.Context, updateType kubetypes.SyncPodType
18831883
// handlePodResourcesResize updates the pod to use the allocated resources. This should come
18841884
// before the main business logic of SyncPod, so that a consistent view of the pod is used
18851885
// across the sync loop.
1886-
if kuberuntime.IsInPlacePodVerticalScalingAllowed(pod) {
1886+
if utilfeature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling) {
18871887
// Handle pod resize here instead of doing it in HandlePodUpdates because
18881888
// this conveniently retries any Deferred resize requests
18891889
// TODO(vinaykul,InPlacePodVerticalScaling): Investigate doing this in HandlePodUpdates + periodic SyncLoop scan
@@ -2816,10 +2816,6 @@ func (kl *Kubelet) HandlePodSyncs(pods []*v1.Pod) {
28162816
// pod should hold the desired (pre-allocated) spec.
28172817
// Returns true if the resize can proceed.
28182818
func (kl *Kubelet) canResizePod(pod *v1.Pod) (bool, v1.PodResizeStatus, string) {
2819-
if goos == "windows" {
2820-
return false, v1.PodResizeStatusInfeasible, "Resizing Windows pods is not supported"
2821-
}
2822-
28232819
if v1qos.GetPodQOS(pod) == v1.PodQOSGuaranteed && !utilfeature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScalingExclusiveCPUs) {
28242820
if utilfeature.DefaultFeatureGate.Enabled(features.CPUManager) {
28252821
if kl.containerManager.GetNodeConfig().CPUManagerPolicy == "static" {
@@ -2877,6 +2873,7 @@ func (kl *Kubelet) canResizePod(pod *v1.Pod) (bool, v1.PodResizeStatus, string)
28772873
// the allocation decision and pod status.
28782874
func (kl *Kubelet) handlePodResourcesResize(pod *v1.Pod, podStatus *kubecontainer.PodStatus) (*v1.Pod, error) {
28792875
allocatedPod, updated := kl.allocationManager.UpdatePodFromAllocation(pod)
2876+
28802877
if !updated {
28812878
// Desired resources == allocated resources. Check whether a resize is in progress.
28822879
resizeInProgress := !allocatedResourcesMatchStatus(allocatedPod, podStatus)
@@ -2889,6 +2886,11 @@ func (kl *Kubelet) handlePodResourcesResize(pod *v1.Pod, podStatus *kubecontaine
28892886
}
28902887
// Pod allocation does not need to be updated.
28912888
return allocatedPod, nil
2889+
} else if resizable, msg := kuberuntime.IsInPlacePodVerticalScalingAllowed(pod); !resizable {
2890+
// If there is a pending resize but the resize is not allowed, always use the allocated resources.
2891+
kl.recorder.Eventf(pod, v1.EventTypeWarning, events.ResizeInfeasible, msg)
2892+
kl.statusManager.SetPodResizeStatus(pod.UID, v1.PodResizeStatusInfeasible)
2893+
return allocatedPod, nil
28922894
}
28932895

28942896
kl.podResizeMutex.Lock()

pkg/kubelet/kubelet_pods.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1748,10 +1748,6 @@ func getPhase(pod *v1.Pod, info []v1.ContainerStatus, podIsTerminal bool) v1.Pod
17481748
}
17491749

17501750
func (kl *Kubelet) determinePodResizeStatus(allocatedPod *v1.Pod, podStatus *kubecontainer.PodStatus, podIsTerminal bool) v1.PodResizeStatus {
1751-
if kubetypes.IsStaticPod(allocatedPod) {
1752-
return ""
1753-
}
1754-
17551751
// If pod is terminal, clear the resize status.
17561752
if podIsTerminal {
17571753
kl.statusManager.SetPodResizeStatus(allocatedPod.UID, "")

pkg/kubelet/kubelet_test.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2711,7 +2711,7 @@ func TestHandlePodResourcesResize(t *testing.T) {
27112711
expectedAllocatedLims v1.ResourceList
27122712
expectedResize v1.PodResizeStatus
27132713
expectBackoffReset bool
2714-
goos string
2714+
annotations map[string]string
27152715
}{
27162716
{
27172717
name: "Request CPU and memory decrease - expect InProgress",
@@ -2781,12 +2781,12 @@ func TestHandlePodResourcesResize(t *testing.T) {
27812781
expectedResize: "",
27822782
},
27832783
{
2784-
name: "windows node, expect Infeasible",
2784+
name: "static pod, expect Infeasible",
27852785
originalRequests: v1.ResourceList{v1.ResourceCPU: cpu1000m, v1.ResourceMemory: mem1000M},
27862786
newRequests: v1.ResourceList{v1.ResourceCPU: cpu500m, v1.ResourceMemory: mem500M},
27872787
expectedAllocatedReqs: v1.ResourceList{v1.ResourceCPU: cpu1000m, v1.ResourceMemory: mem1000M},
27882788
expectedResize: v1.PodResizeStatusInfeasible,
2789-
goos: "windows",
2789+
annotations: map[string]string{kubetypes.ConfigSourceAnnotationKey: kubetypes.FileSource},
27902790
},
27912791
{
27922792
name: "Increase CPU from min shares",
@@ -2873,11 +2873,6 @@ func TestHandlePodResourcesResize(t *testing.T) {
28732873
for _, tt := range tests {
28742874
for _, isSidecarContainer := range []bool{false, true} {
28752875
t.Run(tt.name, func(t *testing.T) {
2876-
oldGOOS := goos
2877-
defer func() { goos = oldGOOS }()
2878-
if tt.goos != "" {
2879-
goos = tt.goos
2880-
}
28812876
kubelet.statusManager = status.NewFakeManager()
28822877

28832878
var originalPod *v1.Pod
@@ -2889,6 +2884,7 @@ func TestHandlePodResourcesResize(t *testing.T) {
28892884
originalPod = testPod1.DeepCopy()
28902885
originalCtr = &originalPod.Spec.Containers[0]
28912886
}
2887+
originalPod.Annotations = tt.annotations
28922888
originalCtr.Resources.Requests = tt.originalRequests
28932889
originalCtr.Resources.Limits = tt.originalLimits
28942890

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//go:build linux
2+
// +build linux
3+
4+
/*
5+
Copyright 2025 The Kubernetes Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
*/
19+
20+
package kuberuntime
21+
22+
import (
23+
v1 "k8s.io/api/core/v1"
24+
utilfeature "k8s.io/apiserver/pkg/util/feature"
25+
"k8s.io/kubernetes/pkg/features"
26+
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
27+
)
28+
29+
func IsInPlacePodVerticalScalingAllowed(pod *v1.Pod) (allowed bool, msg string) {
30+
if !utilfeature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling) {
31+
return false, "InPlacePodVerticalScaling is disabled"
32+
}
33+
if kubetypes.IsStaticPod(pod) {
34+
return false, "In-place resize of static-pods is not supported"
35+
}
36+
return true, ""
37+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//go:build !linux && !windows
2+
// +build !linux,!windows
3+
4+
/*
5+
Copyright 2025 The Kubernetes Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
*/
19+
20+
package kuberuntime
21+
22+
import v1 "k8s.io/api/core/v1"
23+
24+
func IsInPlacePodVerticalScalingAllowed(_ *v1.Pod) (allowed bool, msg string) {
25+
return false, "In-place pod resize is not supported on this node"
26+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//go:build windows
2+
// +build windows
3+
4+
/*
5+
Copyright 2025 The Kubernetes Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
*/
19+
20+
package kuberuntime
21+
22+
import v1 "k8s.io/api/core/v1"
23+
24+
func IsInPlacePodVerticalScalingAllowed(_ *v1.Pod) (allowed bool, msg string) {
25+
return false, "In-place pod resize is not supported on Windows"
26+
}

pkg/kubelet/kuberuntime/kuberuntime_container.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1164,7 +1164,7 @@ func (m *kubeGenericRuntimeManager) computeInitContainerActions(pod *v1.Pod, pod
11641164
}
11651165
}
11661166

1167-
if IsInPlacePodVerticalScalingAllowed(pod) && !m.computePodResizeAction(pod, i, true, status, changes) {
1167+
if !m.computePodResizeAction(pod, i, true, status, changes) {
11681168
// computePodResizeAction updates 'changes' if resize policy requires restarting this container
11691169
break
11701170
}

pkg/kubelet/kuberuntime/kuberuntime_manager.go

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -550,20 +550,14 @@ func containerSucceeded(c *v1.Container, podStatus *kubecontainer.PodStatus) boo
550550
return cStatus.State == kubecontainer.ContainerStateExited && cStatus.ExitCode == 0
551551
}
552552

553-
func IsInPlacePodVerticalScalingAllowed(pod *v1.Pod) bool {
554-
if !utilfeature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling) {
555-
return false
556-
}
557-
if types.IsStaticPod(pod) {
558-
return false
559-
}
560-
return true
561-
}
562-
563553
// computePodResizeAction determines the actions required (if any) to resize the given container.
564554
// Returns whether to keep (true) or restart (false) the container.
565555
// TODO(vibansal): Make this function to be agnostic to whether it is dealing with a restartable init container or not (i.e. remove the argument `isRestartableInitContainer`).
566556
func (m *kubeGenericRuntimeManager) computePodResizeAction(pod *v1.Pod, containerIdx int, isRestartableInitContainer bool, kubeContainerStatus *kubecontainer.Status, changes *podActions) (keepContainer bool) {
557+
if resizable, _ := IsInPlacePodVerticalScalingAllowed(pod); !resizable {
558+
return true
559+
}
560+
567561
var container v1.Container
568562
if isRestartableInitContainer {
569563
container = pod.Spec.InitContainers[containerIdx]
@@ -997,7 +991,7 @@ func (m *kubeGenericRuntimeManager) computePodActions(ctx context.Context, pod *
997991
}
998992
}
999993

1000-
if IsInPlacePodVerticalScalingAllowed(pod) {
994+
if resizable, _ := IsInPlacePodVerticalScalingAllowed(pod); resizable {
1001995
changes.ContainersToUpdate = make(map[v1.ResourceName][]containerToUpdateInfo)
1002996
}
1003997

@@ -1092,7 +1086,7 @@ func (m *kubeGenericRuntimeManager) computePodActions(ctx context.Context, pod *
10921086
// If the container failed the startup probe, we should kill it.
10931087
message = fmt.Sprintf("Container %s failed startup probe", container.Name)
10941088
reason = reasonStartupProbe
1095-
} else if IsInPlacePodVerticalScalingAllowed(pod) && !m.computePodResizeAction(pod, idx, false, containerStatus, &changes) {
1089+
} else if !m.computePodResizeAction(pod, idx, false, containerStatus, &changes) {
10961090
// computePodResizeAction updates 'changes' if resize policy requires restarting this container
10971091
continue
10981092
} else {
@@ -1413,7 +1407,7 @@ func (m *kubeGenericRuntimeManager) SyncPod(ctx context.Context, pod *v1.Pod, po
14131407
}
14141408

14151409
// Step 7: For containers in podContainerChanges.ContainersToUpdate[CPU,Memory] list, invoke UpdateContainerResources
1416-
if IsInPlacePodVerticalScalingAllowed(pod) {
1410+
if resizable, _ := IsInPlacePodVerticalScalingAllowed(pod); resizable {
14171411
if len(podContainerChanges.ContainersToUpdate) > 0 || podContainerChanges.UpdatePodResources {
14181412
m.doPodResizeAction(pod, podContainerChanges, &result)
14191413
}

0 commit comments

Comments
 (0)