Merge pull request #129216 from tallclair/ippr-supported

[FG:InPlacePodVerticalScaling] Never attempt a resize of windows pods and always use allocated resources for unsupported resize pods
This commit is contained in:
Kubernetes Prow Robot 2025-03-04 16:41:44 -08:00 committed by GitHub
commit f816be06ed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 108 additions and 31 deletions

View File

@ -1883,7 +1883,7 @@ func (kl *Kubelet) SyncPod(ctx context.Context, updateType kubetypes.SyncPodType
// handlePodResourcesResize updates the pod to use the allocated resources. This should come
// before the main business logic of SyncPod, so that a consistent view of the pod is used
// across the sync loop.
if kuberuntime.IsInPlacePodVerticalScalingAllowed(pod) {
if utilfeature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling) {
// Handle pod resize here instead of doing it in HandlePodUpdates because
// this conveniently retries any Deferred resize requests
// TODO(vinaykul,InPlacePodVerticalScaling): Investigate doing this in HandlePodUpdates + periodic SyncLoop scan
@ -2816,10 +2816,6 @@ func (kl *Kubelet) HandlePodSyncs(pods []*v1.Pod) {
// pod should hold the desired (pre-allocated) spec.
// Returns true if the resize can proceed.
func (kl *Kubelet) canResizePod(pod *v1.Pod) (bool, v1.PodResizeStatus, string) {
if goos == "windows" {
return false, v1.PodResizeStatusInfeasible, "Resizing Windows pods is not supported"
}
if v1qos.GetPodQOS(pod) == v1.PodQOSGuaranteed && !utilfeature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScalingExclusiveCPUs) {
if utilfeature.DefaultFeatureGate.Enabled(features.CPUManager) {
if kl.containerManager.GetNodeConfig().CPUManagerPolicy == "static" {
@ -2877,6 +2873,7 @@ func (kl *Kubelet) canResizePod(pod *v1.Pod) (bool, v1.PodResizeStatus, string)
// the allocation decision and pod status.
func (kl *Kubelet) handlePodResourcesResize(pod *v1.Pod, podStatus *kubecontainer.PodStatus) (*v1.Pod, error) {
allocatedPod, updated := kl.allocationManager.UpdatePodFromAllocation(pod)
if !updated {
// Desired resources == allocated resources. Check whether a resize is in progress.
resizeInProgress := !allocatedResourcesMatchStatus(allocatedPod, podStatus)
@ -2889,6 +2886,11 @@ func (kl *Kubelet) handlePodResourcesResize(pod *v1.Pod, podStatus *kubecontaine
}
// Pod allocation does not need to be updated.
return allocatedPod, nil
} else if resizable, msg := kuberuntime.IsInPlacePodVerticalScalingAllowed(pod); !resizable {
// If there is a pending resize but the resize is not allowed, always use the allocated resources.
kl.recorder.Eventf(pod, v1.EventTypeWarning, events.ResizeInfeasible, msg)
kl.statusManager.SetPodResizeStatus(pod.UID, v1.PodResizeStatusInfeasible)
return allocatedPod, nil
}
kl.podResizeMutex.Lock()

View File

@ -1748,10 +1748,6 @@ func getPhase(pod *v1.Pod, info []v1.ContainerStatus, podIsTerminal bool) v1.Pod
}
func (kl *Kubelet) determinePodResizeStatus(allocatedPod *v1.Pod, podStatus *kubecontainer.PodStatus, podIsTerminal bool) v1.PodResizeStatus {
if kubetypes.IsStaticPod(allocatedPod) {
return ""
}
// If pod is terminal, clear the resize status.
if podIsTerminal {
kl.statusManager.SetPodResizeStatus(allocatedPod.UID, "")

View File

@ -2711,7 +2711,7 @@ func TestHandlePodResourcesResize(t *testing.T) {
expectedAllocatedLims v1.ResourceList
expectedResize v1.PodResizeStatus
expectBackoffReset bool
goos string
annotations map[string]string
}{
{
name: "Request CPU and memory decrease - expect InProgress",
@ -2781,12 +2781,12 @@ func TestHandlePodResourcesResize(t *testing.T) {
expectedResize: "",
},
{
name: "windows node, expect Infeasible",
name: "static pod, expect Infeasible",
originalRequests: v1.ResourceList{v1.ResourceCPU: cpu1000m, v1.ResourceMemory: mem1000M},
newRequests: v1.ResourceList{v1.ResourceCPU: cpu500m, v1.ResourceMemory: mem500M},
expectedAllocatedReqs: v1.ResourceList{v1.ResourceCPU: cpu1000m, v1.ResourceMemory: mem1000M},
expectedResize: v1.PodResizeStatusInfeasible,
goos: "windows",
annotations: map[string]string{kubetypes.ConfigSourceAnnotationKey: kubetypes.FileSource},
},
{
name: "Increase CPU from min shares",
@ -2873,11 +2873,6 @@ func TestHandlePodResourcesResize(t *testing.T) {
for _, tt := range tests {
for _, isSidecarContainer := range []bool{false, true} {
t.Run(tt.name, func(t *testing.T) {
oldGOOS := goos
defer func() { goos = oldGOOS }()
if tt.goos != "" {
goos = tt.goos
}
kubelet.statusManager = status.NewFakeManager()
var originalPod *v1.Pod
@ -2889,6 +2884,7 @@ func TestHandlePodResourcesResize(t *testing.T) {
originalPod = testPod1.DeepCopy()
originalCtr = &originalPod.Spec.Containers[0]
}
originalPod.Annotations = tt.annotations
originalCtr.Resources.Requests = tt.originalRequests
originalCtr.Resources.Limits = tt.originalLimits

View File

@ -0,0 +1,37 @@
//go:build linux
// +build linux
/*
Copyright 2025 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kuberuntime
import (
v1 "k8s.io/api/core/v1"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/kubernetes/pkg/features"
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
)
func IsInPlacePodVerticalScalingAllowed(pod *v1.Pod) (allowed bool, msg string) {
if !utilfeature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling) {
return false, "InPlacePodVerticalScaling is disabled"
}
if kubetypes.IsStaticPod(pod) {
return false, "In-place resize of static-pods is not supported"
}
return true, ""
}

View File

@ -0,0 +1,26 @@
//go:build !linux && !windows
// +build !linux,!windows
/*
Copyright 2025 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kuberuntime
import v1 "k8s.io/api/core/v1"
func IsInPlacePodVerticalScalingAllowed(_ *v1.Pod) (allowed bool, msg string) {
return false, "In-place pod resize is not supported on this node"
}

View File

@ -0,0 +1,26 @@
//go:build windows
// +build windows
/*
Copyright 2025 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kuberuntime
import v1 "k8s.io/api/core/v1"
func IsInPlacePodVerticalScalingAllowed(_ *v1.Pod) (allowed bool, msg string) {
return false, "In-place pod resize is not supported on Windows"
}

View File

@ -1164,7 +1164,7 @@ func (m *kubeGenericRuntimeManager) computeInitContainerActions(pod *v1.Pod, pod
}
}
if IsInPlacePodVerticalScalingAllowed(pod) && !m.computePodResizeAction(pod, i, true, status, changes) {
if !m.computePodResizeAction(pod, i, true, status, changes) {
// computePodResizeAction updates 'changes' if resize policy requires restarting this container
break
}

View File

@ -550,20 +550,14 @@ func containerSucceeded(c *v1.Container, podStatus *kubecontainer.PodStatus) boo
return cStatus.State == kubecontainer.ContainerStateExited && cStatus.ExitCode == 0
}
func IsInPlacePodVerticalScalingAllowed(pod *v1.Pod) bool {
if !utilfeature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling) {
return false
}
if types.IsStaticPod(pod) {
return false
}
return true
}
// computePodResizeAction determines the actions required (if any) to resize the given container.
// Returns whether to keep (true) or restart (false) the container.
// 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`).
func (m *kubeGenericRuntimeManager) computePodResizeAction(pod *v1.Pod, containerIdx int, isRestartableInitContainer bool, kubeContainerStatus *kubecontainer.Status, changes *podActions) (keepContainer bool) {
if resizable, _ := IsInPlacePodVerticalScalingAllowed(pod); !resizable {
return true
}
var container v1.Container
if isRestartableInitContainer {
container = pod.Spec.InitContainers[containerIdx]
@ -997,7 +991,7 @@ func (m *kubeGenericRuntimeManager) computePodActions(ctx context.Context, pod *
}
}
if IsInPlacePodVerticalScalingAllowed(pod) {
if resizable, _ := IsInPlacePodVerticalScalingAllowed(pod); resizable {
changes.ContainersToUpdate = make(map[v1.ResourceName][]containerToUpdateInfo)
}
@ -1092,7 +1086,7 @@ func (m *kubeGenericRuntimeManager) computePodActions(ctx context.Context, pod *
// If the container failed the startup probe, we should kill it.
message = fmt.Sprintf("Container %s failed startup probe", container.Name)
reason = reasonStartupProbe
} else if IsInPlacePodVerticalScalingAllowed(pod) && !m.computePodResizeAction(pod, idx, false, containerStatus, &changes) {
} else if !m.computePodResizeAction(pod, idx, false, containerStatus, &changes) {
// computePodResizeAction updates 'changes' if resize policy requires restarting this container
continue
} else {
@ -1413,7 +1407,7 @@ func (m *kubeGenericRuntimeManager) SyncPod(ctx context.Context, pod *v1.Pod, po
}
// Step 7: For containers in podContainerChanges.ContainersToUpdate[CPU,Memory] list, invoke UpdateContainerResources
if IsInPlacePodVerticalScalingAllowed(pod) {
if resizable, _ := IsInPlacePodVerticalScalingAllowed(pod); resizable {
if len(podContainerChanges.ContainersToUpdate) > 0 || podContainerChanges.UpdatePodResources {
m.doPodResizeAction(pod, podContainerChanges, &result)
}