Skip to content

Commit d4444dd

Browse files
committed
Use actuated resources to determine resize status
1 parent 660bd6b commit d4444dd

File tree

8 files changed

+409
-567
lines changed

8 files changed

+409
-567
lines changed

pkg/kubelet/kubelet.go

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
740740
kubeDeps.ContainerManager,
741741
klet.containerLogManager,
742742
klet.runtimeClassManager,
743+
klet.allocationManager,
743744
seccompDefault,
744745
kubeCfg.MemorySwap.SwapBehavior,
745746
kubeDeps.ContainerManager.GetNodeAllocatableAbsolute,
@@ -2886,8 +2887,7 @@ func (kl *Kubelet) handlePodResourcesResize(pod *v1.Pod, podStatus *kubecontaine
28862887

28872888
if !updated {
28882889
// Desired resources == allocated resources. Check whether a resize is in progress.
2889-
resizeInProgress := !allocatedResourcesMatchStatus(allocatedPod, podStatus)
2890-
if resizeInProgress {
2890+
if kl.isPodResizeInProgress(allocatedPod, podStatus) {
28912891
// If a resize is in progress, make sure the cache has the correct state in case the Kubelet restarted.
28922892
kl.statusManager.SetPodResizeStatus(pod.UID, v1.PodResizeStatusInProgress)
28932893
} else {
@@ -2928,11 +2928,11 @@ func (kl *Kubelet) handlePodResourcesResize(pod *v1.Pod, podStatus *kubecontaine
29282928
}
29292929
allocatedPod = pod
29302930

2931-
// Special case when the updated allocation matches the actual resources. This can occur
2931+
// Special case when the updated allocation matches the actuated resources. This can occur
29322932
// when reverting a resize that hasn't been actuated, or when making an equivalent change
29332933
// (such as CPU requests below MinShares). This is an optimization to clear the resize
29342934
// status immediately, rather than waiting for the next SyncPod iteration.
2935-
if allocatedResourcesMatchStatus(allocatedPod, podStatus) {
2935+
if !kl.isPodResizeInProgress(allocatedPod, podStatus) {
29362936
// In this case, consider the resize complete.
29372937
kl.statusManager.SetPodResizeStatus(pod.UID, "")
29382938
return allocatedPod, nil
@@ -2952,6 +2952,46 @@ func (kl *Kubelet) handlePodResourcesResize(pod *v1.Pod, podStatus *kubecontaine
29522952
return allocatedPod, nil
29532953
}
29542954

2955+
// isPodResizingInProgress checks whether the actuated resizable resources differ from the allocated resources
2956+
// for any running containers. Specifically, the following differences are ignored:
2957+
// - Non-resizable containers: non-restartable init containers, ephemeral containers
2958+
// - Non-resizable resources: only CPU & memory are resizable
2959+
// - Non-actuated resources: memory requests are not actuated
2960+
// - Non-running containers: they will be sized correctly when (re)started
2961+
func (kl *Kubelet) isPodResizeInProgress(allocatedPod *v1.Pod, podStatus *kubecontainer.PodStatus) bool {
2962+
return !podutil.VisitContainers(&allocatedPod.Spec, podutil.InitContainers|podutil.Containers,
2963+
func(allocatedContainer *v1.Container, containerType podutil.ContainerType) (shouldContinue bool) {
2964+
if !isResizableContainer(allocatedContainer, containerType) {
2965+
return true
2966+
}
2967+
2968+
containerStatus := podStatus.FindContainerStatusByName(allocatedContainer.Name)
2969+
if containerStatus == nil || containerStatus.State != kubecontainer.ContainerStateRunning {
2970+
// If the container isn't running, it doesn't need to be resized.
2971+
return true
2972+
}
2973+
2974+
actuatedResources, _ := kl.allocationManager.GetActuatedResources(allocatedPod.UID, allocatedContainer.Name)
2975+
allocatedResources := allocatedContainer.Resources
2976+
2977+
// Memory requests are excluded since they don't need to be actuated.
2978+
return allocatedResources.Requests[v1.ResourceCPU].Equal(actuatedResources.Requests[v1.ResourceCPU]) &&
2979+
allocatedResources.Limits[v1.ResourceCPU].Equal(actuatedResources.Limits[v1.ResourceCPU]) &&
2980+
allocatedResources.Limits[v1.ResourceMemory].Equal(actuatedResources.Limits[v1.ResourceMemory])
2981+
})
2982+
}
2983+
2984+
func isResizableContainer(container *v1.Container, containerType podutil.ContainerType) bool {
2985+
switch containerType {
2986+
case podutil.InitContainers:
2987+
return podutil.IsRestartableInitContainer(container)
2988+
case podutil.Containers:
2989+
return true
2990+
default:
2991+
return false
2992+
}
2993+
}
2994+
29552995
// LatestLoopEntryTime returns the last time in the sync loop monitor.
29562996
func (kl *Kubelet) LatestLoopEntryTime() time.Time {
29572997
val := kl.syncLoopMonitor.Load()

pkg/kubelet/kubelet_pods.go

Lines changed: 0 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ import (
6060
"k8s.io/kubernetes/pkg/kubelet/metrics"
6161
"k8s.io/kubernetes/pkg/kubelet/status"
6262
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
63-
"k8s.io/kubernetes/pkg/kubelet/util/format"
6463
utilfs "k8s.io/kubernetes/pkg/util/filesystem"
6564
utilpod "k8s.io/kubernetes/pkg/util/pod"
6665
volumeutil "k8s.io/kubernetes/pkg/volume/util"
@@ -1746,86 +1745,6 @@ func (kl *Kubelet) determinePodResizeStatus(allocatedPod *v1.Pod, podStatus *kub
17461745
return resizeStatus
17471746
}
17481747

1749-
// allocatedResourcesMatchStatus tests whether the resizeable resources in the pod spec match the
1750-
// resources reported in the status.
1751-
func allocatedResourcesMatchStatus(allocatedPod *v1.Pod, podStatus *kubecontainer.PodStatus) bool {
1752-
for _, c := range allocatedPod.Spec.Containers {
1753-
if !allocatedContainerResourcesMatchStatus(allocatedPod, &c, podStatus) {
1754-
return false
1755-
}
1756-
}
1757-
if utilfeature.DefaultFeatureGate.Enabled(features.SidecarContainers) {
1758-
for _, c := range allocatedPod.Spec.InitContainers {
1759-
if podutil.IsRestartableInitContainer(&c) && !allocatedContainerResourcesMatchStatus(allocatedPod, &c, podStatus) {
1760-
return false
1761-
}
1762-
}
1763-
}
1764-
return true
1765-
}
1766-
1767-
// allocatedContainerResourcesMatchStatus returns true if the container resources matches with the container statuses resources.
1768-
func allocatedContainerResourcesMatchStatus(allocatedPod *v1.Pod, c *v1.Container, podStatus *kubecontainer.PodStatus) bool {
1769-
if cs := podStatus.FindContainerStatusByName(c.Name); cs != nil {
1770-
if cs.State != kubecontainer.ContainerStateRunning {
1771-
// If the container isn't running, it isn't resizing.
1772-
return true
1773-
}
1774-
1775-
cpuReq, hasCPUReq := c.Resources.Requests[v1.ResourceCPU]
1776-
cpuLim, hasCPULim := c.Resources.Limits[v1.ResourceCPU]
1777-
memLim, hasMemLim := c.Resources.Limits[v1.ResourceMemory]
1778-
1779-
if cs.Resources == nil {
1780-
if hasCPUReq || hasCPULim || hasMemLim {
1781-
// Container status is missing Resources information, but the container does
1782-
// have resizable resources configured.
1783-
klog.ErrorS(nil, "Missing runtime resources information for resizing container",
1784-
"pod", format.Pod(allocatedPod), "container", c.Name)
1785-
return false // We don't want to clear resize status with insufficient information.
1786-
} else {
1787-
// No resizable resources configured; this might be ok.
1788-
return true
1789-
}
1790-
}
1791-
1792-
// Only compare resizeable resources, and only compare resources that are explicitly configured.
1793-
if hasCPUReq {
1794-
if cs.Resources.CPURequest == nil {
1795-
if !cpuReq.IsZero() {
1796-
return false
1797-
}
1798-
} else if !cpuReq.Equal(*cs.Resources.CPURequest) &&
1799-
(cpuReq.MilliValue() > cm.MinShares || cs.Resources.CPURequest.MilliValue() > cm.MinShares) {
1800-
// If both allocated & status CPU requests are at or below MinShares then they are considered equal.
1801-
return false
1802-
}
1803-
}
1804-
if hasCPULim {
1805-
if cs.Resources.CPULimit == nil {
1806-
if !cpuLim.IsZero() {
1807-
return false
1808-
}
1809-
} else if !cpuLim.Equal(*cs.Resources.CPULimit) &&
1810-
(cpuLim.MilliValue() > cm.MinMilliCPULimit || cs.Resources.CPULimit.MilliValue() > cm.MinMilliCPULimit) {
1811-
// If both allocated & status CPU limits are at or below the minimum limit, then they are considered equal.
1812-
return false
1813-
}
1814-
}
1815-
if hasMemLim {
1816-
if cs.Resources.MemoryLimit == nil {
1817-
if !memLim.IsZero() {
1818-
return false
1819-
}
1820-
} else if !memLim.Equal(*cs.Resources.MemoryLimit) {
1821-
return false
1822-
}
1823-
}
1824-
}
1825-
1826-
return true
1827-
}
1828-
18291748
// generateAPIPodStatus creates the final API pod status for a pod, given the
18301749
// internal pod status. This method should only be called from within sync*Pod methods.
18311750
func (kl *Kubelet) generateAPIPodStatus(pod *v1.Pod, podStatus *kubecontainer.PodStatus, podIsTerminal bool) v1.PodStatus {

0 commit comments

Comments
 (0)