Skip to main content

Horizontal Pod Autoscaler

Description

Disallow the following scenarios when deploying HorizontalPodAutoscalers 1. Deployment of HorizontalPodAutoscalers with .spec.minReplicas or .spec.maxReplicas outside the ranges defined in the constraint 2. Deployment of HorizontalPodAutoscalers where the difference between .spec.minReplicas and .spec.maxReplicas is less than the configured minimumReplicaSpread 3. Deployment of HorizontalPodAutoscalers that do not reference a valid scaleTargetRef (e.g. Deployment, ReplicationController, ReplicaSet, StatefulSet).

Template

apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8shorizontalpodautoscaler
annotations:
metadata.gatekeeper.sh/title: "Horizontal Pod Autoscaler"
metadata.gatekeeper.sh/version: 1.0.1
metadata.gatekeeper.sh/requires-sync-data: |
"[
[
{
"groups":["apps"],
"versions": ["v1"],
"kinds": ["Deployment"]
},
{
"groups":["apps"],
"versions": ["v1"],
"kinds": ["StatefulSet"]
}
]
]"
description: >-
Disallow the following scenarios when deploying `HorizontalPodAutoscalers`
1. Deployment of HorizontalPodAutoscalers with `.spec.minReplicas` or `.spec.maxReplicas` outside the ranges defined in the constraint
2. Deployment of HorizontalPodAutoscalers where the difference between `.spec.minReplicas` and `.spec.maxReplicas` is less than the configured `minimumReplicaSpread`
3. Deployment of HorizontalPodAutoscalers that do not reference a valid `scaleTargetRef` (e.g. Deployment, ReplicationController, ReplicaSet, StatefulSet).
spec:
crd:
spec:
names:
kind: K8sHorizontalPodAutoscaler
validation:
# Schema for the `parameters` field
openAPIV3Schema:
type: object
properties:
enforceScaleTargetRef:
description: If set to true it validates the HPA scaleTargetRef exists
type: boolean
minimumReplicaSpread:
description: If configured it enforces the minReplicas and maxReplicas in an HPA must have a spread of at least this many replicas
type: integer
ranges:
type: array
description: Allowed ranges for numbers of replicas. Values are inclusive.
items:
type: object
description: A range of allowed replicas. Values are inclusive.
properties:
min_replicas:
description: The minimum number of replicas allowed, inclusive.
type: integer
max_replicas:
description: The maximum number of replicas allowed, inclusive.
type: integer
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8shorizontalpodautoscaler

violation[{"msg": msg}] {
input.review.kind.kind == "HorizontalPodAutoscaler"
hpa := input.review.object

not input_replica_limit(hpa)
msg := sprintf("The %v <%v> minReplicas %v or maxReplicas %v is not allowed: %v. Allowed ranges: %v", [hpa.kind, hpa.metadata.name, hpa.spec.minReplicas, hpa.spec.maxReplicas, input.parameters.ranges])
}

violation[{"msg": msg}] {
input.review.kind.kind == "HorizontalPodAutoscaler"
hpa := input.review.object

not input_replica_spread(hpa)

msg := sprintf("The %v <%v> is configured with minReplicas %v and maxReplicas %v which is a spread of %v replica(s). The spread must be at least %v replica(s)", [hpa.kind, hpa.metadata.name, hpa.spec.minReplicas, hpa.spec.maxReplicas, hpa.spec.maxReplicas - hpa.spec.minReplicas, input.parameters.minimumReplicaSpread])
}

violation[{"msg": msg}] {
input.review.kind.kind == "HorizontalPodAutoscaler"
hpa := input.review.object
input.parameters.enforceScaleTargetRef

not data.inventory.namespace[hpa.metadata.namespace][hpa.spec.scaleTargetRef.apiVersion][hpa.spec.scaleTargetRef.kind][hpa.spec.scaleTargetRef.name]
msg := sprintf("The HorizontalPodAutoscaler <%v> has a scaleTargetRef of <%v/%v> but it does not exist. The scaleTargetRef for the HorizontalPodAutoscaler must exist", [hpa.metadata.name, hpa.spec.scaleTargetRef.kind, hpa.spec.scaleTargetRef.name])
}

input_replica_limit(hpa) {
count(input.parameters.ranges) > 0
range := input.parameters.ranges[_]
value_within_range(range, hpa.spec.minReplicas, hpa.spec.maxReplicas)
}

value_within_range(range, min_provided, max_provided) {
range.min_replicas <= min_provided
range.max_replicas >= max_provided
}

input_replica_spread(hpa) {
input.parameters.minimumReplicaSpread
(hpa.spec.maxReplicas - hpa.spec.minReplicas) >= input.parameters.minimumReplicaSpread
}

Usage

kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/general/horizontalpodautoscaler/template.yaml

Examples

horizontal-pod-autoscaler
constraint
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sHorizontalPodAutoscaler
metadata:
name: horizontal-pod-autoscaler
spec:
enforcementAction: deny
match:
kinds:
- apiGroups: ["autoscaling"]
kinds: ["HorizontalPodAutoscaler"]
parameters:
minimumReplicaSpread: 1
enforceScaleTargetRef: true
ranges:
- min_replicas: 3
max_replicas: 6

Usage

kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/general/horizontalpodautoscaler/samples/horizontalpodautoscaler/constraint.yaml
example-allowed-hpa
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa-allowed
namespace: default
spec:
minReplicas: 3
maxReplicas: 6
metrics:
- resource:
name: cpu
target:
averageUtilization: 900
type: Utilization
type: Resource
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-deployment

Usage

kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/general/horizontalpodautoscaler/samples/horizontalpodautoscaler/example_allowed_hpa.yaml
example-disallowed-hpa-replicas
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa-disallowed-replicas
namespace: default
spec:
minReplicas: 2
maxReplicas: 7
metrics:
- resource:
name: cpu
target:
averageUtilization: 900
type: Utilization
type: Resource
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-deployment

Usage

kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/general/horizontalpodautoscaler/samples/horizontalpodautoscaler/example_disallowed_hpa_replicas.yaml
example-disallowed-hpa-replicaspread
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa-disallowed-replicaspread
namespace: default
spec:
minReplicas: 4
maxReplicas: 4
metrics:
- resource:
name: cpu
target:
averageUtilization: 900
type: Utilization
type: Resource
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-deployment

Usage

kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/general/horizontalpodautoscaler/samples/horizontalpodautoscaler/example_disallowed_hpa_replicaspread.yaml
example-disallowed-scaletarget
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa-disallowed-scaletarget
namespace: default
spec:
minReplicas: 3
maxReplicas: 6
metrics:
- resource:
name: cpu
target:
averageUtilization: 900
type: Utilization
type: Resource
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-deployment-missing

Usage

kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/general/horizontalpodautoscaler/samples/horizontalpodautoscaler/example_disallowed_hpa_scaletarget.yaml