KEDA: escalonamento de workloads baseado em eventos no Kubernetes

1. Fundamentos do KEDA: O que é e por que surgiu?

1.1. Limitações do HPA tradicional no Kubernetes

O Horizontal Pod Autoscaler (HPA) nativo do Kubernetes é uma ferramenta poderosa, mas possui limitações significativas quando o assunto é escalonamento baseado em eventos. O HPA tradicional depende exclusivamente de métricas de recursos (CPU e memória) ou métricas customizadas expostas por APIs internas do cluster. Isso significa que ele não consegue reagir diretamente a eventos externos, como mensagens em filas, streams de dados ou mudanças em sistemas de armazenamento.

Por exemplo, se você tem uma aplicação que processa mensagens de uma fila RabbitMQ, o HPA só conseguirá escalar depois que a CPU ou memória dos pods já estiverem elevadas, o que introduz latência e ineficiência no processo.

1.2. Definição e arquitetura básica do KEDA

KEDA (Kubernetes Event-Driven Autoscaling) é um operador de código aberto que estende o Kubernetes para permitir escalonamento baseado em eventos de fontes externas. Sua arquitetura é composta por três elementos principais:

  • ScaledObject: Recurso customizado que define como escalar um Deployment com base em eventos
  • Scaler: Componente que se conecta a fontes de eventos externas (filas, bancos, APIs)
  • Operator: Controlador que gerencia o ciclo de vida dos ScaledObjects e interage com o HPA

O KEDA atua como um intermediário entre as fontes de eventos e o HPA nativo, traduzindo métricas externas em métricas que o HPA pode consumir.

1.3. Casos de uso típicos

Os cenários mais comuns incluem processamento de filas de mensagens (RabbitMQ, Kafka, SQS), streams de dados em tempo real, processamento de arquivos em buckets S3, workloads baseados em métricas do Prometheus e integrações com bancos de dados como PostgreSQL e Redis.

2. Componentes e Arquitetura Interna do KEDA

2.1. O operador KEDA e o controlador de reconciliação

O operador KEDA é implantado como um Deployment no namespace keda. Ele contém um controlador de reconciliação que monitora constantemente os recursos ScaledObject e ScaledJob, ajustando o número de réplicas conforme necessário. O operador também expõe métricas para o Prometheus, permitindo monitoramento detalhado.

2.2. ScaledObjects e ScaledJobs

  • ScaledObject: Projetado para escalar Deployments e StatefulSets. Ideal para workloads contínuos que precisam aumentar ou diminuir réplicas com base em eventos.
  • ScaledJob: Projetado para escalar Jobs. Útil para tarefas batch que precisam ser executadas em resposta a eventos, como processamento de arquivos ou limpeza de dados.

2.3. Gatilhos e a interface de scalers

Os triggers (gatilhos) definem qual fonte de evento será monitorada. Cada trigger utiliza um scaler específico que implementa uma interface padronizada para coletar métricas. O KEDA atualmente suporta mais de 50 scalers diferentes, incluindo:

- aws-sqs-queue
- rabbitmq
- kafka
- prometheus
- postgresql
- redis
- cron
- http

3. Instalação e Configuração Inicial do KEDA no Cluster

3.1. Instalação via Helm

A forma mais simples de instalar o KEDA é através do Helm:

helm repo add kedacore https://kedacore.github.io/charts
helm repo update
helm install keda kedacore/keda --namespace keda --create-namespace

3.2. Configuração de permissões RBAC

O KEDA precisa de permissões específicas para escalar deployments e acessar fontes externas. Um exemplo de ClusterRole necessário:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: keda-operator
rules:
- apiGroups: ["keda.sh"]
  resources: ["scaledobjects", "scaledjobs"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
  resources: ["deployments", "statefulsets"]
  verbs: ["get", "list", "watch", "update", "patch"]

3.3. Verificação de funcionamento

Após a instalação, verifique se o operador está ativo:

kubectl get pods -n keda
kubectl logs -n keda deployment/keda-operator

O operador deve exibir logs indicando que está pronto para reconciliar recursos.

4. Scalers Essenciais: Integração com Fontes de Eventos

4.1. Scalers para filas de mensagens

O scaler RabbitMQ é um dos mais utilizados. Ele se conecta a uma fila específica e conta o número de mensagens pendentes:

triggers:
- type: rabbitmq
  metadata:
    protocol: amqp
    queueName: tasks
    host: amqp://guest:guest@rabbitmq-service:5672/
    queueLength: '10'

4.2. Scalers para bancos de dados

O scaler PostgreSQL permite escalar com base em consultas SQL:

triggers:
- type: postgresql
  metadata:
    connection: postgresql://user:pass@postgres-service:5432/db
    query: "SELECT COUNT(*) FROM pending_orders WHERE status = 'pending'"
    targetQueryValue: "5"

4.3. Scalers HTTP e métricas customizadas

O scaler Prometheus permite usar qualquer métrica exposta pelo Prometheus:

triggers:
- type: prometheus
  metadata:
    serverAddress: http://prometheus-server.monitoring.svc:9090
    query: sum(rate(http_requests_total[1m]))
    threshold: '100'

5. Criação de ScaledObjects na Prática

5.1. Exemplo com RabbitMQ

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: rabbitmq-scaledobject
  namespace: default
spec:
  scaleTargetRef:
    name: message-processor
  minReplicaCount: 1
  maxReplicaCount: 10
  pollingInterval: 30
  cooldownPeriod: 300
  triggers:
  - type: rabbitmq
    metadata:
      protocol: amqp
      queueName: tasks
      host: amqp://guest:guest@rabbitmq-service:5672/
      queueLength: '10'

5.2. Exemplo com Prometheus

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: prometheus-scaledobject
  namespace: default
spec:
  scaleTargetRef:
    name: web-app
  minReplicaCount: 2
  maxReplicaCount: 20
  pollingInterval: 15
  cooldownPeriod: 120
  triggers:
  - type: prometheus
    metadata:
      serverAddress: http://prometheus-server.monitoring.svc:9090
      query: sum(rate(http_requests_total{status="5xx"}[1m]))
      threshold: '5'

5.3. Parâmetros importantes

  • minReplicaCount: Número mínimo de réplicas (padrão: 1)
  • maxReplicaCount: Número máximo de réplicas (padrão: 100)
  • pollingInterval: Intervalo em segundos para verificar a fonte de evento (padrão: 30)
  • cooldownPeriod: Tempo em segundos antes de reduzir réplicas (padrão: 300)

6. ScaledJobs: Execução de Tarefas Baseadas em Eventos

6.1. Diferença entre ScaledObject e ScaledJob

Enquanto ScaledObject escala Deployments (que mantêm pods rodando continuamente), ScaledJob escala Jobs (que executam tarefas e terminam). ScaledJob é ideal para workloads batch como processamento de arquivos, geração de relatórios ou limpeza de dados.

6.2. Exemplo prático com S3

apiVersion: keda.sh/v1alpha1
kind: ScaledJob
metadata:
  name: s3-processor-job
  namespace: default
spec:
  jobTargetRef:
    template:
      spec:
        containers:
        - name: processor
          image: myapp/s3-processor:latest
          env:
          - name: S3_BUCKET
            value: my-input-bucket
        restartPolicy: Never
  pollingInterval: 30
  maxReplicaCount: 10
  successfulJobsHistoryLimit: 5
  failedJobsHistoryLimit: 3
  triggers:
  - type: aws-s3
    metadata:
      bucketName: my-input-bucket
      bucketPrefix: incoming/
      targetObjectCount: '1'

6.3. Estratégias de retry e paralelismo

ScaledJob suporta configurações avançadas de Jobs, como backoffLimit e parallelism:

spec:
  jobTargetRef:
    backoffLimit: 3
    parallelism: 5
    completions: 10

7. Boas Práticas, Monitoramento e Troubleshooting

7.1. Monitoramento com Prometheus e Grafana

O KEDA expõe métricas importantes como:

keda_scaler_errors_total
keda_scaled_object_current_replica_count
keda_scaled_object_desired_replica_count
keda_scaled_object_polling_count

Crie dashboards no Grafana para visualizar o comportamento de escalonamento em tempo real.

7.2. Debugando ScaledObjects

Para depurar problemas, verifique os eventos do ScaledObject:

kubectl describe scaledobject rabbitmq-scaledobject
kubectl get events --field-selector involvedObject.name=rabbitmq-scaledobject
kubectl logs -n keda deployment/keda-operator

7.3. Dicas de performance

  • Ajuste pollingInterval para evitar consultas excessivas a fontes externas
  • Use cooldownPeriod adequado para evitar flutuações bruscas
  • Configure limites de cache de métricas no operador
  • Monitore o consumo de recursos do operador KEDA

Referências