#SeLiga 05 – Escale suas aplicações usando KEDA
Author
GetupTue Feb 28 2023

#SeLiga 05 – Escale suas aplicações usando KEDA

Nesta edição do #SeLiga, nosso boletim mensal, nossos especialistas mostram como tornar a escalar de maneira simples e automatizada através do KEDA.

KEDA é uma plataforma de escalabilidade para o Kubernetes que está mudando como as empresas gerenciam seus recursos dentro do Kubernetes.

O KEDA torna a escalabilidade simples e automatizada, permitindo que os usuários dimensionem suas aplicações e serviços de forma eficiente e com o mínimo de esforço.

O grande diferencial do KEDA é a sua flexibilidade e adaptabilidade. A plataforma consegue escalar horizontalmente qualquer workload, independentemente do tipo de aplicação ou serviço em execução. Além disso, KEDA é compatível com uma variedade de provedores de nuvem e ferramentas de monitoramento, permitindo que os usuários personalizem a plataforma para atender às necessidades específicas de seus negócios.

Se você não quer escalar suas aplicações baseando-se somente em CPU e memória, mas observando outras métricas ou eventos externos, essa é a ferramenta que vai te ajudar na escalabilidade horizontal. Subindo ou descendo pods a medida que sua stack demanda.

KEDA, Kubernetes Event-Driven Autoscaling, é um dimensionador automático de pods baseado em eventos externos. Podemos escalar facilmente nossos pods baseados em métricas locais de CPU e memória, mas e quando temos algum evento externo que precede o seu uso? Por exemplo, uma fila de mensageria, uma tabela de banco de dados, uma query de ElasticSearch, Kafka, Redis, Prometheus externos ao seu cluster, e por aí vai.

Existem várias vantagens técnicas em usar o KEDA em vez do Horizontal Pod Autoscaler (HPA) para escalar aplicativos no Kubernetes. Aqui estão algumas delas:

  • Suporte a métricas personalizadas: O KEDA oferece suporte a métricas personalizadas, permitindo que os usuários dimensionem seus aplicativos e serviços com base em métricas específicas, além de CPU e memória. Isso permite que os usuários personalizem a plataforma para atender às necessidades específicas de seus aplicativos.
  • Suporte a várias fontes de eventos: O KEDA é compatível com várias fontes de eventos, incluindo Kafka, RabbitMQ e Azure Service Bus. Isso permite que os usuários dimensionem seus aplicativos com base em eventos, em vez de apenas métricas.
  • Autenticação de recurso: O KEDA suporta autenticação de recursos, permitindo que os usuários autentiquem com segurança o acesso aos recursos de escalabilidade. Isso ajuda a proteger os recursos do cluster Kubernetes de acesso não autorizado.
  • Escalabilidade rápida: O KEDA oferece escalabilidade rápida e precisa. A plataforma utiliza tecnologias avançadas de escalabilidade em tempo real para garantir que os recursos sejam usados ​​de forma eficiente e eficaz. Isso permite que os usuários escalonem rapidamente com base em métricas personalizadas e outras condições.
  • Maior eficiência de recursos: O KEDA é altamente eficiente em termos de recursos, permitindo que os usuários dimensionem seus aplicativos com o mínimo de recursos necessários. Isso ajuda a economizar dinheiro e a melhorar o desempenho do cluster Kubernetes.
  • Melhor integração com provedores de nuvem: O KEDA oferece uma melhor integração com provedores de nuvem, incluindo Azure, AWS e Google Cloud. Isso permite que os usuários personalizem a plataforma para atender às necessidades específicas de seus negócios e aproveitem os recursos do provedor de nuvem.
  • Escalar pods para ZERO unidades: Diferente do HPA, o KEDA permite zerar as unidades de pods de um deploy e utilizar uma trigger para escalar de acordo com a demanda.

Vamos começar pela arquitetura do KEDA:

Vamos ver como ele funciona de fato, para isso vamos instalar o KEDA em um cluster Kubernetes e criar uma fila no SQS para usarmos de trigger

Vamos usar um cluster Kind para testar.

cat <<EOF | kind create cluster --config -
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: demo
nodes:
- role: control-plane
  image: kindest/node:v1.24.7@sha256:577c630ce8e509131eab1aea12c022190978dd2f745aac5eb1fe65c0807eb315    
- role: worker
  image: kindest/node:v1.24.7@sha256:577c630ce8e509131eab1aea12c022190978dd2f745aac5eb1fe65c0807eb315
EOF
Creating cluster "demo" ...
 ✓ Ensuring node image (kindest/node:v1.24.7) 🖼 
 ✓ Preparing nodes 📦 📦  
 ✓ Writing configuration 📜 
 ✓ Starting control-plane 🕹️ 
 ✓ Installing CNI 🔌 
 ✓ Installing StorageClass 💾 
 ✓ Joining worker nodes 🚜 
Set kubectl context to "kind-demo"
You can now use your cluster with:

kubectl cluster-info --context kind-demo

Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/#community 🙂

Instalando o KEDA:

# Adicione o repositório helm do KEDA 

helm repo add keda https://kedacore.github.io/charts

# Atualize seus repositórios

helm repo update

# Instale o chart do KEDA

helm install keda keda/keda -n keda --create-namespace

Criando uma aplicação simples para testar

kubectl create deploy web --image nginx

Crie uma fila AWS SQS (standard queue)

No console da AWS -> AWS SQS -> Standard Queue, copie a regiao e a URL da fila.

Criando um objeto KEDA, ScaledObject e sua autenticação na AWS

cat <<EOF | kubectl apply -f -
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
 name: aws-sqs-queue-scaledobject
 namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1 # Opcional. Default: apps/v1
    kind: Deployment  # Opcional. Default: Deployment
    name: web      # Mandatório. Deve estar no mesmo namespace desse ScaledObject
  pollingInterval: 5  # Intervalo de polling
  cooldownPeriod: 10 # Opcional. Default 300s
  idleReplicaCount: 0  # Opcional. Quando ociosa, escala para 0 pod.
  minReplicaCount: 0 # Opcional. Default 0
  maxReplicaCount: 3 # Opcional. Default 100
  fallback:  # Opcional. Estratégia de Fallback qdo métricas ñ disp.
    failureThreshold: 5 # se métricas indisp., mantém a qtd. de réplicas abaixo
    replicas: 2  # item acima
  triggers:
  - type: aws-sqs-queue
    authenticationRef:
      name: keda-trigger-auth-aws-credentials  # Autenticação que aponta o acesso à AWS
    metadata:
      queueURL: https://sqs.us-east-2.amazonaws.com/12345678909/my-sqs-keda
      queueLength: "5"  
      awsRegion: "us-east-2"
EOF
cat <<EOF | kubectl apply -f -
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
  name: keda-trigger-auth-aws-credentials
  namespace: default
spec:
  secretTargetRef:
  - parameter: awsAccessKeyID     # Required.
    name: test-secrets            # Required.
    key: AWS_ACCESS_KEY_ID        # Required.
  - parameter: awsSecretAccessKey # Required.
    name: test-secrets            # Required.
    key: AWS_SECRET_ACCESS_KEY    # Required.
EOF
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: test-secrets
  Namespace: default
data:
  AWS_ACCESS_KEY_ID: <encoded-user-id> # Required.
  AWS_SECRET_ACCESS_KEY: <encoded-key> # Required.
EOF

O KEDA suporta para o tipo ScaledObjects: Deployments, StatefulSets ou CustomResources como um ArgoRollout por exemplo.

Vamos explicar o ScaledObject acima:

1- O ScaledObject vai ser criado no namespace default.

2- Ele vai gerenciar as réplicas do Deployment ‘web’.

3 – A fonte de eventos vai ser uma AWS SQS com a fila https://sqs.us-east-2.amazonaws.com/12345678909/my-sqs-keda na região us-east-2.

4- O tamanho da fila que dispara a escalada é 5, ou seja, chegou em 5, aumenta 1 pod, isso a cada 5 mensagens represadas.

5- o idleReplicaCount é 0, isso reduz para 0 pods caso a fila esteja vazia.

6- Fallback habilitado, significa se houver falha na obtenção do tamanho da fila será mantida 2 réplicas em execução.

7- O triggerAuthentication é a maneira como esse ScaledObject obterá acesso a fila SQS, que por sua vez faz referência a uma secret com credenciais AWS. Pensando em segurança isso não é a melhor maneira, há como utilizar IAM Role e atribuir a nodes ou a serviceAccount no cluster, como documentado aqui.

Por fim, a criação do ScaledObject, cria um objeto HPA ‘filho’ que controla a quantidade de pods baseados na seção triggers.

Hora da ação!

1 – Observe seu deployment web

kubectl get deployments web -n default --watch
NAME       READY   UP-TO-DATE   AVAILABLE   AGE
web        0/0     0            0           4h52m

2 – Adicione algumas mensagens na fila, mais de 5 para ver escalar os pods;

Resultado: O KEDA vai escalar seus pods

kubectl get deployments web -n default --watchNAME  READY   UP-TO-DATE   AVAILABLE   AGE
Web   0/0     0            0           4h52m
web   0/1     0            0           4h54m
web   0/1     0            0           4h54m
web   0/1     0            0           4h54m
web   0/1     1            0           4h54m
web   1/1     1            1           4h54m
web   1/2     1            1           4h54m
web   1/2     1            1           4h54m
web   1/2     1            1           4h54m
Web   1/2     2            1           4h54m
Web   2/2     2            2           4h54m

Depois que fica ociosa a fila, seu deploy será escalado para 0 automaticamente.

Conclusão

Vimos como o KEDA cria o HPA e atua nele diretamente escalando os pods, isso pode ser observado nos eventos do namespace e na descrição do hpa:

kubectl get events -n default
LAST SEEN   TYPE     REASON              OBJECT                                                        MESSAGE
23s         Normal   SuccessfulRescale   horizontalpodautoscaler/keda-hpa-aws-sqs-queue-scaledobject   New size: 2; reason: external metric s0-aws-sqs-my-sqs-keda(&LabelSelector{MatchLabels:map[string]string{scaledobject.keda.sh/name: aws-sqs-queue-scaledobject,},MatchExpressions:[]LabelSelectorRequirement{},}) above target
68s         Normal   Killing             pod/web-68bdbdcb94-48c54                                      Stopping container nginx
23s         Normal   Scheduled           pod/web-68bdbdcb94-d9hql                                      Successfully assigned default/web-68bdbdcb94-d9hql to demo-worker3
23s         Normal   Pulling             pod/web-68bdbdcb94-d9hql                                      Pulling image "nginx"
22s         Normal   Pulled              pod/web-68bdbdcb94-d9hql                                      Successfully pulled image "nginx" in 1.196212139s
22s         Normal   Created             pod/web-68bdbdcb94-d9hql                                      Created container nginx
21s         Normal   Started             pod/web-68bdbdcb94-d9hql                                      Started container nginx
39s         Normal   Scheduled           pod/web-68bdbdcb94-lnsjj                                      Successfully assigned default/web-68bdbdcb94-lnsjj to demo-worker4
38s         Normal   Pulling             pod/web-68bdbdcb94-lnsjj                                      Pulling image "nginx"
33s         Normal   Pulled              pod/web-68bdbdcb94-lnsjj                                      Successfully pulled image "nginx" in 5.913160223s
33s         Normal   Created             pod/web-68bdbdcb94-lnsjj                                      Created container nginx
32s         Normal   Started             pod/web-68bdbdcb94-lnsjj                                      Started container nginx
68s         Normal   SuccessfulDelete    replicaset/web-68bdbdcb94                                     Deleted pod: web-68bdbdcb94-48c54
39s         Normal   SuccessfulCreate    replicaset/web-68bdbdcb94                                     Created pod: web-68bdbdcb94-lnsjj
23s         Normal   SuccessfulCreate    replicaset/web-68bdbdcb94                                     Created pod: web-68bdbdcb94-d9hql
39s         Normal   ScalingReplicaSet   deployment/web                                                Scaled up replica set web-68bdbdcb94 to 1
68s         Normal   ScalingReplicaSet   deployment/web                                                Scaled down replica set web-68bdbdcb94 to 0
23s         Normal   ScalingReplicaSet   deployment/web                                                Scaled up replica set web-68bdbdcb94 to 2
kubectl describe hpa 
Name:                                               keda-hpa-aws-sqs-queue-scaledobject
Namespace:                                          default
Labels:                                             app.kubernetes.io/managed-by=keda-operator
                                                    app.kubernetes.io/name=keda-hpa-aws-sqs-queue-scaledobject
                                                    app.kubernetes.io/part-of=aws-sqs-queue-scaledobject
                                                    app.kubernetes.io/version=2.9.1
                                                    scaledobject.keda.sh/name=aws-sqs-queue-scaledobject
Annotations:                                        <none>
CreationTimestamp:                                  Tue, 03 Jan 2023 10:17:30 -0300
Reference:                                          Deployment/web
Metrics:                                            ( current / target )
  "s0-aws-sqs-my-sqs-keda" (target average value):  3 / 5
Min replicas:                                       1
Max replicas:                                       3
Deployment pods:                                    2 current / 2 desired
Conditions:
  Type            Status  Reason              Message
  ----            ------  ------              -------
  AbleToScale     True    ReadyForNewScale    recommended size matches current size
  ScalingActive   True    ValidMetricFound    the HPA was able to successfully calculate a replica count from external metric s0-aws-sqs-my-sqs-keda(&LabelSelector{MatchLabels:map[string]string{scaledobject.keda.sh/name: aws-sqs-queue-scaledobject,},MatchExpressions:[]LabelSelectorRequirement{},})
  ScalingLimited  False   DesiredWithinRange  the desired count is within the acceptable range
Events:
  Type    Reason             Age   From                       Message
  ----    ------             ----  ----                       -------
  Normal  SuccessfulRescale  34s   horizontal-pod-autoscaler  New size: 2; reason: external metric s0-aws-sqs-my-sqs-keda(&LabelSelector{MatchLabels:map[string]string{scaledobject.keda.sh/name: aws-sqs-queue-scaledobject,},MatchExpressions:[]LabelSelectorRequirement{},}) above target

Usamos como objeto externo uma fila SQS na AWS, mas pode ser qualquer sistema ou aplicação que gere alguma métrica que possa ser coletada, inclusive via o Prometheus instalado em seu cluster recebendo métricas desse mesmo tipo de aplicações internas e externas ao cluster. Também fiz um Lab bem prático aqui no blog ano passado: https://gtup.me/kubilab-keda01 

Referencias

https://blog.getup.io

https://keda.sh

https://kubernetes.io

Já assinou a nossa Newsletter?

Encontre oportunidades na Jornada Kubernetes

O Kubernetes já faz muito por você e a Getup faz o resto. Oferecemos apoio técnico e estratégico para encontrar oportunidades na sua operação.