Skip to content

Instantly share code, notes, and snippets.

@Rud5G
Forked from iyalang/auto-vpa-creation-policy.yaml
Created December 22, 2024 12:35
Show Gist options
  • Save Rud5G/5faafc0c2f86e74bc34e992cc41706c4 to your computer and use it in GitHub Desktop.
Save Rud5G/5faafc0c2f86e74bc34e992cc41706c4 to your computer and use it in GitHub Desktop.
Kyverno policy for automated creation of Vertical Pod Autoscalers (VPAs)
---
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: auto-vpa-creation
annotations:
policies.kyverno.io/title: Add default VPA
policies.kyverno.io/category: Cost Optimization
policies.kyverno.io/subject: Vertical Pod Autoscaler
policies.kyverno.io/description: >-
This policy creates a Vertical Pod Autoscaler for each new workload unless it already has one or is using a Horizontal Pod Autoscaler.
spec:
validationFailureAction: Enforce
background: true
generateExistingOnPolicyUpdate: true
rules:
- name: create-default-vpa-one-container
match:
any:
- resources:
kinds:
- DaemonSet
- Deployment
- StatefulSet
context:
- name: existingHPA
apiCall:
urlPath: '/apis/autoscaling/v2/namespaces/{{request.namespace}}/horizontalpodautoscalers'
jmesPath: "items[].spec.scaleTargetRef.name"
- name: existingVPA
apiCall:
urlPath: "/apis/autoscaling.k8s.io/v1/namespaces/{{request.namespace}}/verticalpodautoscalers"
jmesPath: "items[].spec.targetRef.name"
- name: autoVPACount
apiCall:
urlPath: '/apis/autoscaling.k8s.io/v1/namespaces/{{request.namespace}}/verticalpodautoscalers'
jmesPath: items[?metadata.labels."auto-vpa"] | [?spec.targetRef.name=='{{request.object.metadata.name}}'] | length(@)
- name: totalContainers
variable:
value: '{{ request.object.spec.template.spec.containers }}'
jmesPath: 'length(@)'
preconditions:
all:
- key: '{{request.operation}}'
operator: NotEquals
value: DELETE
- key: '{{request.object.metadata.name}}'
operator: AllNotIn
value: '{{existingHPA}}'
- key: '{{totalContainers}}'
operator: Equals
value: "1"
# Make sure there are no existing VPAs for this object
# UNLESS there is an auto VPA (then it's ok to update it).
any:
- key: '{{request.object.metadata.name}}'
operator: AllNotIn
value: '{{existingVPA}}'
- key: '{{ autoVPACount }}'
operator: Equals
value: 1
exclude:
any:
- resources:
selector:
matchLabels:
auto-vpa/create: "false"
- resources:
namespaces:
- kube-system
- resources:
namespaceSelector:
matchExpressions:
- key: "auto-vpa/create"
operator: In
values:
- "false"
generate:
synchronize: true
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
name: '{{request.object.metadata.name}}-auto-vpa'
namespace: '{{request.object.metadata.namespace}}'
data:
metadata:
labels:
auto-vpa: "true"
ownerReferences:
- apiVersion: apps/v1
kind: '{{request.object.kind}}'
name: '{{request.object.metadata.name}}'
uid: '{{request.object.metadata.uid}}'
spec:
targetRef:
apiVersion: "apps/v1"
kind: '{{request.object.kind}}'
name: '{{request.object.metadata.name}}'
updatePolicy:
updateMode: "Auto"
resourcePolicy:
containerPolicies:
- containerName: "*"
minAllowed:
cpu: 10m
memory: 32Mi
maxAllowed:
cpu: '{{request.object.spec.template.spec.containers[0].resources.requests.cpu}}'
memory: '{{request.object.spec.template.spec.containers[0].resources.requests.memory}}'
controlledResources: ["cpu", "memory"]
controlledValues: "RequestsOnly"
- name: create-default-vpa-multiple-containers
match:
any:
- resources:
kinds:
- DaemonSet
- Deployment
- StatefulSet
context:
- name: existingHPA
apiCall:
urlPath: "/apis/autoscaling/v2/namespaces/{{request.namespace}}/horizontalpodautoscalers"
jmesPath: "items[].spec.scaleTargetRef.name"
- name: existingVPA
apiCall:
urlPath: "/apis/autoscaling.k8s.io/v1/namespaces/{{request.namespace}}/verticalpodautoscalers"
jmesPath: "items[].spec.targetRef.name"
- name: autoVPACount
apiCall:
urlPath: '/apis/autoscaling.k8s.io/v1/namespaces/{{request.namespace}}/verticalpodautoscalers'
jmesPath: items[?metadata.labels."auto-vpa"] | [?spec.targetRef.name=='{{request.object.metadata.name}}'] | length(@)
- name: totalContainers
variable:
value: '{{request.object.spec.template.spec.containers}}'
jmesPath: 'length(@)'
preconditions:
all:
- key: '{{request.operation}}'
operator: NotEquals
value: DELETE
- key: '{{request.object.metadata.name}}'
operator: AllNotIn
value: '{{existingHPA}}'
- key: '{{totalContainers}}'
operator: NotEquals
value: "1"
# Make sure there are no existing VPAs for this object
# UNLESS there is an auto VPA (then it's ok to update it).
any:
- key: '{{request.object.metadata.name}}'
operator: AllNotIn
value: '{{existingVPA}}'
- key: '{{ autoVPACount }}'
operator: Equals
value: 1
exclude:
any:
- resources:
selector:
matchLabels:
auto-vpa/create: "false"
- resources:
namespaces:
- kube-system
- resources:
namespaceSelector:
matchExpressions:
- key: "auto-vpa/create"
operator: In
values:
- "false"
generate:
synchronize: true
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
name: '{{request.object.metadata.name}}-auto-vpa'
namespace: '{{request.object.metadata.namespace}}'
data:
metadata:
labels:
auto-vpa: "true"
ownerReferences:
- apiVersion: apps/v1
kind: '{{request.object.kind}}'
name: '{{request.object.metadata.name}}'
uid: '{{request.object.metadata.uid}}'
spec:
targetRef:
apiVersion: "apps/v1"
kind: '{{request.object.kind}}'
name: '{{request.object.metadata.name}}'
updatePolicy:
updateMode: "Auto"
resourcePolicy:
containerPolicies:
- containerName: "*"
minAllowed:
cpu: 10m
memory: 32Mi
controlledResources: ["cpu", "memory"]
controlledValues: "RequestsOnly"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment