Escalando aplicações automaticamente no Kubernetes usando KEDA

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.
Alt Text
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 e maxReplicaCount. 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 para true. 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:
    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 )
  • 38

    This website collects cookies to deliver better user experience

    Escalando aplicações automaticamente no Kubernetes usando KEDA