DevOps & CI/CD

Dominando Horizontal Pod Autoscaler e Vertical Pod Autoscaler em Kubernetes em Projetos Reais

15 min de leitura

Dominando Horizontal Pod Autoscaler e Vertical Pod Autoscaler em Kubernetes em Projetos Reais

Entendendo Autoscaling em Kubernetes Autoscaling é um dos pilares da infraestrutura moderna em Kubernetes. Quando sua aplicação recebe picos de tráfego, você precisa de mais recursos de forma automática. Da mesma forma, quando a demanda cai, você não quer pagar por capacidade ociosa. O Kubernetes oferece duas estratégias principais de autoscaling: o Horizontal Pod Autoscaler (HPA) e o Vertical Pod Autoscaler (VPA). Embora ambos resolvam o problema de escalabilidade, eles abordam o problema de ângulos completamente diferentes. O HPA adiciona mais réplicas do seu pod quando a carga aumenta, enquanto o VPA ajusta os recursos (CPU e memória) solicitados e os limites de cada pod individual. Entender a diferença entre essas duas abordagens e quando usá-las é essencial para qualquer engenheiro que trabalha com Kubernetes em produção. Horizontal Pod Autoscaler (HPA) O que é e como funciona O Horizontal Pod Autoscaler monitora métricas como CPU e memória (ou métricas personalizadas) e automaticamente aumenta ou diminui o número de réplicas de

<h2>Entendendo Autoscaling em Kubernetes</h2>

<p>Autoscaling é um dos pilares da infraestrutura moderna em Kubernetes. Quando sua aplicação recebe picos de tráfego, você precisa de mais recursos de forma automática. Da mesma forma, quando a demanda cai, você não quer pagar por capacidade ociosa. O Kubernetes oferece duas estratégias principais de autoscaling: o <strong>Horizontal Pod Autoscaler (HPA)</strong> e o <strong>Vertical Pod Autoscaler (VPA)</strong>. Embora ambos resolvam o problema de escalabilidade, eles abordam o problema de ângulos completamente diferentes.</p>

<p>O HPA adiciona mais <strong>réplicas</strong> do seu pod quando a carga aumenta, enquanto o VPA ajusta os <strong>recursos (CPU e memória)</strong> solicitados e os limites de cada pod individual. Entender a diferença entre essas duas abordagens e quando usá-las é essencial para qualquer engenheiro que trabalha com Kubernetes em produção.</p>

<h2>Horizontal Pod Autoscaler (HPA)</h2>

<h3>O que é e como funciona</h3>

<p>O Horizontal Pod Autoscaler monitora métricas como CPU e memória (ou métricas personalizadas) e automaticamente aumenta ou diminui o número de réplicas de um Deployment, StatefulSet ou ReplicaSet. O controlador HPA funciona em um loop contínuo, consultando as métricas a cada 15 segundos (por padrão) e calculando se mais ou menos réplicas são necessárias.</p>

<p>A fórmula básica do HPA é: <code>desiredReplicas = ceil[currentReplicas <em> (currentMetricValue / targetMetricValue)]</code>. Se sua aplicação tem 2 réplicas consumindo 80% de CPU e o alvo é 50%, o HPA tentará escalar para 3 réplicas (2 </em> 80/50 = 3.2, arredondado para 3).</p>

<h3>Pré-requisitos e instalação de métricas</h3>

<p>Antes de usar HPA, você precisa ter o <strong>Metrics Server</strong> instalado no seu cluster. Este componente coleta métricas de uso de recursos dos nodes e pods. Se você estiver usando um cluster gerenciado (GKE, EKS, AKS), o Metrics Server já vem pré-instalado.</p>

<pre><code class="language-bash"># Para verificar se o Metrics Server está instalado

kubectl get deployment metrics-server -n kube-system

Se não estiver instalado, faça a instalação

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

Verifique se está rodando

kubectl top nodes

kubectl top pods -n default</code></pre>

<p>Se os comandos <code>kubectl top</code> funcionarem, você está pronto para usar HPA.</p>

<h3>Exemplo prático de HPA</h3>

<p>Vamos criar um exemplo completo com uma aplicação simples que consome CPU sob demanda. Primeiro, criaremos um Deployment:</p>

<pre><code class="language-yaml"># deployment.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

name: web-app

namespace: default

spec:

replicas: 2

selector:

matchLabels:

app: web-app

template:

metadata:

labels:

app: web-app

spec:

containers:

  • name: app

image: nginx:latest

resources:

requests:

cpu: 100m

memory: 128Mi

limits:

cpu: 500m

memory: 512Mi

ports:

  • containerPort: 80</code></pre>

<p>Agora criamos o HPA que escalará este Deployment:</p>

<pre><code class="language-yaml"># hpa.yaml

apiVersion: autoscaling/v2

kind: HorizontalPodAutoscaler

metadata:

name: web-app-hpa

namespace: default

spec:

scaleTargetRef:

apiVersion: apps/v1

kind: Deployment

name: web-app

minReplicas: 2

maxReplicas: 10

metrics:

  • type: Resource

resource:

name: cpu

target:

type: Utilization

averageUtilization: 70

  • type: Resource

resource:

name: memory

target:

type: Utilization

averageUtilization: 80

behavior:

scaleDown:

stabilizationWindowSeconds: 300

policies:

  • type: Percent

value: 50

periodSeconds: 15

scaleUp:

stabilizationWindowSeconds: 0

policies:

  • type: Percent

value: 100

periodSeconds: 15

  • type: Pods

value: 4

periodSeconds: 15

selectPolicy: Max</code></pre>

<p>Aplicar os recursos:</p>

<pre><code class="language-bash">kubectl apply -f deployment.yaml

kubectl apply -f hpa.yaml

Monitorar o status do HPA

kubectl get hpa web-app-hpa --watch

kubectl describe hpa web-app-hpa</code></pre>

<p>Agora, para testar o autoscaling, vamos simular carga com um pod auxiliar:</p>

<pre><code class="language-bash"># Criar um pod de teste

kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh -c &quot;while sleep 0.01; do wget -q -O- http://web-app; done&quot;</code></pre>

<p>Observe como o número de pods aumenta gradualmente enquanto a carga é mantida. Quando você encerrar o gerador de carga (Ctrl+C), verá os pods sendo reduzidos após o <code>stabilizationWindowSeconds</code>.</p>

<h3>Métricas personalizadas com HPA</h3>

<p>O HPA não se limita apenas a CPU e memória. Você pode escalar baseado em métricas customizadas coletadas de ferramentas como Prometheus. Aqui está um exemplo:</p>

<pre><code class="language-yaml">apiVersion: autoscaling/v2

kind: HorizontalPodAutoscaler

metadata:

name: web-app-custom-hpa

spec:

scaleTargetRef:

apiVersion: apps/v1

kind: Deployment

name: web-app

minReplicas: 2

maxReplicas: 10

metrics:

  • type: Pods

pods:

metric:

name: http_requests_per_second

target:

type: AverageValue

averageValue: &quot;1000&quot;</code></pre>

<p>Neste caso, o HPA escalará a aplicação para manter aproximadamente 1000 requisições por segundo por pod.</p>

<h2>Vertical Pod Autoscaler (VPA)</h2>

<h3>O que é e como funciona</h3>

<p>O Vertical Pod Autoscaler é fundamentalmente diferente do HPA. Em vez de aumentar o número de pods, o VPA ajusta os <strong>requests e limits</strong> de CPU e memória de cada pod existente. Ele analisa o histórico de uso de cada container e faz recomendações sobre qual deveria ser o tamanho ideal.</p>

<p>O VPA funciona em três modos principais: <strong>Off</strong> (apenas faz recomendações), <strong>Initial</strong> (define recursos apenas na criação), <strong>Recreate</strong> (mata e recria pods com novos valores) e <strong>Auto</strong> (escolhe automaticamente entre os anteriores). A maioria das implementações em produção usa o modo <strong>Auto</strong>, que tenta ser menos disruptivo possível.</p>

<h3>Instalação do VPA</h3>

<p>O VPA é mais complexo de instalar porque requer três componentes: o <strong>Recommender</strong> (que coleta dados), o <strong>Updater</strong> (que modifica pods) e o <strong>Admission Controller</strong> (que define recursos em novos pods). A maneira mais fácil é usar o script fornecido pela comunidade:</p>

<pre><code class="language-bash"># Clone o repositório

git clone https://github.com/kubernetes/autoscaler.git

cd autoscaler/vertical-pod-autoscaler

Execute o script de instalação

./hack/vpa-up.sh

Verifique a instalação

kubectl get deployment -n kube-system | grep vpa kubectl get pods -n kube-system | grep vpa</code></pre>

<h3>Exemplo prático de VPA</h3>

<p>Vamos criar uma aplicação que têm requests iniciais inadequados e deixar o VPA otimizá-los:</p>

<pre><code class="language-yaml"># app-for-vpa.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

name: memory-intensive-app

spec:

replicas: 3

selector:

matchLabels:

app: memory-app

template:

metadata:

labels:

app: memory-app

spec:

containers:

  • name: app

image: polinux/stress

resources:

requests:

cpu: 50m # Muito baixo para o que a app precisa

memory: 64Mi # Muito baixo para o que a app precisa

limits:

cpu: 200m

memory: 256Mi

command: [&quot;stress&quot;]

args:

  • &quot;--cpu&quot;
  • &quot;1&quot;
  • &quot;--vm&quot;
  • &quot;1&quot;
  • &quot;--vm-bytes&quot;
  • &quot;150M&quot;
  • &quot;--vm-hang&quot;
  • &quot;1&quot;</code></pre>

<p>Agora criamos a política do VPA:</p>

<pre><code class="language-yaml"># vpa-policy.yaml

apiVersion: autoscaling.k8s.io/v1

kind: VerticalPodAutoscaler

metadata:

name: memory-app-vpa

spec:

targetRef:

apiVersion: &quot;apps/v1&quot;

kind: Deployment

name: memory-intensive-app

updatePolicy:

updateMode: &quot;Auto&quot;

resourcePolicy:

containerPolicies:

  • containerName: &quot;*&quot;

minAllowed:

cpu: 50m

memory: 64Mi

maxAllowed:

cpu: 1

memory: 1Gi

controlledResources: [&quot;cpu&quot;, &quot;memory&quot;]

controlledValues: RequestsAndLimits</code></pre>

<p>Aplicar:</p>

<pre><code class="language-bash">kubectl apply -f app-for-vpa.yaml

kubectl apply -f vpa-policy.yaml

Monitorar as recomendações

kubectl describe vpa memory-app-vpa

kubectl get vpa memory-app-vpa --watch

Ver em tempo real as mudanças

kubectl describe deployment memory-intensive-app</code></pre>

<p>Após alguns minutos, o VPA enviará as recomendações. Quando está em modo &quot;Auto&quot;, ele criará novos pods com os recursos recomendados, matando os antigos.</p>

<h3>Entendendo as recomendações do VPA</h3>

<p>Quando você executa <code>kubectl describe vpa</code>, você verá algo como:</p>

<pre><code>Status:

Recommendation:

Container Recommendations:

  • Container Name: app

Lower Bound:

Cpu: 100m

Memory: 256Mi

Target:

Cpu: 200m

Memory: 512Mi

Uncapped Target:

Cpu: 200m

Memory: 512Mi

Upper Bound:

Cpu: 500m

Memory: 1Gi</code></pre>

<p>Essas recomendações vêm de percentis de uso histórico: o <strong>Target</strong> geralmente é o P95 (95º percentil) do uso observado, o <strong>Lower Bound</strong> é um valor seguro mínimo, e o <strong>Upper Bound</strong> garante que você não aloque recursos demais.</p>

<h2>Comparando HPA vs VPA: Quando usar cada um</h2>

<h3>HPA: Escalabilidade horizontal</h3>

<p>Use HPA quando sua aplicação é <strong>stateless</strong> ou quando os pods podem ser criados e destruídos facilmente. Exemplos incluem APIs REST, serviços web e workers de processamento de filas. O HPA é ideal quando você quer distribuir a carga entre múltiplas instâncias da aplicação.</p>

<p>HPA também é a escolha certa quando você sabe que picos de tráfego são temporários. Se você recebe 10x mais requisições por uma hora e depois volta ao normal, escalar horizontalmente é mais eficiente que aumentar a memória de cada pod permanentemente.</p>

<h3>VPA: Escalabilidade vertical</h3>

<p>Use VPA quando sua aplicação é <strong>stateful</strong> ou quando o custo de criação de novos pods é alto (como em bancos de dados que replicam dados). O VPA também é essencial quando você não tem ideia de qual é o tamanho correto dos seus containers — ele aprende com o tempo e ajusta.</p>

<p>O VPA brilha em cenários de &quot;right-sizing&quot;: muitas organizações definem requests com valores aleatórios ou muito conservadores. O VPA analisa semanas de dados e diz exatamente quanto cada container precisa.</p>

<h3>Combinando HPA e VPA</h3>

<p>A melhor prática em muitos cenários é usar <strong>ambos juntos</strong>, mas com cuidado. O HPA escalará horizontalmente para distribuir a carga, enquanto o VPA garante que cada pod tem o tamanho correto. No entanto, você deve configurá-los com inteligência:</p>

<pre><code class="language-yaml"># Exemplo: HPA + VPA juntos

apiVersion: autoscaling/v2

kind: HorizontalPodAutoscaler

metadata:

name: app-hpa

spec:

scaleTargetRef:

apiVersion: apps/v1

kind: Deployment

name: my-app

minReplicas: 2

maxReplicas: 20

metrics:

  • type: Resource

resource:

name: cpu

target:

type: Utilization

averageUtilization: 70

---

apiVersion: autoscaling.k8s.io/v1

kind: VerticalPodAutoscaler

metadata:

name: app-vpa

spec:

targetRef:

apiVersion: &quot;apps/v1&quot;

kind: Deployment

name: my-app

updatePolicy:

updateMode: &quot;Auto&quot;</code></pre>

<p>Nesta configuração, o VPA define requests/limits ideais, e o HPA escala horizontalmente quando a utilização ultrapassa 70%. Isso funciona bem porque o VPA está sempre ajustando os tamanhos dos containers para o valor ideal, enquanto HPA reage em tempo real ao tráfego.</p>

<h2>Troubleshooting e Boas Práticas</h2>

<h3>Problemas comuns com HPA</h3>

<p>Se seu HPA não está escalando, verifique: (1) o Metrics Server está rodando? (2) os pods têm <code>requests</code> definidos? (3) as métricas estão disponíveis via <code>kubectl top</code>? O HPA <strong>precisa</strong> de requests para calcular a utilização percentual. Sem requests, ele não consegue fazer cálculos.</p>

<pre><code class="language-bash"># Diagnóstico: verificar eventos do HPA

kubectl describe hpa seu-hpa-name

kubectl get events -n seu-namespace --sort-by=&#039;.lastTimestamp&#039;

Verificar métricas manualmente

kubectl get --raw /apis/metrics.k8s.io/v1beta1/namespaces/default/pods</code></pre>

<h3>Problemas comuns com VPA</h3>

<p>O VPA às vezes não faz recomendações se há dados insuficientes. Aguarde alguns dias de coleta de dados antes de esperar recomendações precisas. Além disso, se você definir <code>maxAllowed</code> muito apertado, o VPA não conseguirá fazer recomendações maiores que esse valor.</p>

<pre><code class="language-bash"># Ver o status do VPA em detalhes

kubectl get vpa seu-vpa-name -o yaml | grep -A 20 &quot;recommendation&quot;

Verificar logs do recommender

kubectl logs -n kube-system -l app=vpa-recommender -f</code></pre>

<h3>Boas práticas gerais</h3>

<ol>

<li><strong>Sempre defina requests</strong>: Tanto HPA quanto VPA dependem de requests bem definidos. Requests são diferentes de limits — um request é o que você <strong>garante</strong> que o pod vai ter, enquanto limit é o máximo que pode usar.</li>

</ol>

<ol>

<li><strong>Monitore o comportamento do autoscaling</strong>: Use ferramentas como Prometheus e Grafana para rastrear quando e por que o autoscaling foi acionado. Às vezes o comportamento revela problemas na aplicação, não no Kubernetes.</li>

</ol>

<ol>

<li><strong>Use políticas de <code>scaleDown</code> conservadoras</strong>: Escalar para cima é bom, mas escalar para baixo agressivamente pode matar requisições em progresso. O exemplo anterior tem <code>stabilizationWindowSeconds: 300</code> para scale-down, o que é razoável.</li>

</ol>

<ol>

<li><strong>Teste em staging primeiro</strong>: Não implante HPA/VPA em produção sem testar o comportamento em um ambiente de teste idêntico.</li>

</ol>

<ol>

<li><strong>Considere custos</strong>: HPA pode aumentar sua conta de cloud rapidamente em picos de tráfego. Sempre defina <code>maxReplicas</code> e <code>maxAllowed</code> com responsabilidade.</li>

</ol>

<h2>Conclusão</h2>

<p>O <strong>Horizontal Pod Autoscaler</strong> e o <strong>Vertical Pod Autoscaler</strong> são ferramentas complementares, não concorrentes. O HPA resolve o problema de distribuir carga entre múltiplas instâncias (escala horizontal), enquanto o VPA resolve o problema de garantir que cada instância tem o tamanho certo (escala vertical). Na prática, você provavelmente usará ambos em sua infraestrutura Kubernetes: HPA para aplicações stateless que recebem tráfego variável, e VPA para right-sizing de todas as suas cargas de trabalho e para aplicações stateful que não podem ser replicadas trivialmente. O segredo é começar com HPA se você está começando em Kubernetes, ganhar experiência com o comportamento de sua aplicação sob carga, e depois introduzir VPA para otimização fina dos recursos.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/" target="_blank" rel="noopener noreferrer">Kubernetes Horizontal Pod Autoscaler - Documentação Oficial</a></li>

<li><a href="https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler" target="_blank" rel="noopener noreferrer">Kubernetes Vertical Pod Autoscaler - GitHub Autoscaler Project</a></li>

<li><a href="https://github.com/kubernetes-sigs/metrics-server" target="_blank" rel="noopener noreferrer">Metrics Server - GitHub Repository</a></li>

<li><a href="https://www.manning.com/books/kubernetes-in-action" target="_blank" rel="noopener noreferrer">Kubernetes in Action - Marko Lukša - Seção sobre Autoscaling</a></li>

<li><a href="https://www.cncf.io/" target="_blank" rel="noopener noreferrer">HPA e VPA: When and How to Use Each - Cloud Native Computing Foundation</a></li>

</ul>

<p>&lt;!-- FIM --&gt;</p>

Comentários

Mais em DevOps & CI/CD

Crossplane: Infraestrutura como Código dentro do Kubernetes na Prática
Crossplane: Infraestrutura como Código dentro do Kubernetes na Prática

O que é Crossplane e por que você deve aprender Crossplane é um framework ope...

Boas Práticas de DevSecOps: Integrando Segurança no Pipeline de CI/CD para Times Ágeis
Boas Práticas de DevSecOps: Integrando Segurança no Pipeline de CI/CD para Times Ágeis

O Que é DevSecOps e Por Que Importa DevSecOps é a integração deliberada de pr...

Incident Management: Runbooks, Post-mortems e Cultura de Confiabilidade na Prática
Incident Management: Runbooks, Post-mortems e Cultura de Confiabilidade na Prática

Incident Management: Fundamentos e Importância Incident Management é a discip...