Horizontal Pod Autoscaling with KEDA
In this guide I wanted to show you can deploy KEDA as a solution for horizontal pod autoscaling in your cluster. Unlike the default metrics server provided to you by some cloud providers, KEDA is a more flexible and powerful solution that can scale your pods based on custom metrics. KEDA is event driven, so it can listen almost any metric you provide it with and scale your deployments accordingly. In my example I'll be using Prometheus as a metric source to scale Nginx.
Prerequisites
Let's setup a new cluster: kind create cluster --name keda
After it's done, I'll install:
- KEDA
- Prometheus
- Nginx
You can install them however you want, but in this example I'll use Terraform and Helm.
0-providers.tf
:
1-keda.tf
:
resource "helm_release" "keda" {
name = "keda"
repository = "https://kedacore.github.io/charts"
chart = "keda"
namespace = "keda"
create_namespace = true
}
2-prometheus.tf
:
resource "helm_release" "prometheus" {
name = "prometheus"
repository = "https://prometheus-community.github.io/helm-charts"
chart = "kube-prometheus-stack"
namespace = "prometheus"
create_namespace = true
values = [file("values/prom-values.yaml")]
}
Note
For Prometheus, I used the default values which you can get using helm show values prometheus-community/kube-prometheus-stack
.
3-nginx.tf
:
resource "helm_release" "nginx" {
name = "nginx"
repository = "https://charts.bitnami.com/bitnami"
chart = "nginx"
namespace = "nginx"
create_namespace = true
values = [file("values/values.yaml")]
}
For Nginx's values file, I enabled metrics
and ServiceMonitor
and provided a release
label:
service:
type: NodePort
metrics:
enabled: true
serviceMonitor:
enabled: true
labels:
release: prometheus
Checks
Let's make sure that Nginx's ServiceMonitor was applied correctly:
Great! We can see the ServiceMonitor object, as well as the target in our Prometheus.
Trigger KEDA
Now that we have everything in place, all we need to do is to trigger KEDA and see that it scales our deployment.
For this, I chose to use nginx_connections_accepted
as the metric on which we'll scale, but you can literally choose anything you want.
Let's deploy this following ScaledObject
by running kubectl apply
:
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: nginx-scaledobject
spec:
scaleTargetRef:
name: nginx
pollingInterval: 5
cooldownPeriod: 15
maxReplicaCount: 5
minReplicaCount: 1
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus-kube-prometheus-prometheus.prometheus.svc.cluster.local:9090
query: rate(nginx_connections_accepted[1m])
threshold: '1'
Note
Make sure to to update the attributes based on your setup.
Now that this manifest is applied, let's trigger it using k6. Here is a simple test that would send load to our endpoint:
import http from "k6/http";
export const options = {
iterations: 10,
};
export default function () {
const response = http.post("http://localhost:8080");
}
For it to work, port-forward your nginx service and update the script accordingly, then run it: k6 run --vus 5 --duration 60s load-test.js
.
Once we run it, we should be able to see our metric go up:
You can run kubectl events
and see the scaling process:
And lastly, running kubectl get pods | grep nginx
we can see the 4 pods that were created:
Depending on your cooldown period, it might take a while for the pods to scale back down.
This is pretty much it. KEDA is simple, powerful and provides you with many different Scalers to use, so you don't have to base your metric on Prometheus alone of course.