Instalando o Locust no Kubernetes para testes de carga

Locust é uma ferramenta de código fonte aberto usada para fazer testes de desempenho/carga no protocolo HTTP e outros.

Os testes do Locust podem ser executados a partir da linha de comando ou usando sua interface web. A taxa de transferência, os tempos de resposta e os erros podem ser visualizados em tempo real e/ou exportados para análise posterior.

O Locust permite a escrita e execução de códigos e bibliotecas Python para a execução dos testes, simulando usuários interagindo com o site.

Um caso de uso no Kubernetes é usar Locust para testar a carga de uma aplicação web (backend ou frontend) para estudar o comportamento e o scaling gerenciados pelo Horizontal Pod Autoscaling (HPA), o Keda ou Knative.

Requisitos

  1. Neste tutorial, usaremos o Kind para simular um cluster Kubernetes rodando localmente. Se você tiver acesso a cluster on-premisse ou gerenciado na cloud pelo EKS, GKE, AKS, DKS ou outro, pode ignorar o uso do kind.
  2. Também será necessário o uso do Docker, kubectl, git e helm. Esses softwares podem ser instalados seguindo o tutorial disponível em: https://github.com/aeciopires/adsoft/blob/master/REQUIREMENTS.md

Instalando uma aplicação de teste

  • / => Exibe o nome do host, o nome da interface e os endereços IP;
  • /health => Exibe o status da aplicação;
  • /metrics => Exibe as métricas no formato suportado pelo Prometheus;
  • /env => Exibe as variáveis ​​de ambiente;
  • /css => Exibe o modelo CSS;
kubectl create namespace test
cd /tmp

git clone https://gitlab.com/aeciopires/kube-pires.git

cd kube-pires/helm-chart/

helm upgrade --install kube-pires -f values.yaml . -n test --create-namespace

Instalação do Locust via helm

helm repo add deliveryhero https://charts.deliveryhero.io

helm repo update
cd /tmp

git clone https://github.com/deliveryhero/helm-charts.git
nano /tmp/helm-charts/stable/locust/locustfiles/example/main.py
from locust import HttpUser, TaskSet, task, between
import random

class SiteUser(HttpUser):
    # Define a taxa de "spawn" de usuários entre 1 e 5 segundos (com base na frequência de geração dos usuários)
    # Configura o intervalo de tempo entre as requisições que cada usuário simulado vai fazer.
    # O valor between(1, 5) significa que o Locust irá esperar entre 1 e 5 segundos entre as requisições feitas.
    wait_time = between(1, 5)
    
    # Define as páginas que serão acessadas durante o teste de carga.
    pages = [
        "http://kube-pires.test.cluster.local/metrics",
        "http://kube-pires.test.cluster.local/health",
        "http://kube-pires.test.cluster.local/env",
    ]

    # Este método simula o acesso à página principal
    @task(1)
    def load_home_page(self):
        """Acessa a página inicial"""
        self.client.get("http://kube-pires.test.cluster.local/")
    
    # Este método acessa páginas aleatórias dentro da lista pages para simular a navegação do usuário.
    @task(2)
    def browse_pages(self):
        """Acessa uma página aleatória"""
        page = random.choice(self.pages)
        self.client.get(page)

class WebsiteUser(HttpUser):
    tasks = [SiteUser]  # Aqui é especificado que os usuários simulados irão realizar as tarefas da classe SiteUser
    min_wait = 1000  # Tempo mínimo de espera entre as requisições
    max_wait = 2000  # Tempo máximo de espera entre as requisições

Altere o nome do namespace na variável $MYNAMESPACE de acordo com o ambiente.

export MYNAMESPACE="test"

kubectl create namespace $MYNAMESPACE

kubectl -n $MYNAMESPACE create configmap my-loadtest-locustfile --from-file /tmp/helm-charts/stable/locust/locustfiles/example/main.py
kubectl -n $MYNAMESPACE create configmap my-loadtest-lib --from-file /tmp/helm-charts/stable/locust/locustfiles/example/lib/
kubectl get configmap -n $MYNAMESPACE

Como neste caso, eu só preciso alterar alguns poucos valores, vou ignorar o uso do arquivo values.yaml e configurar algumas coisas usando o parâmetro --set do helm.

O paramêtro --set worker.replicas determina quantos pods work do locust serão instanciados no teste. Neste caso, estarei usando 10. Isso afeta diretamente nos resultados dos testes. Cada worker tende a usar 1 CPU inteira. Poucos workers pode dar a impressão que sua aplicação é lenta ou não aguenta uma carga alta de requisições, mas na verdade pode ser o Locust não conseguindo fazer mais requisições paralelas. Por isso é importante aumentar esse valor para descobrir o limite real de requisições simultâneas que a aplicação suporta.

Com os configmap criados no cluster, execute o seguinte comando para instalar o locust:

LOCUST_VERSION="2.33.2"
CHART_VERSION="0.31.6"

helm -n $MYNAMESPACE upgrade --install locust deliveryhero/locust \
  --set image.tag=$LOCUST_VERSION \
  --set loadtest.name=my-loadtest \
  --set loadtest.locust_locustfile_configmap=my-loadtest-locustfile \
  --set loadtest.locust_lib_configmap=my-loadtest-lib \
  --set worker.replicas=10 \
  --version $CHART_VERSION \
  --debug --timeout=900s
kubectl -n $MYNAMESPACE port-forward service/locust 8089:8089

Imagem 1 – Gráficos de desempenho no Locust

Audiodescrição: A imagem exibe três gráficos:

Começa em 0 e vai até 50 usuários em questão de segundos.

Total Requests per Second (RPS):

  • Um gráfico de linha mostrando o número de requisições por segundo em vermelho.
  • A linha mostra crescimento constante até cerca de 8 requisições por segundo.
  • O gráfico também mostra 100% de falhas (linha vermelha constante).

Response Times (ms):

  • Gráfico com duas linhas:
  • Laranja: 50º percentil (tempo de resposta mediano).
  • Roxo: 95º percentil (tempo de resposta dos piores 5%).
  • Mostra aumento gradual dos tempos, com o 95º percentil chegando a cerca de 16 ms.

Number of Users:

  • Linha azul representando o número de usuários virtuais.

Imagem 2 – Estatísticas detalhadas por rota

Audiodescrição: A imagem mostra uma tabela com dados estatísticos sobre as requisições feitas:

  • Cada linha corresponde a uma rota HTTP testada: /, /env, /health e /metrics.
  • Para cada rota, são mostradas as seguintes informações:
    • # Requests: Total de requisições feitas.
    • # Fails: Total de falhas (todas as requisições falharam, 100% de falhas).
    • Median (ms): Mediana do tempo de resposta (3 ms para todas).
    • 95%ile / 99%ile: Percentis 95 e 99 do tempo de resposta.
    • Average / Min / Max (ms): Média, mínimo e máximo tempo de resposta.
    • Current RPS: Requisições por segundo por rota.
    • Current Failures/s: Falhas por segundo por rota.

No topo da tela aparecem os dados globais do teste:

Alterações no script do Locust

kubectl -n $MYNAMESPACE delete configmap my-loadtest-locustfile
nano /tmp/helm-charts/stable/locust/locustfiles/example/main.py

kubectl -n $MYNAMESPACE create configmap my-loadtest-locustfile --from-file /tmp/helm-charts/stable/locust/locustfiles/example/main.py
kubectl rollout restart deployment/locust-master -n $MYNAMESPACE

Removendo os configmaps

kubectl -n $MYNAMESPACE delete configmap my-loadtest-lib my-loadtest-locustfile

Removendo o locust

helm -n $MYNAMESPACE uninstall locust

Locust por linha de comando

NAMESPACE="CHANGE HERE"

# Descobrir o nome do pod locust
kubectl get pod -n $MYNAMESPACE

POD_NAME="CHANGE HERE"

# Acessar o pod do locust
kubectl exec -it pod/$POD_NAME -n $MYNAMESPACE -- bash
ParâmetrosDescrição
-uQuantidade de usuários
-rQuantidade de usuários que são iniciados por segundo (ramp up)
-tDuração do teste
--headlessSem cabeçalho na requisição
--htmlGera um relatório em html
--csvExporta os dados em CSV
--hostHost alvo dos testes

Exemplo:

locust -f main.py --headless -u 800 -r 800 -t 5m --html report.html --csv dados.csv --host
POD_NAME="CHANGE HERE"
NAMESPACE="CHANGE HERE"
LOCAL_DIR="CHANGE HERE" # Local que deseja armazenar o relatório do teste executado

kubectl cp $POD_NAME:/home/locust/dados.csv /$LOCAL_DIR/ -n $MYNAMESPACE

Referências

Categories: , , , , ,

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *