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