diff --git a/pkg/kubelet/kubelet_pods.go b/pkg/kubelet/kubelet_pods.go index c4861648f44..5dcc3c2085d 100644 --- a/pkg/kubelet/kubelet_pods.go +++ b/pkg/kubelet/kubelet_pods.go @@ -1791,19 +1791,31 @@ func allocatedResourcesMatchStatus(allocatedPod *v1.Pod, podStatus *kubecontaine // Only compare resizeable resources, and only compare resources that are explicitly configured. if hasCPUReq { - // If both allocated & status CPU requests are at or below MinShares then they are considered equal. - if !cpuReq.Equal(*cs.Resources.CPURequest) && + if cs.Resources.CPURequest == nil { + if !cpuReq.IsZero() { + return false + } + } else if !cpuReq.Equal(*cs.Resources.CPURequest) && (cpuReq.MilliValue() > cm.MinShares || cs.Resources.CPURequest.MilliValue() > cm.MinShares) { + // If both allocated & status CPU requests are at or below MinShares then they are considered equal. return false } } if hasCPULim { - if !cpuLim.Equal(*cs.Resources.CPULimit) { + if cs.Resources.CPULimit == nil { + if !cpuLim.IsZero() { + return false + } + } else if !cpuLim.Equal(*cs.Resources.CPULimit) { return false } } if hasMemLim { - if !memLim.Equal(*cs.Resources.MemoryLimit) { + if cs.Resources.MemoryLimit == nil { + if !memLim.IsZero() { + return false + } + } else if !memLim.Equal(*cs.Resources.MemoryLimit) { return false } } diff --git a/pkg/kubelet/kubelet_pods_test.go b/pkg/kubelet/kubelet_pods_test.go index c7dd26647e3..22e1a6ea61a 100644 --- a/pkg/kubelet/kubelet_pods_test.go +++ b/pkg/kubelet/kubelet_pods_test.go @@ -6797,6 +6797,38 @@ func TestAllocatedResourcesMatchStatus(t *testing.T) { CPURequest: resource.NewMilliQuantity(2, resource.DecimalSI), }, expectMatch: true, + }, { + name: "nil status resources: cpu request mismatch", + allocatedResources: v1.ResourceRequirements{ + Requests: v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("100m"), + }, + }, + statusResources: &kubecontainer.ContainerResources{}, + expectMatch: false, + }, { + name: "nil status resources: cpu limit mismatch", + allocatedResources: v1.ResourceRequirements{ + Requests: v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("100m"), + }, + Limits: v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("100m"), + }, + }, + statusResources: &kubecontainer.ContainerResources{ + CPURequest: resource.NewMilliQuantity(2, resource.DecimalSI), + }, + expectMatch: false, + }, { + name: "nil status resources: memory limit mismatch", + allocatedResources: v1.ResourceRequirements{ + Limits: v1.ResourceList{ + v1.ResourceMemory: resource.MustParse("100M"), + }, + }, + statusResources: &kubecontainer.ContainerResources{}, + expectMatch: false, }} for _, test := range tests { diff --git a/pkg/kubelet/kuberuntime/kuberuntime_manager.go b/pkg/kubelet/kuberuntime/kuberuntime_manager.go index d9925774812..55b1fb04166 100644 --- a/pkg/kubelet/kuberuntime/kuberuntime_manager.go +++ b/pkg/kubelet/kuberuntime/kuberuntime_manager.go @@ -584,8 +584,10 @@ func (m *kubeGenericRuntimeManager) computePodResizeAction(pod *v1.Pod, containe cpuRequest: container.Resources.Requests.Cpu().MilliValue(), } - // Default current values to the desired values so that a resize isn't triggered for missing values. - currentResources := desiredResources + currentResources := containerResources{ + // memoryRequest isn't set by the runtime, so default it to the desired. + memoryRequest: desiredResources.memoryRequest, + } if kubeContainerStatus.Resources.MemoryLimit != nil { currentResources.memoryLimit = kubeContainerStatus.Resources.MemoryLimit.Value() } @@ -839,16 +841,21 @@ func (m *kubeGenericRuntimeManager) updatePodContainerResources(pod *v1.Pod, res } switch resourceName { case v1.ResourceMemory: - return status.Resources.MemoryLimit.Equal(*container.Resources.Limits.Memory()) + actualLimit := nonNilQuantity(status.Resources.MemoryLimit) + return actualLimit.Equal(*container.Resources.Limits.Memory()) case v1.ResourceCPU: - if !status.Resources.CPULimit.Equal(*container.Resources.Limits.Cpu()) { + actualLimit := nonNilQuantity(status.Resources.CPULimit) + actualRequest := nonNilQuantity(status.Resources.CPURequest) + desiredLimit := container.Resources.Limits.Cpu() + desiredRequest := container.Resources.Requests.Cpu() + if !actualLimit.Equal(*desiredLimit) { return false // limits don't match - } else if status.Resources.CPURequest.Equal(*container.Resources.Requests.Cpu()) { + } else if actualRequest.Equal(*desiredRequest) { return true // requests & limits both match } // Consider requests equal if both are at or below MinShares. - return status.Resources.CPURequest.MilliValue() <= cm.MinShares && - container.Resources.Requests.Cpu().MilliValue() <= cm.MinShares + return actualRequest.MilliValue() <= cm.MinShares && + desiredRequest.MilliValue() <= cm.MinShares default: return true // Shouldn't happen. } @@ -870,6 +877,15 @@ func (m *kubeGenericRuntimeManager) updatePodContainerResources(pod *v1.Pod, res return nil } +// nonNilQuantity returns a non-nil quantity. If the input is non-nil, it is returned. Otherwise a +// pointer to the zero value is returned. +func nonNilQuantity(q *resource.Quantity) *resource.Quantity { + if q != nil { + return q + } + return &resource.Quantity{} +} + // computePodActions checks whether the pod spec has changed and returns the changes if true. func (m *kubeGenericRuntimeManager) computePodActions(ctx context.Context, pod *v1.Pod, podStatus *kubecontainer.PodStatus) podActions { klog.V(5).InfoS("Syncing Pod", "pod", klog.KObj(pod))