Contents

KEDA for custom metrics based HPA

KEDA is a Kubernetes-based Event Driven Autoscaler. With KEDA, you can drive the scaling of any container in Kubernetes based on the number of events needing to be processed.

The following demo is based on the examples here

Install KEDA

Follow setups in KEDA docs

I used Helm 3 method

1
2
kubectl create namespace keda
helm install keda kedacore/keda --namespace keda

Install Prometheus

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: prometheus
rules:
- apiGroups: [""]
  resources:
  - services
  verbs: ["get", "list", "watch"]
- nonResourceURLs: ["/metrics"]
  verbs: ["get"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: default
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: prometheus
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: prometheus
subjects:
- kind: ServiceAccount
  name: default
  namespace: default
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: prom-conf
  labels:
    name: prom-conf
data:
  prometheus.yml: |-
    global:
      scrape_interval: 5s
      evaluation_interval: 5s
    scrape_configs:
      - job_name: 'go-prom-job'

        kubernetes_sd_configs:
        - role: service
        relabel_configs:
        - source_labels: [__meta_kubernetes_service_label_run]
          regex: go-prom-app-service
          action: keep
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: prometheus-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
        app: prometheus-server  
  template:
    metadata:
      labels:
        app: prometheus-server
    spec:
      containers:
        - name: prometheus
          image: prom/prometheus
          args:
            - "--config.file=/etc/prometheus/prometheus.yml"
            - "--storage.tsdb.path=/prometheus/"
          ports:
            - containerPort: 9090
          volumeMounts:
            - name: prometheus-config-volume
              mountPath: /etc/prometheus/
            - name: prometheus-storage-volume
              mountPath: /prometheus/
      volumes:
        - name: prometheus-config-volume
          configMap:
            defaultMode: 420
            name: prom-conf
  
        - name: prometheus-storage-volume
          emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: prometheus-service
spec:
  ports:
  - port: 9090
    protocol: TCP
  selector:
    app: prometheus-server

Check prometheus from UI

  • kubectl port-forward service/prometheus-service 9090
  • open localhost:9090 in a browser

Install redis for the demo app

helm install redis-server --set cluster.enabled=false --set usePassword=false stable/redis

Deploy demo app

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
apiVersion: apps/v1
kind: Deployment
metadata:
  name: go-prom-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: go-prom-app
  template:
    metadata:
      labels:
        app: go-prom-app
    spec:
      containers:
      - name: go-prom-app
        image: abhirockzz/go-prom-app
        env:
          - name: REDIS_HOST
            value: redis-server-master.default.svc.cluster.local
          - name: REDIS_PORT
            value: "6379"
        imagePullPolicy: Always
        ports:
            - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: go-prom-app-service
  labels:
    run: go-prom-app-service
spec:
  ports:
  - port: 8080
    protocol: TCP
  selector:
    app: go-prom-app

Make sure you can see the demo app in the prometheus targets page http://localhost:9090/targets

Deploy KEDA ScaledObject resource

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: keda.k8s.io/v1alpha1
kind: ScaledObject
metadata:
  name: prometheus-scaledobject
  namespace: default
  labels:
    deploymentName: go-prom-app
spec:
  scaleTargetRef:
    deploymentName: go-prom-app
  pollingInterval: 15  # Optional. Default: 30 seconds
  cooldownPeriod:  30 # Optional. Default: 300 seconds
  minReplicaCount: 1   # Optional. Default: 0
  maxReplicaCount: 10 # Optional. Default: 100
  triggers:
  - type: prometheus
    metadata:
      # Required
      serverAddress: http://prometheus-service.default.svc.cluster.local:9090
      metricName: access_frequency
      threshold: '3'
      query: sum(rate(http_requests[2m]))

Testing KEDA

Make the demo app accessible locally

kubectl port-forward service/go-prom-app-service 8080

View current pods

1
2
3
# kubectl get pod
NAME                                               READY   STATUS    RESTARTS   AGE
go-prom-app-5547b97ccd-l5p8v                       1/1     Running   0          6m

watch pod changes:

  • kubectl get pods -l=app=go-prom-app -w

Start load testing

1
echo "GET http://localhost:8080/test" | vegeta attack -duration=100s | tee results.bin | vegeta report

I am using vegeta for the loading here.

You will see number of pods increases.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# kubectl get pods -l=app=go-prom-app -w

NAME                           READY   STATUS    RESTARTS   AGE
go-prom-app-5547b97ccd-l5p8v   1/1     Running   0          7h6m
go-prom-app-5547b97ccd-l8nsz   0/1     Pending   0          0s
go-prom-app-5547b97ccd-l8nsz   0/1     Pending   0          0s
go-prom-app-5547b97ccd-l8nsz   0/1     ContainerCreating   0          0s
go-prom-app-5547b97ccd-l8nsz   1/1     Running             0          4s
go-prom-app-5547b97ccd-7c64n   0/1     Pending             0          0s
go-prom-app-5547b97ccd-7c64n   0/1     Pending             0          0s
go-prom-app-5547b97ccd-tj8gw   0/1     Pending             0          0s
go-prom-app-5547b97ccd-tj8gw   0/1     Pending             0          0s
go-prom-app-5547b97ccd-7c64n   0/1     ContainerCreating   0          0s
go-prom-app-5547b97ccd-tj8gw   0/1     ContainerCreating   0          0s