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 é:
- Criar uma policy que dará permissão ao KEDA de acessar a fila SQS.
- 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 podoperator
.
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 coffee