Skip to content

Commit fd82b0a

Browse files
feat(recommender): add OOMMinBumpUp&OOMBumpUpRatio to CRD (#8012)
* feat(recommender): add OOMMinBumpUp&OOMBumpUpRatio to CRD Signed-off-by: Omer Aplatony <[email protected]> * fixed e2e tests Signed-off-by: Omer Aplatony <[email protected]> * Update features.go Co-authored-by: Adrian Moisey <[email protected]> --------- Signed-off-by: Omer Aplatony <[email protected]> Co-authored-by: Adrian Moisey <[email protected]>
1 parent d526000 commit fd82b0a

File tree

31 files changed

+611
-86
lines changed

31 files changed

+611
-86
lines changed

vertical-pod-autoscaler/charts/vertical-pod-autoscaler/crds/vpa-v1-crd-gen.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,22 @@ spec:
372372
- Auto
373373
- "Off"
374374
type: string
375+
oomBumpUpRatio:
376+
anyOf:
377+
- type: integer
378+
- type: string
379+
description: oomBumpUpRatio is the ratio to increase memory
380+
when OOM is detected.
381+
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
382+
x-kubernetes-int-or-string: true
383+
oomMinBumpUp:
384+
anyOf:
385+
- type: integer
386+
- type: string
387+
description: oomMinBumpUp is the minimum increase in memory
388+
when OOM is detected.
389+
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
390+
x-kubernetes-int-or-string: true
375391
type: object
376392
type: array
377393
type: object

vertical-pod-autoscaler/deploy/vpa-v1-crd-gen.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,22 @@ spec:
372372
- Auto
373373
- "Off"
374374
type: string
375+
oomBumpUpRatio:
376+
anyOf:
377+
- type: integer
378+
- type: string
379+
description: oomBumpUpRatio is the ratio to increase memory
380+
when OOM is detected.
381+
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
382+
x-kubernetes-int-or-string: true
383+
oomMinBumpUp:
384+
anyOf:
385+
- type: integer
386+
- type: string
387+
description: oomMinBumpUp is the minimum increase in memory
388+
when OOM is detected.
389+
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
390+
x-kubernetes-int-or-string: true
375391
type: object
376392
type: array
377393
type: object

vertical-pod-autoscaler/docs/api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ _Appears in:_
4848
| `maxAllowed` _[ResourceList](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#resourcelist-v1-core)_ | Specifies the maximum amount of resources that will be recommended<br />for the container. The default is no maximum. | | |
4949
| `controlledResources` _[ResourceName](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#resourcename-v1-core)_ | Specifies the type of recommendations that will be computed<br />(and possibly applied) by VPA.<br />If not specified, the default of [ResourceCPU, ResourceMemory] will be used. | | |
5050
| `controlledValues` _[ContainerControlledValues](#containercontrolledvalues)_ | Specifies which resource values should be controlled.<br />The default is "RequestsAndLimits". | | Enum: [RequestsAndLimits RequestsOnly] <br /> |
51+
| `oomBumpUpRatio` _float_ | OOMBumpUpRatio is the ratio to increase resources when OOM is detected. | | Minimum: 1 <br /> |
52+
| `oomMinBumpUp` _float_ | OOMMinBumpUp is the minimum increase in resources when OOM is detected. | | Minimum: 0 <br /> |
5153

5254

5355
#### ContainerScalingMode

vertical-pod-autoscaler/docs/flags.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ This document is auto-generated from the flag definitions in the VPA admission-c
1414
| `address` | string | ":8944" | The address to expose Prometheus metrics. |
1515
| `alsologtostderr` | | | log to standard error as well as files (no effect when -logtostderr=true) |
1616
| `client-ca-file` | string | "/etc/tls-certs/caCert.pem" | Path to CA PEM file. |
17-
| `feature-gates` | mapStringBool | | A set of key=value pairs that describe feature gates for alpha/experimental features. Options are:<br>AllAlpha=true\|false (ALPHA - default=false)<br>AllBeta=true\|false (BETA - default=false)<br>InPlaceOrRecreate=true\|false (BETA - default=true) |
17+
| `feature-gates` | mapStringBool | | A set of key=value pairs that describe feature gates for alpha/experimental features. Options are:<br>AllAlpha=true\|false (ALPHA - default=false)<br>AllBeta=true\|false (BETA - default=false)<br>InPlaceOrRecreate=true\|false (BETA - default=true)<br>PerVPAConfig=true\|false (ALPHA - default=false) |
1818
| `ignored-vpa-object-namespaces` | string | | A comma-separated list of namespaces to ignore when searching for VPA objects. Leave empty to avoid ignoring any namespaces. These namespaces will not be cleaned by the garbage collector. |
1919
| `kube-api-burst` | float | 100 | QPS burst limit when making requests to Kubernetes apiserver |
2020
| `kube-api-qps` | float | 50 | QPS limit when making requests to Kubernetes apiserver |
@@ -68,7 +68,7 @@ This document is auto-generated from the flag definitions in the VPA recommender
6868
| `cpu-integer-post-processor-enabled` | | | Enable the cpu-integer recommendation post processor. The post processor will round up CPU recommendations to a whole CPU for pods which were opted in by setting an appropriate label on VPA object (experimental) |
6969
| `external-metrics-cpu-metric` | string | | ALPHA. Metric to use with external metrics provider for CPU usage. |
7070
| `external-metrics-memory-metric` | string | | ALPHA. Metric to use with external metrics provider for memory usage. |
71-
| `feature-gates` | mapStringBool | | A set of key=value pairs that describe feature gates for alpha/experimental features. Options are:<br>AllAlpha=true\|false (ALPHA - default=false)<br>AllBeta=true\|false (BETA - default=false)<br>InPlaceOrRecreate=true\|false (BETA - default=true) |
71+
| `feature-gates` | mapStringBool | | A set of key=value pairs that describe feature gates for alpha/experimental features. Options are:<br>AllAlpha=true\|false (ALPHA - default=false)<br>AllBeta=true\|false (BETA - default=false)<br>InPlaceOrRecreate=true\|false (BETA - default=true)<br>PerVPAConfig=true\|false (ALPHA - default=false) |
7272
| `history-length` | string | "8d" | How much time back prometheus have to be queried to get historical metrics |
7373
| `history-resolution` | string | "1h" | Resolution at which Prometheus is queried for historical metrics |
7474
| `humanize-memory` | | | DEPRECATED: Convert memory values in recommendations to the highest appropriate SI unit with up to 2 decimal places for better readability. This flag is deprecated and will be removed in a future version. Use --round-memory-bytes instead. |
@@ -95,8 +95,8 @@ This document is auto-generated from the flag definitions in the VPA recommender
9595
| `metric-for-pod-labels` | string | "up{job=\"kubernetes-pods\"}" | Which metric to look for pod labels in metrics |
9696
| `min-checkpoints` | int | 10 | Minimum number of checkpoints to write per recommender's main loop. WARNING: this flag is deprecated and doesn't have any effect. It will be removed in a future release. Refer to update-worker-count to influence the minimum number of checkpoints written per loop. |
9797
| `one-output` | severity | | If true, only write logs to their native level (vs also writing to each lower severity level; no effect when -logtostderr=true) |
98-
| `oom-bump-up-ratio` | float | 1.2 | The memory bump up ratio when OOM occurred, default is 1.2. |
99-
| `oom-min-bump-up-bytes` | float | 1.048576e+08 | The minimal increase of memory when OOM occurred in bytes, default is 100 * 1024 * 1024 |
98+
| `oom-bump-up-ratio` | float | 1.2 | Default memory bump up ratio when OOM occurs. This value applies to all VPAs unless overridden in the VPA spec. Default is 1.2. |
99+
| `oom-min-bump-up-bytes` | float | 1.048576e+08 | Default minimal increase of memory (in bytes) when OOM occurs. This value applies to all VPAs unless overridden in the VPA spec. Default is 100 * 1024 * 1024 (100Mi). |
100100
| `password` | string | | The password used in the prometheus server basic auth. Can also be set via the PROMETHEUS_PASSWORD environment variable |
101101
| `pod-label-prefix` | string | "pod_label_" | Which prefix to look for pod labels in metrics |
102102
| `pod-name-label` | string | "kubernetes_pod_name" | Label name to look for pod names |
@@ -144,7 +144,7 @@ This document is auto-generated from the flag definitions in the VPA updater cod
144144
| `eviction-rate-burst` | int | 1 | Burst of pods that can be evicted. |
145145
| `eviction-rate-limit` | float | | Number of pods that can be evicted per seconds. A rate limit set to 0 or -1 will disable<br>the rate limiter. (default -1) |
146146
| `eviction-tolerance` | float | 0.5 | Fraction of replica count that can be evicted for update, if more than one pod can be evicted. |
147-
| `feature-gates` | mapStringBool | | A set of key=value pairs that describe feature gates for alpha/experimental features. Options are:<br>AllAlpha=true\|false (ALPHA - default=false)<br>AllBeta=true\|false (BETA - default=false)<br>InPlaceOrRecreate=true\|false (BETA - default=true) |
147+
| `feature-gates` | mapStringBool | | A set of key=value pairs that describe feature gates for alpha/experimental features. Options are:<br>AllAlpha=true\|false (ALPHA - default=false)<br>AllBeta=true\|false (BETA - default=false)<br>InPlaceOrRecreate=true\|false (BETA - default=true)<br>PerVPAConfig=true\|false (ALPHA - default=false) |
148148
| `ignored-vpa-object-namespaces` | string | | A comma-separated list of namespaces to ignore when searching for VPA objects. Leave empty to avoid ignoring any namespaces. These namespaces will not be cleaned by the garbage collector. |
149149
| `in-recommendation-bounds-eviction-lifetime-threshold` | | 12h0m0s | duration Pods that live for at least that long can be evicted even if their request is within the [MinRecommended...MaxRecommended] range |
150150
| `kube-api-burst` | float | 100 | QPS burst limit when making requests to Kubernetes apiserver |

vertical-pod-autoscaler/e2e/v1/admission_controller.go

Lines changed: 143 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -871,26 +871,149 @@ var _ = AdmissionControllerE2eDescribe("Admission-controller", ginkgo.Label("FG:
871871
err := InstallRawVPA(f, validVPA)
872872
gomega.Expect(err).NotTo(gomega.HaveOccurred(), "Valid VPA object rejected")
873873

874-
ginkgo.By("Setting up invalid VPA object")
875-
// The invalid object differs by name and minAllowed - there is an invalid "requests" field.
876-
invalidVPA := []byte(`{
877-
"kind": "VerticalPodAutoscaler",
878-
"apiVersion": "autoscaling.k8s.io/v1",
879-
"metadata": {"name": "hamster-vpa-invalid"},
880-
"spec": {
881-
"targetRef": {
882-
"apiVersion": "apps/v1",
883-
"kind": "Deployment",
884-
"name":"hamster"
885-
},
886-
"resourcePolicy": {
887-
"containerPolicies": [{"containerName": "*", "minAllowed":{"requests":{"cpu":"50m"}}}]
888-
}
889-
}
890-
}`)
891-
err2 := InstallRawVPA(f, invalidVPA)
892-
gomega.Expect(err2).To(gomega.HaveOccurred(), "Invalid VPA object accepted")
893-
gomega.Expect(err2.Error()).To(gomega.MatchRegexp(`.*admission webhook .*vpa.* denied the request: .*`))
874+
ginkgo.By("Setting up invalid VPA objects")
875+
testCases := []struct {
876+
name string
877+
vpaJSON string
878+
expectedErr string
879+
}{
880+
{
881+
name: "Invalid oomBumpUpRatio (negative value)",
882+
vpaJSON: `{
883+
"apiVersion": "autoscaling.k8s.io/v1",
884+
"kind": "VerticalPodAutoscaler",
885+
"metadata": {"name": "oom-test-vpa"},
886+
"spec": {
887+
"targetRef": {
888+
"apiVersion": "apps/v1",
889+
"kind": "Deployment",
890+
"name": "oom-test"
891+
},
892+
"updatePolicy": {
893+
"updateMode": "Auto"
894+
},
895+
"resourcePolicy": {
896+
"containerPolicies": [{
897+
"containerName": "*",
898+
"oomBumpUpRatio": -1,
899+
"oomMinBumpUp": 104857600
900+
}]
901+
}
902+
}
903+
}`,
904+
expectedErr: "spec.resourcePolicy.containerPolicies[0].oomBumpUpRatio: Invalid value: -1: spec.resourcePolicy.containerPolicies[0].oomBumpUpRatio in body should be greater than or equal to 1",
905+
},
906+
{
907+
name: "Invalid oomBumpUpRatio (string value)",
908+
vpaJSON: `{
909+
"apiVersion": "autoscaling.k8s.io/v1",
910+
"kind": "VerticalPodAutoscaler",
911+
"metadata": {"name": "oom-test-vpa"},
912+
"spec": {
913+
"targetRef": {
914+
"apiVersion": "apps/v1",
915+
"kind": "Deployment",
916+
"name": "oom-test"
917+
},
918+
"updatePolicy": {
919+
"updateMode": "Auto"
920+
},
921+
"resourcePolicy": {
922+
"containerPolicies": [{
923+
"containerName": "*",
924+
"oomBumpUpRatio": "12",
925+
"oomMinBumpUp": 104857600
926+
}]
927+
}
928+
}
929+
}`,
930+
expectedErr: "json: cannot unmarshal string into Go struct field ContainerResourcePolicy.spec.resourcePolicy.containerPolicies.oomBumpUpRatio of type float64",
931+
},
932+
{
933+
name: "Invalid oomBumpUpRatio (less than 1)",
934+
vpaJSON: `{
935+
"apiVersion": "autoscaling.k8s.io/v1",
936+
"kind": "VerticalPodAutoscaler",
937+
"metadata": {"name": "oom-test-vpa"},
938+
"spec": {
939+
"targetRef": {
940+
"apiVersion": "apps/v1",
941+
"kind": "Deployment",
942+
"name": "oom-test"
943+
},
944+
"updatePolicy": {
945+
"updateMode": "Auto"
946+
},
947+
"resourcePolicy": {
948+
"containerPolicies": [{
949+
"containerName": "*",
950+
"oomBumpUpRatio": 0.5,
951+
"oomMinBumpUp": 104857600
952+
}]
953+
}
954+
}
955+
}`,
956+
expectedErr: "spec.resourcePolicy.containerPolicies[0].oomBumpUpRatio: Invalid value: 0.5: spec.resourcePolicy.containerPolicies[0].oomBumpUpRatio in body should be greater than or equal to 1",
957+
},
958+
{
959+
name: "Invalid oomMinBumpUp (negative value)",
960+
vpaJSON: `{
961+
"apiVersion": "autoscaling.k8s.io/v1",
962+
"kind": "VerticalPodAutoscaler",
963+
"metadata": {"name": "oom-test-vpa"},
964+
"spec": {
965+
"targetRef": {
966+
"apiVersion": "apps/v1",
967+
"kind": "Deployment",
968+
"name": "oom-test"
969+
},
970+
"updatePolicy": {
971+
"updateMode": "Auto"
972+
},
973+
"resourcePolicy": {
974+
"containerPolicies": [{
975+
"containerName": "*",
976+
"oomBumpUpRatio": 2,
977+
"oomMinBumpUp": -1
978+
}]
979+
}
980+
}
981+
}`,
982+
expectedErr: "spec.resourcePolicy.containerPolicies[0].oomMinBumpUp: Invalid value: -1: spec.resourcePolicy.containerPolicies[0].oomMinBumpUp in body should be greater than or equal to 0",
983+
},
984+
{
985+
name: "Invalid minAllowed (invalid requests field)",
986+
vpaJSON: `{
987+
"apiVersion": "autoscaling.k8s.io/v1",
988+
"kind": "VerticalPodAutoscaler",
989+
"metadata": {"name": "hamster-vpa-invalid"},
990+
"spec": {
991+
"targetRef": {
992+
"apiVersion": "apps/v1",
993+
"kind": "Deployment",
994+
"name": "hamster"
995+
},
996+
"resourcePolicy": {
997+
"containerPolicies": [{
998+
"containerName": "*",
999+
"minAllowed": {
1000+
"requests": {
1001+
"cpu": "50m"
1002+
}
1003+
}
1004+
}]
1005+
}
1006+
}
1007+
}`,
1008+
expectedErr: "admission webhook .*vpa.* denied the request:",
1009+
},
1010+
}
1011+
for _, tc := range testCases {
1012+
ginkgo.By(fmt.Sprintf("Testing %s", tc.name))
1013+
err := InstallRawVPA(f, []byte(tc.vpaJSON))
1014+
gomega.Expect(err).To(gomega.HaveOccurred(), "Invalid VPA object accepted")
1015+
gomega.Expect(err.Error()).To(gomega.MatchRegexp(tc.expectedErr))
1016+
}
8941017
})
8951018

8961019
ginkgo.It("reloads the webhook leaf and CA certificate", func(ctx ginkgo.SpecContext) {

vertical-pod-autoscaler/e2e/v1/common.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737
"k8s.io/autoscaler/vertical-pod-autoscaler/e2e/utils"
3838
vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1"
3939
vpa_clientset "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/clientset/versioned"
40+
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/features"
4041
clientset "k8s.io/client-go/kubernetes"
4142
"k8s.io/kubernetes/test/e2e/framework"
4243
framework_deployment "k8s.io/kubernetes/test/e2e/framework/deployment"
@@ -468,6 +469,20 @@ func WaitForPodsUpdatedWithoutEviction(f *framework.Framework, initialPods *apiv
468469
return err
469470
}
470471

472+
// checkPerVPAConfigTestsEnabled checks if the PerVPAConfig feature gate is enabled
473+
// in the VPA recommender.
474+
func checkPerVPAConfigTestsEnabled(f *framework.Framework) {
475+
ginkgo.By("Checking PerVPAConfig feature gate is enabled for recommender")
476+
deploy, err := f.ClientSet.AppsV1().Deployments(VpaNamespace).Get(context.TODO(), "vpa-recommender", metav1.GetOptions{})
477+
gomega.Expect(err).NotTo(gomega.HaveOccurred())
478+
gomega.Expect(deploy.Spec.Template.Spec.Containers).To(gomega.HaveLen(1))
479+
vpaRecommenderPod := deploy.Spec.Template.Spec.Containers[0]
480+
gomega.Expect(vpaRecommenderPod.Name).To(gomega.Equal("recommender"))
481+
if !anyContainsSubstring(vpaRecommenderPod.Args, fmt.Sprintf("%s=true", string(features.PerVPAConfig))) {
482+
ginkgo.Skip("Skipping suite: PerVPAConfig feature gate is not enabled for the VPA recommender")
483+
}
484+
}
485+
471486
func anyContainsSubstring(arr []string, substr string) bool {
472487
for _, s := range arr {
473488
if strings.Contains(s, substr) {

0 commit comments

Comments
 (0)