Para quem ainda não conhece o KEDA (Kubernetes Event-Driven Autoscaling), é:
Um componente leve e de finalidade única que pode ser adicionado a qualquer cluster do Kubernetes. Funciona junto com componentes Kubernetes padrão, como o Horizontal Pod Autoscaler (HPA) e pode estender a funcionalidade sem sobrescrever ou duplicação.
Retirado da documentação oficial
Foi lançado no fim de 2019 (anúncio oficial) e é fruto de uma parceria entre Microsoft & Red Hat.
E ele cumpre bem o lema, que é: “Application autoscaling made simple”.
Nativamente o Kubernetes só permite configurar HPA com as métricas de CPU e memória.
Se quiser escalar as aplicações utilizando outro tipo de métrica, por exemplo, lags de eventos ou filas, você precisa primeiro criar um adaptador de métricas (custom metrics) para extrair as métricas da fonte desejada. Entretanto se precisar obter métricas de várias fontes usando vários adaptadores, você está sem sorte porque apenas um por vez é compatível (a menos que tenha mudado recentemente).
Já o KEDA extrai de uma variedade de fontes e dimensiona automaticamente suas implantações de 0
a N-instâncias
com base em sua configuração no ScaledObject.
Outro ponto interessante é que o KEDA não “reinventa a roda” e não construiu seu próprio mecanismo de escalonamento, se aproveitando de HPAs do Kubernetes e dos secrets (TriggerAuthentication) já usados pelas aplicações.
INSTALANDO O KEDA
As instruções para implantar o KEDA são muito simples e podem ser encontradas aqui.
Existem três maneiras de implantar KEDA em seu cluster Kubernetes:
- Helm charts
- Operator Hub
- Implantar YAMLs
Vamos usar a primeira opção.
helm repo add kedacore https://kedacore.github.io/charts
helm repo update
kubectl create ns keda
helm install keda kedacore/keda --namespace keda
Após a instalação teremos 2 deployments (KEDA Operator e KEDA Metrics API) rodando no cluster…
kubectl get deployment -n keda
NAME READY UP-TO-DATE AVAILABLE AGE
keda-operator 1/1 1 1 1h
keda-operator-metrics-apiserver 1/1 1 1 1h
e mais alguns CRDs disponíveis:
kubectl api-resources --api-group=keda.sh
NAME SHORTNAMES APIGROUP NAMESPACED KIND
scaledjobs sj keda.sh true ScaledJob
scaledobjects so keda.sh true ScaledObject
triggerauthentications ta,triggerauth keda.sh true TriggerAuthentication
ScaledJobs*/ScaledObject: Os ScaledJobs/ScaledObjects mapeiam uma fonte de evento para a jobs/deployments que você deseja dimensionar.
TriggerAuthentication: Se necessário, este recurso contém a configuração de autenticação necessária para monitorar a origem do evento.
O "ScaledObject" também cria o HPA para você.
- O KEDA não apenas dimensiona deployments, mas também pode dimensionar seus jobs do Kubernetes. Em vez de ter muitos eventos processados em sua implantação e aumentar ou diminuir com base no número de mensagens que precisam ser consumidas, o KEDA pode ativar um trabalho para cada mensagem na origem do evento.
EXEMPLO COM KAFKA
Vamos dar uma olhada mais de perto no ScaledObject e Kafka trigger.
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: kafka-consumer-scaler
labels:
deploymentName: my-kafka-consumer-service
namespace: sample
spec:
scaleTargetRef:
deploymentName: my-kafka-consumer-service
pollingInterval: 1 # Optional. Default: 30 seconds
cooldownPeriod: 30 # Optional. Default: 300 seconds
minReplicaCount: 0 # Optional. Default: 0
maxReplicaCount: 10 # Optional. Default: 100
triggers:
- type: kafka
metadata:
topic: test-topic-1
# brokerList: my-cluster-kafka-bootstrap.kafka:9092 - deprecated
bootstrapServers: my-cluster-kafka-bootstrap.kafka:9092
consumerGroup: my-kafka-consumerGroup
lagThreshold: '5' # Default: 10
offsetResetPolicy: latest
allowIdleConsumers: false
authenticationRef:
name: keda-trigger-auth-kafka-credential
## Optional: list of topics to trigger
#- type: kafka
# metadata:
# topic: test-topic-2
# bootstrapServers: my-cluster-kafka-bootstrap.kafka:9092
# consumerGroup: my-kafka-consumerGroup
# lagThreshold: '5' # Default: 10
# offsetResetPolicy: latest
# allowIdleConsumers: false
# authenticationRef:
# name: keda-trigger-auth-kafka-credential
O ScaledObject, TriggerAuthentication e a implantação referenciada em deploymentName precisam estar no mesmo namespace.
- Apesar de serem valores opcionais, é importante definir valores dentro dos padrões para seu negócio nos parâmetros
minReplicaCount
emaxReplicaCount
. Para evitar rebalanceamento de partições no Kafka E/OU evitar que muitos pods sejam iniciados - consumindo todos os recursos do cluster 💥. - O parâmetro
offsetResetPolicy
pode ser earliest ou latest. Como o KEDA vai percorrer todos os tópicos, vale a pena entender como o código (negócio) se comporta com duplicidade de eventos.
Por padrão, o número de réplicas não excederá o número de partições em um tópico. Ou seja, se maxReplicaCount for definido mais do que o número de partições, o escalonador não vai atingir o valor definido. Caso queira mudar este comportamento, ajuste o parâmetro
allowIdleConsumers
paratrue
. Porém, se houver mais número de consumidores do que número de partições em um tópico, o consumidor extra terá que ficar ocioso.
Para facilitar criamos um usuário no Kafka com permissão de somente leitura (list
e describe
) em todos os grupos e tópicos e referenciamos no TriggerAuthentication o secret com este usuário:
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
name: keda-trigger-auth-kafka-credential
namespace: sample
spec:
secretTargetRef:
- key: sasl
name: keda-credentials
parameter: sasl
- key: username
name: keda-credentials
parameter: username
- key: password
name: keda-credentials
parameter: password
REFERÊNCIAS:
https://keda.sh/docs/2.3/
https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
https://cloudblogs.microsoft.com/opensource/2020/04/06/kubernetes-event-driven-autoscaling-keda-cncf-sandbox-project/
https://keda.sh/resources/
AGRADECIMENTOS
Obrigado à todos os envolvidos que me incentivaram a escrever este artigo e revisaram o texto:
- Felipe Lamarão Silva (@lipekis)
- Willian Itiho (@Willian_Itiho)
- Rafael Gomes (@gomex)
Top comments (5)
Trabalho muito bacana mesmo. Sou testemunha disso, ontem mesmo fiz um deploy em produção de uma app que consome um tópico bem pesado do kafka e pude ver o keda em ação escalando os pods baseado no lagThreshold definido.
Excelente artigo, obrigado por compartilhar.
Tenho uma dúvida, em um cenário que exista vários consumer groups e vários tópicos ou um consumer group e vários tópicos será necessário criar diversas triggers?
Obrigado @erthalmvp !
Se entendi bem seu exemplo, será necessário sim. Pois o lag é baseado no grupo e tópico.
muito bom Will
Sensacional Will!
Parabéns pelo conteúdo <3