• January 1, 1
Table of Contents

There’s no place like K3d continued — 2 — scaling with KEDA

TLDR; this is a lab used to prove concepts delivered in the production-readiness series I am writing in Tikal’s Tech Radar.

Background

As you may know by now I am quite a big fan of K3d and it looks like i’ve embarked on a* “There’s no place like K3d” series* …, this post is a complementary to the “production readiness series”, i’m in the process of writing part 6 — scaling, and as it took me some time to separate scaling from scheduling which I eventually did in part5, this is my attempt to create an example I can reference in part6 discussing Horizontal Scaling which is very typical of Event Driven Systems / Architectures such as kubernetes.

Event Driven Architecture is at the core of how kubernetes controllers operate each request to the api is written to the key-value store which stores all the api requests in or case a deployment an hpa and a replica-set with a number of pods …

DALL-E | control loop, HPA and all things related comics styleDALL-E | control loop, HPA and all things related comics style

KEDA & HPA

like many things in kubernetes, kubernetes is a framework which provides a spec you can build on top of, in this case HPA which is a concept of adding replicas in form of additional pods to a deployment.

HPA provides the basic scaling option which includes cpu / memory based scaling whilst KEDA can expand on that technique by augmenting the HPA with its scaleObject as illustrated in the image below.

KEDA architecture — no words needed ;)KEDA architecture — no words needed ;)

Let’s review the use-case and later on continue to a step by step walkthrough.

Usecase:

KEDA basically creates the HPA and monitors it “externally” — which means the keda-controller monitors the keda.sh/v1alpha1 custom resource definition named ScaledObject, in our example we will have keda controller with a redis based scaleObject and in the triggers section of the spec we will request the listName my-queue is equal to 10 … it will basically look like the following object:

cat <<EOF | kubectl apply -f -
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: redis-scaler
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-app
  pollingInterval: 15
  cooldownPeriod: 30
  minReplicaCount: 1
  maxReplicaCount: 10
  triggers:
  - type: redis
    metadata:
      address: redis-master.keda-demo.svc.cluster.local:6379
      listName: my-queue
      listLength: "10"
      password: ""
      databaseIndex: "0"
      key: "hits"
      type: string
      operator: GT
      threshold: "2"
EOF

Once applied you can monitor the scaled object:

kubectl  get scaledobjects.keda.sh,hpa,deploy -n keda-demo

NAME                                SCALETARGETKIND      SCALETARGETNAME   MIN   MAX   TRIGGERS   AUTHENTICATION   READY   ACTIVE   FALLBACK   PAUSED    AGE
scaledobject.keda.sh/redis-scaler   apps/v1.Deployment   web-app           1     10    redis                       True    True     False      Unknown   6h24m

NAME                                                        REFERENCE            TARGETS      MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/keda-hpa-redis-scaler   Deployment/web-app   7/10 (avg)   1         10        2          6h24m

NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/web-app   1/1     1            1           12h

keda configuration is pretty straight forward and if we add to this some job that populates the redis listName … e.g:

# create a job that uses redis-cli to connect and add items to the my-queue collection
apiVersion: batch/v1
kind: Job
metadata:
  name: populate-redis-queue
spec:
  template:
    spec:
      containers:
      - name: redis-cli
        image: redis:latest
        command: ["sh", "-c", "redis-cli -h redis-master.keda-demo.svc.cluster.local -p 6379 lpush my-queue item1 item2 item3 item4 item5 item6 item7 item8 item9"]
      restartPolicy: Never

were basically using redis-cli lpush my-queue item1 item2 item3 … command to populate the list if we now examine our resources we should see additional replicas added based on the listName length.

kubectl  get scaledobjects.keda.sh,hpa,deploy -n keda-demo

NAME                                SCALETARGETKIND      SCALETARGETNAME   MIN   MAX   TRIGGERS   AUTHENTICATION   READY   ACTIVE   FALLBACK   PAUSED    AGE
scaledobject.keda.sh/redis-scaler   apps/v1.Deployment   web-app           1     10    redis                       True    True     False      Unknown   6h24m

NAME                                                        REFERENCE            TARGETS      MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/keda-hpa-redis-scaler   Deployment/web-app   7/10 (avg)   1         10        2          6h24m

NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/web-app   2/2     2            2           12h

These scaling capabilities are quite commodity nowadays and can simulate “server-less style architecture” from the scale of 0 to n which arn’t just elegant — but cost-effective, especially nowadays which model training based on triggers is in demand.

DALL-E | Lets create an image saying “switching to hands-on mode” make it in the theme of “kubernetes” “k3d” “hpa” “keda” we want to emphasize the hands-on experience and how important it is to software developersDALL-E | Lets create an image saying “switching to hands-on mode” make it in the theme of “kubernetes” “k3d” “hpa” “keda” we want to emphasize the hands-on experience and how important it is to software developers

A step-by-step guide for this example

  1. Create a k3d cluster named keda-demo

  2. Deploy keda and redis to store our scaling-list

  3. Deploy a example web-app application deployment using nginx:latest

  4. Deploy a scaleObject that will connect to redis

  5. Deploy a kubernetes job that populates the scaling-list

Let’s get to work …

  1. Create a cluster

    k3d cluster create keda-demo

  2. Deploy keda and redis via helm

    please note usage of –kube-context k3d-keda-demo

    install keda

    helm repo add kedacore https://kedacore.github.io/charts helm upgrade –install keda kedacore/keda
    –namespace keda
    –create-namespace
    –kube-context k3d-keda-demo

    install redis via helm disabeling auth for demo purposes

    helm repo add bitnami https://charts.bitnami.com/bitnami helm upgrade –install redis bitnami/redis
    –set auth.enabled=false
    –set architecture=standalone
    –namespace keda-demo –create-namespace
    –kube-context k3d-keda-demo

  3. Deploy a example web-app application deployment using nginx:latest

    were starting with 1 replica of nginx:latest container

    cat «EOF | kubectl -n keda-demo apply -f - apiVersion: apps/v1 kind: Deployment metadata: name: web-app spec: replicas: 1 selector: matchLabels: app: web-app template: metadata: labels: app: web-app spec: containers: - name: web-container image: nginx:latest resources: requests: memory: “64Mi” cpu: “250m” limits: memory: “128Mi” cpu: “500m” EOF

  4. Deploy a scaleObject that will connect to redis ans suscribe to the my-queue list

    redis-scaler for Deployment named web-app

    cat «EOF | kubectl apply -f - apiVersion: keda.sh/v1alpha1 kind: ScaledObject metadata: name: redis-scaler spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: web-app pollingInterval: 15 cooldownPeriod: 30 minReplicaCount: 1 maxReplicaCount: 10 triggers:

    • type: redis metadata:

      based on the svc name:

      “redis-master” . “keda-demo” (namespace) . “svc.cluster.local” (cluster-suffix)

      address: redis-master.keda-demo.svc.cluster.local:6379 listName: my-queue listLength: “10” password: "" databaseIndex: “0” key: “hits” type: string operator: GT threshold: “2” EOF
  5. Deploy a kubernetes job that populates the scaling-list

    cat «EOF | kubectl apply -f - apiVersion: batch/v1 kind: Job metadata: name: populate-redis-queue spec: template: spec: containers: - name: redis-cli image: redis:latest command: [“sh”, “-c”, “redis-cli -h redis-master.keda-demo.svc.cluster.local -p 6379 lpush my-queue item1 item2 item3 item4 item5 item6 item7 item8 item9”] restartPolicy: Never EOF

Review our setup

We can take a closer look at our scaledobject now: take a close look at the status of the resource which indicates what it has done.

kubectl describe scaledobjects.keda.sh -n keda-demo


Name:         redis-scaler
Namespace:    keda-demo
Labels:       scaledobject.keda.sh/name=redis-scaler
Annotations:  <none>
API Version:  keda.sh/v1alpha1
Kind:         ScaledObject
Metadata:
  Creation Timestamp:  2024-07-10T14:27:46Z
  Finalizers:
    finalizer.keda.sh
  Generation:        1
  Resource Version:  1706
  UID:               72dcd626-0122-46f5-9841-cbace93a30aa
Spec:
  Cooldown Period:    30
  Max Replica Count:  10
  Min Replica Count:  1
  Polling Interval:   15
  Scale Target Ref:
    API Version:  apps/v1
    Kind:         Deployment
    Name:         web-app
  Triggers:
    Metadata:
      Address:         redis-master.keda-demo.svc.cluster.local:6379
      Database Index:  0
      Key:             hits
      List Length:     10
      List Name:       my-queue
      Operator:        GT
      Password:        
      Threshold:       2
      Type:            string
    Type:              redis
Status:
  Conditions:
    Message:  ScaledObject is defined correctly and is ready for scaling
    Reason:   ScaledObjectReady
    Status:   True
    Type:     Ready
    Message:  Scaling is performed because triggers are active
    Reason:   ScalerActive
    Status:   True
    Type:     Active
    Message:  No fallbacks are active on this scaled object
    Reason:   NoFallbackFound
    Status:   False
    Type:     Fallback
    Status:   Unknown
    Type:     Paused
  External Metric Names:
    s0-redis-my-queue
  Health:
    s0-redis-my-queue:
      Number Of Failures:  0
      Status:              Happy
  Hpa Name:                keda-hpa-redis-scaler
  Last Active Time:        2024-07-10T14:31:32Z
  Original Replica Count:  1
  Scale Target GVKR:
    Group:            apps
    Kind:             Deployment
    Resource:         deployments
    Version:          v1
  Scale Target Kind:  apps/v1.Deployment
Events:
  Type    Reason              Age                    From           Message
  ----    ------              ----                   ----           -------
  Normal  KEDAScalersStarted  3m52s                  keda-operator  Scaler redis is built.
  Normal  KEDAScalersStarted  3m52s                  keda-operator  Started scalers watch
  Normal  ScaledObjectReady   3m52s (x2 over 3m52s)  keda-operator  ScaledObject is ready for scaling

Unlike the deployment we created above, we can now see there are 2 replicas:

kubectl get deployments.apps web-app

NAME      READY   UP-TO-DATE   AVAILABLE   AGE
web-app   2/2     2            2           19m

You can of corse adjust this use case as wild as you imagination can go ;) and was mainly to emphasis how KEDA is another “must have” controller to help these common event driven use cases on-premise as we saw in this example which used redis and could have as easily used rabbitmq / sqs etc.

KEDA | Kubernetes Event-driven AutoscalingKEDA | Kubernetes Event-driven Autoscaling

I created a gist of a Taskfile.yml which has this demo avail in the following gist https://gist.github.com/hagzag/6f66c357e8c511c22b84365df68fff11 to run it:

git clone https://gist.github.com/6f66c357e8c511c22b84365df68fff11.git
cd 6f66c357e8c511c22b84365df68fff11
task setup 
# check what was done - kubectl get po -A
task demonstrate-scale 
# check that the web-app in keda-demo namespace is scaling from 1-2

Hope you enjoy this style of posts, I know I do … :) Thanks, HP

comments powered by Disqus

Related Posts

Developing a Webcam Arcade Controller using Deep Learning by TensorFlow & Keras - part 1, Meetup

Developing a Webcam Arcade Controller using Deep Learning by TensorFlow & Keras - part 1, Meetup

We will introduce Deep Learning, demo a DL model in action, introduce an architecture for training and use of such model in a production environment, and show some critical sections of the code. Demo - Control video game using Deep Learning (15 min) - by Haim Cohen, Big Data Architect from Tikal. We will demo an application which makes use of deep learning in order to control a video game through webcam and head gestures. Lectures: Deep Learning - Starting Now (20 min) - by Shai Tal, Data Scientist and Machine Learning Engineer from Tikal. Deep learning is a tool. And tools need to be understood. We will briefly discuss the practical benefits of machine learning over programming, and the benefits of deep learning over classic machine learning for building visualisation and NLP models. Deep Learning API’s & Architecture (30 min) by Haim Cohen. We will Introduce TensorFlow & Keras through code examples, go through main parts of the demo application and talk about the architecture of the demo application and other Deep Learning based systems. DevOps Concerns for Deep Learning Systems (30 min) - by Haggai Philip Zagury, DevOps Architect from Tikal.

Read More
Docking your services with Docker | Hebrew

Docking your services with Docker | Hebrew

How MSA (Micro Service Architecture) encourages immutable servers and how containers help deliver such an architecture. The talk will discuss LXC, Docker and technologies / techniques which are making there way in to the “best practices” handbook for containers in a MSA based systems.

Read More