Published by

Il y a 4 semaines -

Temps de lecture 5 minutes

Kubernetes Event-driven Autoscaling (KEDA)

Sur Kubernetes, vous pouvez scale automatiquement vos Deployments grâce aux Horizontal Pod Autoscaler (HPA). Les HPA se basent sur la consommation en CPU et en mémoire des Pods de votre Deployment pour augmenter ou réduire son nombre de réplicas.

Maintenant, supposons que nous souhaitions autoscale un consumer Kafka. À la XebiCon 2018, nous vous présentions une façon d’utiliser les HPA avec les métriques personnalisées de Kubernetes pour autoscale une application kafka-streams. Aujourd’hui, je vous propose de découvrir KEDA qui s’occupera de vous abstraire des principales difficultés.

Prérequis

Pour reproduire les expérimentations de cet article, il vous faudra un cluster Kubernetes 1.18+ et Helm 3.5.x+.

Les composants de KEDA

L’opérateur KEDA est composé des éléments suivants :

  • Une CRD ScaledObject, qu’on utilisera pour configurer l’autoscaling.
  • Un Controller, qui se base les ScaledObject pour créer les HPA correspondant au scaling désiré.
  • Un metrics-apiserver, qui expose toutes les métriques utiles à notre Controller.

 

Exemple d’un scale up avec KEDA

KEDA fonctionne avec la grande majorité des outils de file de messages.

Installer KEDA

Il existe un chart Helm KEDA officiel très simple d’utilisation. Pour tester rapidement, pas besoin de surcharger beaucoup de valeurs, vous pouvez vous contenter d’un simple :

helm repo add kedacore https://kedacore.github.io/charts
helm install keda kedacore/keda --namespace keda-system --version 2.1.3

On peut vérifier que tout a bien été installé :

$ kubectl get deploy -n keda-system
NAME                                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/keda-operator                     1/1     1            1           42s
deployment.apps/keda-operator-metrics-apiserver   1/1     1            1           42s

 

Installer Kafka

Pour gagner du temps nous allons déployer un chart Helm Kafka sur notre cluster Kubernetes. Bien évidemment, ce cluster n’a rien de « prod-ready » et dans des conditions réelles nous lui préfererions probablement un service managé. Pour notre test, nous allons au plus simple et déployons avec les valeurs par défaut.

helm repo add bitnami https://charts.bitnami.com/bitnami
helm install my-release bitnami/kafka

Une fois le chart Helm installé, toutes les informations utiles à son utilisation sont affichées. Voici ce qui va nous intéresser :

Each Kafka broker can be accessed by producers via port 9092 on the following DNS name(s) from within your cluster:

    my-release-kafka-0.my-release-kafka-headless.default.svc.cluster.local:9092

To create a pod that you can use as a Kafka client run the following commands:

    kubectl run my-release-kafka-client --restart='Never' --image docker.io/bitnami/kafka:2.8.0-debian-10-r0 --namespace default --command -- sleep infinity
    kubectl exec --tty -i my-release-kafka-client --namespace default -- bash

    PRODUCER:
        kafka-console-producer.sh \
            --broker-list my-release-kafka-0.my-release-kafka-headless.default.svc.cluster.local:9092 \
            --topic test

L’adresse du broker sera nécessaire pour notre consumer maison.

On peut dès à présent déployer le producer proposé en exemple qui nous servira à tester KEDA. La méthode proposé par le chart Helm vous fait d’abord créer un pod, lancer bash dedans puis utiliser le script kafka-console-producer.sh pour démarrer un producer. Ensuite, vous n’avez plus qu’à écrire vos messages et appuyée sur entrée pour qu’ils soient produits dans le topic.

Déployer un consumer

Pour que KEDA puisse autoscale une application, celle-ci doit utiliser un Deployment. J’ai préparé pour vous une image de consumer Kafka : sapientfr/consumer.

C’est une application très simple qui ne fait que récupérer le contenu d’un topic Kafka et le loguer.

Voici notre manifeste de Deployment pour Kubernetes :

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: consumer
  name: consumer
spec:
  replicas: 1
  selector:
    matchLabels:
      app: consumer
  template:
    metadata:
      labels:
        app: consumer
    spec:
      containers:
      - image: sapientfr/consumer
        name: consumer
        env:
        - name: BROKER
          value: my-release-kafka-0.my-release-kafka-headless.default.svc.cluster.local:9092
        - name: TOPIC
          value: test
        - name: GROUP_ID
          value: app_1

Une fois déployé, on va surveiller le nombre de réplicas que le Deployment possède :

kubectl get deploy -w
NAME       READY   UP-TO-DATE   AVAILABLE   AGE
consumer   1/1     1            1           42s

On peut tester que notre consumer fonctionne bien en envoyant des messages via notre producer et en affichant les logs :


Producer Kafka

Consumer Kafka

Déployer le ScaledObject

Il ne nous reste plus qu’à déployer notre ScaledObjectDeployment. Voici notre manifeste de ScaledObject :

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: kafka-scaledobject
  namespace: default
spec:
  maxReplicaCount: 100
  minReplicaCount: 0
  pollingInterval: 5
  scaleTargetRef:
    name: consumer
  triggers:
    - type: kafka
      metadata:
        bootstrapServers: my-release-kafka-0.my-release-kafka-headless.default.svc.cluster.local:9092
        consumerGroup: app_1
        topic: test
        lagThreshold: '5'

 

Dans ce manifeste on définit en spec toute la configuration de notre autoscaling :

  • maxReplicaCount : le nombre maximal de réplicas souhaité, utile pour éviter de prendre toutes les ressources du cluster Kubernetes.
  • minReplicaCount : c’est l’inverse. KEDA vous permet de downscale jusqu’à 0 si vous le désirez quand votre file de message est vide. Attention au cold start !
  • pollingInterval : le nombre de secondes entre chaque vérification de l’état de la file de message.
  • scaleTargetRef : les informations nécessaires pour identifier la cible à autoscale. Ici, le nom du Deployment seul suffit.
  • triggers :
    • type: le type de scalers en fonction de l’outil de file de message que l’on utilise.
    • metadata : les informations pour se connecter à notre source de messages.

Retrouvez sur la documentation du ScaledObject de KEDA toutes les autres configurations possibles.

Résultats

Actuellement notre application est à jour dans la file de message. Si nous attendons quelques secondes que notre ScaledObject fasse effet, nous allons voir notre Deployment diminuer son nombre de réplicas pour passer à 0.

kubectl get deploy -w
NAME       READY   UP-TO-DATE   AVAILABLE   AGE
consumer   1/1     1            1           42s   # le nombre initial de réplicas est à 1
consumer   0/0     0            0           1337s # le nombre de réplicas a été mis à jour à 0

Amusez-vous à renvoyer des messages, et vous verrez votre Deployment augmenter son nombre de réplicas tout seul !

kubectl get deploy -w
NAME       READY   UP-TO-DATE   AVAILABLE   AGE
consumer   1/1     1            1           42s   # le nombre initial de réplicas est à 1
consumer   0/0     0            0           1337s # le nombre de réplicas a été mis à jour à 0
consumer   0/1     1            0           1350s # le nombre de réplicas a été mis à jour à 1
consumer   1/1     1            1           1355s # on a 1 pod qui est running

Vous pouvez également jouer avec les paramètres de votre ScaledObject pour observer l’impact sur l’autoscaling.

Pour conclure

Dans cet article, nous venons donc de voir à quel point il est aisé d’autoscale une application en fonction d’une file de message (ici un topic Kafka) grâce à KEDA. Celui-ci se déploie facilement grâce à un chart Helm et propose plus d’une trentaine de connecteurs sur lesquels baser vos autoscaling. Vous pouvez retrouver tout le code source présenté dans ce repository GitHub KEDA hello world.

Published by

Commentaire

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Nous recrutons

Être un Sapient, c'est faire partie d'un groupe de passionnés ; C'est l'opportunité de travailler et de partager avec des pairs parmi les plus talentueux.