Skip to main content

HPA e VPA - Autoscaler

Autoscaling deploy (Horizontal e Vertical)
  • Criar uma aplicação básica
  • Escalar a aplicação usando Horizontal Pod Autoscaler (HPA)
  • Escalar a aplicação usando Vertical Pod Autoscaler (HPA)
  • Teste de desempenho usando o Locust
Topologia do Laboratório:

image.png

Estrutura inicial

1) Criando o diretório dos arquivos .yaml de deployment dos Pods.

mkdir ~/scaler && cd ~/scaler

2) Instalando o serviço de coleta de métricas:

Antes de começarmos a explorar o Horizontal Pod Autoscaler (HPA), é essencial termos o Metrics Server instalado em nosso cluster Kubernetes. O Metrics Server é um agregador de métricas de recursos de sistema, que coleta métricas como uso de CPU e memória dos nós e pods no cluster. Essas métricas são vitais para o funcionamento do HPA, pois são usadas para determinar quando e como escalar os recursos.

 

O HPA utiliza métricas de uso de recursos para tomar decisões inteligentes sobre o escalonamento dos pods. Por exemplo, se a utilização da CPU de um pod exceder um determinado limite, o HPA pode decidir aumentar o número de réplicas desse pod. Da mesma forma, se a utilização da CPU for muito baixa, o HPA pode decidir reduzir o número de réplicas. Para fazer isso de forma eficaz, o HPA precisa ter acesso a métricas precisas e atualizadas, que são fornecidas pelo Metrics Server.

Nota: Vamos usar o gerenciador de pacotes HELM ( https://helm.sh/ ).  

Instalar o Helm

curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

Adicionar o Repositório

helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/

Instalar o serviço de métricas

helm upgrade --install \
    --set args={--kubelet-insecure-tls} metrics-server metrics-server/metrics-server \
    --namespace kube-system

Nota: Aguarde uns minutos até a criação dos Pods do serviço de métrica.

3) Verificar se tudo OK:

kubectl get pods -n kube-system | grep metrics-server

Nota: Com o serviço de métricas funcionando, será possível usar o comando top para verificar o consumo de recurso pelos objetos:

kubectl top nodes
kubectl top pods
Servidor de Aplicação

4) Antes de usar o HPA, vamos criar um deployment simples usando qualquer imagem apenas para teste.

vi app-tfd1.yaml
# Deployment
apiVersion: apps/v1                    # Versão da API que define um Deployment
kind: Deployment                       # Tipo de recurso que estamos definindo
metadata:
  name: app-tfd1                       # Nome do nosso Deployment
spec:
  replicas: 3                          # Número inicial de réplicas
  selector:
    matchLabels:
      app: app-tfd1                    # Label que identifica os pods deste Deployment
  template:
    metadata:
      labels:
        app: app-tfd1                  # Label aplicada aos pods
    spec:
      containers:
      - name: app-tfd1                 # Nome do contêiner
        image: brunofischer/app-tfd1   # Imagem do contêiner
        ports:
        - containerPort: 80            # Porta exposta pelo contêiner
        resources:
          limits:
            cpu: 100m                  # Limite de CPU
          requests:
            cpu: 25m                  # Requisição de CPU

---
# Service
apiVersion: v1
kind: Service
metadata:
  name: app-tfd1-service

spec:
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: app-tfd1
  type: LoadBalancer
  loadBalancerIP: 10.9.66.150

5) Subir o deployment e o service da aplicação:

kubectl apply -f app-tfd1.yaml

6) Verifique se o deploy foi finalizado e o POD está rodando (Running). 

kubectl get pods
Locust (Stress Test)

Será instalado uma ferramenta para testes de stress chamada Locust ( https://locust.io/ ). Com ela vamos testar o stress do deployment do nginx para validarmos o HPA.

7) Arquivo locust.yaml

vi locust.yaml
# ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: locust-config
data:
  locustfile.py: |
    from locust import HttpUser, task, between
    class Fischer(HttpUser):
        wait_time = between(1, 2)
        @task(1)
        def testar(self):
            self.client.get("/")
            
---
# Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: locust
spec:
  replicas: 1
  selector:
    matchLabels:
      app: locust
  template:
    metadata:
      labels:
        app: locust
    spec:
      containers:
      - name: locust
        image: locustio/locust
        command: ["locust", "-f", "/etc/locust/locustfile.py"]
        volumeMounts:
        - name: locust-config
          mountPath: /etc/locust
      volumes:
      - name: locust-config
        configMap:
          name: locust-config

---
# Service
apiVersion: v1
kind: Service
metadata:
  name: locust-service

spec:
  ports:
  - port: 80
    targetPort: 8089
  selector:
    app: locust
  type: LoadBalancer
  loadBalancerIP: 10.9.66.151

8) Subir o deployment do serviço locust

kubectl apply -f locust.yaml

9) Verifique se o deploy foi finalizado e o POD está rodando (Running). 

kubectl get pods
Horizontal Pod Autoscaler (HPA)

Agora, com nossoo deployment pronto, vamos dar o próximo passo na criação do nosso HPA. Neste exemplo, criamos um HPA que monitora a utilização da CPU do nosso deployment app-tfd1. O HPA se esforçará para manter a utilização da CPU em torno de 50%, ajustando o número de réplicas entre 3 e 10 conforme necessário.

7)1) Especificações do HPA:

vi app-tfd1-hpa.yaml
# Definição do HPA para o nginx-deployment

apiVersion: autoscaling/v2       # Versão da API que define um HPA
kind: HorizontalPodAutoscaler    # Tipo de recurso que estamos definindo
metadata:
  name: app-tfd1-hpa             # Nome do nosso HPA
spec:
  scaleTargetRef:
    apiVersion: apps/v1          # A versão da API do recurso alvo
    kind: Deployment             # O tipo de recurso alvo
    name: app-tfd1               # O nome do recurso alvo
  minReplicas: 3                 # Número mínimo de réplicas
  maxReplicas: 10                # Número máximo de réplicas
  metrics:
  - type: Resource               # Tipo de métrica (recurso do sistema)
    resource:
      name: cpu                  # Nome da métrica (CPU neste caso)
      target:
        type: Utilization        # Tipo de alvo (utilização)
        averageUtilization: 50   # Valor alvo (50% de utilização)
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 0    # Período de estabilização para escalonamento para cima
    scaleDown:
      stabilizationWindowSeconds: 30   # Período de estabilização para escalonamento para baixo

8)2) Aplicar as configurações do HPA:

kubectl apply -f app-tfd1-hpa.yaml

9)3) Verificar se o serviço do HPA está ativo:

kubectl get hpa
Locust (Stress Test)

Será instalado uma ferramenta para testes de stress chamada Locust ( https://locust.io/ ). Com ela vamos testar o stress do deployment do nginx para validarmos o HPA.

10) Arquivo locust.yaml

vi locust.yaml
# ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: locust-config
data:
  locustfile.py: |
    from locust import HttpUser, task, between
    class Fischer(HttpUser):
        wait_time = between(1, 2)
        @task(1)
        def testar(self):
            self.client.get("/")
            
---
# Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: locust
spec:
  replicas: 1
  selector:
    matchLabels:
      app: locust
  template:
    metadata:
      labels:
        app: locust
    spec:
      containers:
      - name: locust
        image: locustio/locust
        command: ["locust", "-f", "/etc/locust/locustfile.py"]
        volumeMounts:
        - name: locust-config
          mountPath: /etc/locust
      volumes:
      - name: locust-config
        configMap:
          name: locust-config

---
# Service
apiVersion: v1
kind: Service
metadata:
  name: locust-service

spec:
  ports:
  - port: 80
    targetPort: 8089
  selector:
    app: locust
  type: LoadBalancer
  loadBalancerIP: 10.9.66.151

11) Subir o deployment do serviço locust

kubectl apply -f locust.yaml

12) Verifique se o deploy foi finalizado e o POD está rodando (Running). 

kubectl get pods

13)4) Fazer o teste usando o Firefoxatravés do ORC-Server.navegador.

Nota: Antes de abrir o navegado para o teste, deixedeixamos o comando abaixo rodando para acompanhar a criação dos Pods.
A opção -w ficará observando as mudanças (watching)

kubectl get deploy/app-tfd1 -w

image.png

  • Máximo de usuários simultâneos: 1000
  • Incremento de 10 em 10. 
  • Host: http://10.9.66.150 (serviço da aplicação de exemplo).

5) 

image.pngResultados dos Testes (HPA)

image.png

Conclusão

A medida que as requisições começaram a demandar uso de CPU, superior ao estabelecidos no HPA, houve incremento de PODs. Ainda, 30 segundos após a finalização do teste de stress, a quantidade de PODs foi  reduzida gradualmente até o número mínimo definido no HPA.

image.png

image.png

Vertical Pod Autoscaler (VPA)

A seguir, vamos remover o HPA criado anteriormente e criar uma regra de VPA (Vertical Pod Autoscaler). O VPA irá monitora a utilização da CPU e Memória do nosso deployment app-tfd1. Porém, agora, ao invés de aumentar a quantidade de Pods, o VPA garantirá incremento de CPU e Memória aos 03 pods já existentes.

1) Excluir o HPA:

kubectl delete -f app-tfd1-hpa.yaml

2) Instalação os componentes do VPA:

Antes de criar objetos VPA, primeiro precisamos instalar o VPA em nosso cluster usando as etapas abaixo:

git clone https://github.com/kubernetes/autoscaler.git
cd autoscaler/vertical-pod-autoscaler
./hack/vpa-up.sh
cd ~/scaler
kubectl get pods -n kube-system | grep vpa

3) Especificações do VPA:

vi app-tfd1-vpa.yaml
apiVersion: "autoscaling.k8s.io/v1"
kind: VerticalPodAutoscaler
metadata:
  name: app-tfd1-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: app-tfd1
  updatePolicy:
    updateMode: Auto
  resourcePolicy:
    containerPolicies:
      - containerName: '*'
        minAllowed:
          cpu: 100m
          memory: 50Mi
        maxAllowed:
          cpu: 200m  
          memory: 500Mi
        controlledResources: ["cpu", "memory"]

3) Aplicar as configurações do VPA:

kubectl apply -f app-tfd1-vpa.yaml

4) Verificar se o serviço do HPA está ativo e quanto de CPU e Memoria os Pods do Deployment app-tfd1 estão consumindo de recursos:

kubectl get vpa
kubectl top pod