Skip to content

Commit 5d95cfd

Browse files
authored
Merge pull request #8062 from laoj2/fix-spec-client
Read container resources from containerStatus in the spec client
2 parents 130af54 + 3eba409 commit 5d95cfd

File tree

6 files changed

+319
-34
lines changed

6 files changed

+319
-34
lines changed

vertical-pod-autoscaler/pkg/recommender/input/spec/spec_client.go

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
v1lister "k8s.io/client-go/listers/core/v1"
2323

2424
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/recommender/model"
25+
resourcehelpers "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/resources"
2526
)
2627

2728
// BasicPodSpec contains basic information defining a pod and its containers.
@@ -79,16 +80,13 @@ func (client *specClient) GetPodSpecs() ([]*BasicPodSpec, error) {
7980
}
8081
return podSpecs, nil
8182
}
83+
8284
func newBasicPodSpec(pod *v1.Pod) *BasicPodSpec {
83-
podId := model.PodID{
84-
PodName: pod.Name,
85-
Namespace: pod.Namespace,
86-
}
87-
containerSpecs := newContainerSpecs(podId, pod.Spec.Containers)
88-
initContainerSpecs := newContainerSpecs(podId, pod.Spec.InitContainers)
85+
containerSpecs := newContainerSpecs(pod, pod.Spec.Containers, false /* isInitContainer */)
86+
initContainerSpecs := newContainerSpecs(pod, pod.Spec.InitContainers, true /* isInitContainer */)
8987

9088
basicPodSpec := &BasicPodSpec{
91-
ID: podId,
89+
ID: podID(pod),
9290
PodLabels: pod.Labels,
9391
Containers: containerSpecs,
9492
InitContainers: initContainerSpecs,
@@ -97,34 +95,38 @@ func newBasicPodSpec(pod *v1.Pod) *BasicPodSpec {
9795
return basicPodSpec
9896
}
9997

100-
func newContainerSpecs(podID model.PodID, containers []v1.Container) []BasicContainerSpec {
98+
func newContainerSpecs(pod *v1.Pod, containers []v1.Container, isInitContainer bool) []BasicContainerSpec {
10199
var containerSpecs []BasicContainerSpec
102-
103100
for _, container := range containers {
104-
containerSpec := newContainerSpec(podID, container)
101+
containerSpec := newContainerSpec(pod, container, isInitContainer)
105102
containerSpecs = append(containerSpecs, containerSpec)
106103
}
107-
108104
return containerSpecs
109105
}
110106

111-
func newContainerSpec(podID model.PodID, container v1.Container) BasicContainerSpec {
107+
func newContainerSpec(pod *v1.Pod, container v1.Container, isInitContainer bool) BasicContainerSpec {
112108
containerSpec := BasicContainerSpec{
113109
ID: model.ContainerID{
114-
PodID: podID,
110+
PodID: podID(pod),
115111
ContainerName: container.Name,
116112
},
117113
Image: container.Image,
118-
Request: calculateRequestedResources(container),
114+
Request: calculateRequestedResources(pod, container, isInitContainer),
119115
}
120116
return containerSpec
121117
}
122118

123-
func calculateRequestedResources(container v1.Container) model.Resources {
124-
cpuQuantity := container.Resources.Requests[v1.ResourceCPU]
119+
func calculateRequestedResources(pod *v1.Pod, container v1.Container, isInitContainer bool) model.Resources {
120+
requestsAndLimitsFn := resourcehelpers.ContainerRequestsAndLimits
121+
if isInitContainer {
122+
requestsAndLimitsFn = resourcehelpers.InitContainerRequestsAndLimits
123+
}
124+
requests, _ := requestsAndLimitsFn(container.Name, pod)
125+
126+
cpuQuantity := requests[v1.ResourceCPU]
125127
cpuMillicores := cpuQuantity.MilliValue()
126128

127-
memoryQuantity := container.Resources.Requests[v1.ResourceMemory]
129+
memoryQuantity := requests[v1.ResourceMemory]
128130
memoryBytes := memoryQuantity.Value()
129131

130132
return model.Resources{
@@ -133,3 +135,10 @@ func calculateRequestedResources(container v1.Container) model.Resources {
133135
}
134136

135137
}
138+
139+
func podID(pod *v1.Pod) model.PodID {
140+
return model.PodID{
141+
PodName: pod.Name,
142+
Namespace: pod.Namespace,
143+
}
144+
}

vertical-pod-autoscaler/pkg/recommender/input/spec/spec_client_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,6 @@ func TestGetPodSpecsReturnsSpecs(t *testing.T) {
4747
assert.NoError(t, err)
4848
assert.Equal(t, len(tc.podSpecs), len(podSpecs), "SpecClient returned different number of results then expected")
4949
for _, podSpec := range podSpecs {
50-
assert.Contains(t, tc.podSpecs, podSpec, "One of returned BasicPodSpcec is different than expected")
50+
assert.Contains(t, tc.podSpecs, podSpec, "One of returned BasicPodSpec is different than expected")
5151
}
5252
}

vertical-pod-autoscaler/pkg/recommender/input/spec/spec_client_test_util.go

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,19 @@ metadata:
6868
name: Pod2
6969
labels:
7070
Pod2LabelKey: Pod2LabelValue
71+
status:
72+
containerStatuses:
73+
- name: Name23
74+
resources:
75+
requests:
76+
memory: "250Mi"
77+
cpu: "30m"
78+
initContainerStatuses:
79+
- name: Name22-init
80+
resources:
81+
requests:
82+
memory: "350Mi"
83+
cpu: "40m"
7184
spec:
7285
containers:
7386
- name: Name21
@@ -82,13 +95,29 @@ spec:
8295
requests:
8396
memory: "4096Mi"
8497
cpu: "4000m"
98+
- name: Name23
99+
image: Name23Image
100+
resources:
101+
# Requests below will be ignored because
102+
# requests are also defined in containerStatus.
103+
requests:
104+
memory: "1Mi"
105+
cpu: "1m"
85106
initContainers:
86107
- name: Name21-init
87108
image: Name21-initImage
88109
resources:
89110
requests:
90111
memory: "128Mi"
91112
cpu: "40m"
113+
- name: Name22-init
114+
image: Name22-initImage
115+
resources:
116+
requests:
117+
# Requests below will be ignored because
118+
# requests are also defined in initContainerStatus.
119+
memory: "1Mi"
120+
cpu: "1m"
92121
`
93122

94123
type podListerMock struct {
@@ -122,11 +151,13 @@ func newSpecClientTestCase() *specClientTestCase {
122151
containerSpec12 := newTestContainerSpec(podID1, "Name12", 1000, 1024*1024*1024)
123152
containerSpec21 := newTestContainerSpec(podID2, "Name21", 2000, 2048*1024*1024)
124153
containerSpec22 := newTestContainerSpec(podID2, "Name22", 4000, 4096*1024*1024)
154+
containerSpec23 := newTestContainerSpec(podID2, "Name23", 30, 250*1024*1024)
125155

126156
initContainerSpec21 := newTestContainerSpec(podID2, "Name21-init", 40, 128*1024*1024)
157+
initContainerSpec22 := newTestContainerSpec(podID2, "Name22-init", 40, 350*1024*1024)
127158

128159
podSpec1 := newTestPodSpec(podID1, []BasicContainerSpec{containerSpec11, containerSpec12}, nil)
129-
podSpec2 := newTestPodSpec(podID2, []BasicContainerSpec{containerSpec21, containerSpec22}, []BasicContainerSpec{initContainerSpec21})
160+
podSpec2 := newTestPodSpec(podID2, []BasicContainerSpec{containerSpec21, containerSpec22, containerSpec23}, []BasicContainerSpec{initContainerSpec21, initContainerSpec22})
130161

131162
return &specClientTestCase{
132163
podSpecs: []*BasicPodSpec{podSpec1, podSpec2},

vertical-pod-autoscaler/pkg/utils/resources/resourcehelpers.go

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import (
3030
//
3131
// [1] https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/1287-in-place-update-pod-resources
3232
func ContainerRequestsAndLimits(containerName string, pod *v1.Pod) (v1.ResourceList, v1.ResourceList) {
33-
cs := containerStatusForContainer(containerName, pod)
33+
cs := containerStatusFor(containerName, pod)
3434
if cs != nil && cs.Resources != nil {
3535
return cs.Resources.Requests.DeepCopy(), cs.Resources.Limits.DeepCopy()
3636
}
@@ -44,6 +44,29 @@ func ContainerRequestsAndLimits(containerName string, pod *v1.Pod) (v1.ResourceL
4444
return nil, nil
4545
}
4646

47+
// InitContainerRequestsAndLimits returns a copy of the actual resource requests
48+
// and limits of a given initContainer:
49+
//
50+
// - If in-place pod updates feature [1] is enabled, the actual resource requests
51+
// are stored in the initContainer status field.
52+
// - Otherwise, fallback to the resource requests defined in the pod spec.
53+
//
54+
// [1] https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/1287-in-place-update-pod-resources
55+
func InitContainerRequestsAndLimits(initContainerName string, pod *v1.Pod) (v1.ResourceList, v1.ResourceList) {
56+
cs := initContainerStatusFor(initContainerName, pod)
57+
if cs != nil && cs.Resources != nil {
58+
return cs.Resources.Requests.DeepCopy(), cs.Resources.Limits.DeepCopy()
59+
}
60+
61+
klog.V(6).InfoS("initContainer resources not found in initContainerStatus for initContainer. Falling back to resources defined in the pod spec. This is expected for clusters with in-place pod updates feature disabled.", "initContainer", initContainerName, "initContainerStatus", cs)
62+
initContainer := findInitContainer(initContainerName, pod)
63+
if initContainer != nil {
64+
return initContainer.Resources.Requests.DeepCopy(), initContainer.Resources.Limits.DeepCopy()
65+
}
66+
67+
return nil, nil
68+
}
69+
4770
func findContainer(containerName string, pod *v1.Pod) *v1.Container {
4871
for i, container := range pod.Spec.Containers {
4972
if container.Name == containerName {
@@ -53,11 +76,29 @@ func findContainer(containerName string, pod *v1.Pod) *v1.Container {
5376
return nil
5477
}
5578

56-
func containerStatusForContainer(containerName string, pod *v1.Pod) *v1.ContainerStatus {
79+
func findInitContainer(initContainerName string, pod *v1.Pod) *v1.Container {
80+
for i, initContainer := range pod.Spec.InitContainers {
81+
if initContainer.Name == initContainerName {
82+
return &pod.Spec.InitContainers[i]
83+
}
84+
}
85+
return nil
86+
}
87+
88+
func containerStatusFor(containerName string, pod *v1.Pod) *v1.ContainerStatus {
5789
for i, containerStatus := range pod.Status.ContainerStatuses {
5890
if containerStatus.Name == containerName {
5991
return &pod.Status.ContainerStatuses[i]
6092
}
6193
}
6294
return nil
6395
}
96+
97+
func initContainerStatusFor(initContainerName string, pod *v1.Pod) *v1.ContainerStatus {
98+
for i, initContainerStatus := range pod.Status.InitContainerStatuses {
99+
if initContainerStatus.Name == initContainerName {
100+
return &pod.Status.InitContainerStatuses[i]
101+
}
102+
}
103+
return nil
104+
}

0 commit comments

Comments
 (0)