Mateus Müller

O carinha do Linux

19 set. 2022

KEDA: Autoscaling para Kubernetes usando AWS SQS

O KEDA é um projeto que está abaixo do guarda-chuva da CNCF, que visa basicamente trazer a possibilidade de escalar pods baseado em eventos.

Mas por que isso? Nem todas as aplicações devem ser escaladas baseado em utilização de CPU. A depender da arquitetura da aplicação, faz muito mais sentido escalar com base no tamanho da fila (SQS, RabbitMQ, NATS, etc).

Neste post, vamos fazer a configuração de um cluster Kubernetes, deployar o KEDA e dar uma brincada com ele!

Criação do EKS

Se você já tem um cluster aí para testar, pode pular essa parte!

Deixei tudo no meu GitHub, então dá pra você baixar tudo direitinho e modificar o que achar necessário.

Basicamente, vai deployar a stack de rede, EKS e um Managed Node Group com 1 Node.

$ git clone https://github.com/mateusmuller/mateusmullerme-youtube
$ cd mateusmullerme-youtube/kubernetes/01_keda/eks
$ terraform init
$ terraform plan
$ terraform apply

Ah, não esqueça de atualizar o kubeconfig.

$ aws eks update-kubeconfig --name eks-demo --region us-east-1

Criação da IAM role e Service Account

Caso você ainda não conheça, o EKS tem um recurso bem bacana chamado de IAM roles for service accounts, que basicamente permite criar uma IAM role específica para um pod, sem a necessidade de atribuir alguma permissão ao nível do node.

Dessa forma, o que vamos fazer aqui é:

  1. Criar uma policy que dará permissão ao KEDA de acessar a fila SQS.
  2. Criar a IAM Role e Service Account.

Então vamos lá!

$ cat > sqs.json <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sqs:GetQueueAttributes",
            "Resource": "<ARN da fila>"
        }
    ]
}
EOF

Com isso, você terá um arquivo sqs.json que dará permissão de fazer uma GetQueueAttributes naquela fila SQS específica.

$ aws iam create-policy --policy-name keda-sqs \
  --policy-document file://sqs.json

PS: Anote o ARN da policy!

Vamos criar a namespace.

$ kubectl create ns keda

E por fim, vamos usar o eksctl para criar a IAM role e Service Account (mais fácil rsrs).

$ eksctl create iamserviceaccount --name keda-operator \
  --namespace keda \
  --cluster <Cluster> \
  --attach-policy-arn <Policy ARN> \
  --region <Regiao> \
  --approve

E prontinho! Agora você tem uma Service Account chamada keda-operator na namespace keda que tem permissões de ler a fila SQS.

Isso quer dizer que basta deployar o KEDA e mandar usar essa Service Account.

Deploy do KEDA

Aqui tem a documentação de deploy. Eu optei pelo Helm porque acho mais prático e mais fácil de manter.

PS: O segredo tá em não deixar o Helm criar a Service Account, mas sim reusar a que criamos.

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

$ helm install keda kedacore/keda --namespace keda \
  --set serviceAccount.create=false \
  --set serviceAccount.name=keda-operator

Logo você verá dois pods na namespace keda. Assim que ambos estiverem em Running, podemos começar.

Demo com KEDA

Bom, você pode criar um arquivo YAML com o seguinte conteúdo:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx-deployment
spec:
  replicas: 0
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
---
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: aws-sqs-queue-scaledobject
  namespace: default
spec:
  scaleTargetRef:
    name: nginx-deployment
  minReplicaCount: 0
  maxReplicaCount: 5
  pollingInterval: 5
  cooldownPeriod:  25
  triggers:
  - type: aws-sqs-queue
    metadata:
      queueURL: <URL da fila>
      queueLength: "10"
      awsRegion: "<Regiao>"
      identityOwner: operator

O deployment é simplesmente um NGINX com 0 replicas. Vamos deixar o KEDA fazer o trampo.

Já o ScaledObject é justamente a configuração específica da integração entre o KEDA e o produto que vai prover os dados para escalar. Neste caso, o AWS SQS!

Vamos dar uma olhada nos parâmetros do spec.

  • minReplicaCount - Se não tiver nada no SQS, mantém 0 replicas.
  • maxReplicaCount - Pode escalar ao máximo em 5 replicas.
  • pollingInterval - Buscar informações da fila de 5 em 5 segundos.
  • cooldownPeriod - Esperar 25 segundos para fazer o scale-in (remover replicas).

Posteriormente, em metadata, é onde a mágica acontece.

  • queueLength - Quantas mensagens cada pod consegue processar? Por exemplo, se cada pod consegue processar 10 mensagens, sete o valor para 10. Se você tiver 30 mensagens na fila, haverão 3 pods processando as requisições.
  • identityOwner - Como será feito a autenticação e autorização? Neste caso, estamos dizendo para reusar a IAM role do pod operator.

Pode aplicar o YAML com:

$ kubectl apply -f <arquivo.yaml>

E basta, então, encher de mensagens na fila. Com o comando abaixo você vai enviar 50 mensagens para a fila.

for i in `seq 50`; do 
  aws sqs send-message --queue-url '<URL da fila>' \
    --message-body "XXXX" \
    --region <Regiao> \
    --no-cli-pager \
    --output text
done

Se você definiu o queueLength como 10, haverão 5 pods.

Lembrando que assim que finalizar, pode destruir o cluster Kubernetes com:

$ terraform apply -destroy

Espero que tenham gostado dessa dica. O que acham de fazer uns testes com mais ferramentas da CNCF? :)

Buy me a coffeeBuy me a coffee
Comentários Disqus