Otimizar Kubernetes em VPS Linux é ajustar o consumo de CPU e memória do cluster para pagar por menos recursos sem perder estabilidade. Na prática, isso significa usar uma distribuição leve como K3s, medir o uso real dos pods e definir requests e limits compatíveis com essa medição. Para reduzir custos, siga estes passos:
- Escolha uma distribuição leve (K3s) e desative os componentes que você não usa.
- Instale o metrics-server e meça o consumo real com
kubectl top. - Defina requests e limits próximos do uso observado em cada Deployment.
- Aplique LimitRange e ResourceQuota por namespace para impedir desperdício.
- Use HPA onde a carga varia e remova workloads ociosos.
Pré-requisitos
- Um VPS com Ubuntu 24.04 LTS (os comandos valem para outras distros com poucas mudanças) e acesso root ou sudo.
- Um cluster Kubernetes já em funcionamento: K3s de nó único ou de poucos nós.
kubectlconfigurado e apontando para o cluster.- Pelo menos um Deployment em execução para servir de exemplo.
- Noções básicas de YAML e de namespaces.
Se você ainda está decidindo entre rodar containers puros ou orquestrados, veja antes Otimizar Kubernetes vs Docker no Rocky 10: checklist prático.
Escolher uma distribuição leve para o control plane
O primeiro custo fixo de um cluster em VPS é o próprio control plane. Em um VPS pequeno, uma distribuição enxuta como o K3s empacota os componentes em um único binário e reduz a memória reservada antes mesmo de você subir a primeira aplicação.
O K3s vem com Traefik (ingress) e ServiceLB habilitados por padrão. Se você já usa outro ingress ou não precisa deles, desative na instalação para economizar memória:
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server --disable traefik --disable servicelb" sh -
Depois confira se o nó está pronto:
sudo k3s kubectl get nodes
NAME STATUS ROLES AGE VERSION
vps-01 Ready control-plane,master 1m v1.34.1+k3s1
A versão exibida é ilustrativa; a sua dependerá do release do K3s instalado.
Atenção: desativar o Traefik e o ServiceLB significa que você precisa fornecer outro ingress e outra forma de expor serviços. Faça isso só se já tiver essa parte resolvida.
Alternativas leves incluem o MicroK8s. Em qualquer opção, evite instalar add-ons que você não vai usar: cada componente extra consome memória do VPS. Para ajustes no sistema operacional que complementam este passo, consulte Otimizar a Performance de VPS Linux e Servidor Dedicado com Configuração Avançada do Kernel.
Medir o consumo real com metrics-server
Sem medição, requests e limits viram palpite. O metrics-server coleta uso de CPU e memória dos nós e dos pods e alimenta tanto o kubectl top quanto o HPA. O K3s costuma incluir o metrics-server por padrão; confirme antes de instalar outro:
kubectl get deployment metrics-server -n kube-system
Se ele não existir no seu cluster, instale pelo manifesto oficial do projeto:
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
Com ele funcionando, veja o consumo por nó e por pod:
kubectl top nodes
kubectl top pods -A --sort-by=memory
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
vps-01 180m 9% 1450Mi 36%
Os valores variam com a sua carga. O formato das colunas é o que importa: CPU em millicores (m) e memória em Mi. Observe os pods por um período representativo, incluindo horário de pico, e não apenas um instante. Anote o uso médio e o máximo de cada aplicação: eles serão a base para os requests e limits.
Definir requests e limits dos pods
Requests e limits controlam como o scheduler distribui pods e quanto cada container pode consumir. Requests altos demais fazem o nó parecer cheio mesmo com uso baixo, e você acaba pagando por mais VPS. Requests baixos demais causam disputa por recursos e instabilidade.
Um exemplo de Deployment com valores definidos a partir de medição (ajuste os números ao que você observou):
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-web
namespace: producao
spec:
replicas: 2
selector:
matchLabels:
app: app-web
template:
metadata:
labels:
app: app-web
spec:
containers:
- name: app
image: nginx:stable
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
memory: "256Mi"
Note que o exemplo define limite de memória, mas não de CPU. É uma escolha comum: o limite de CPU causa throttling mesmo quando o nó tem CPU livre, enquanto o limite de memória protege o nó contra um pod que consome RAM sem controle. Decida por workload.
Como regra de partida, o request fica próximo do uso médio observado e o limite de memória com folga acima do pico. Crie o namespace e aplique:
kubectl create namespace producao
kubectl apply -f app-web.yaml
kubectl get pods -n producao
kubectl top pods -n producao
Atenção: se um container ultrapassar o limite de memória, ele é encerrado por OOM kill e reiniciado. Se você vir reinícios, aumente o limite com base na medição em vez de remover a proteção.
Aplicar LimitRange e ResourceQuota por namespace
O LimitRange define valores padrão e limites mínimos e máximos por container; o ResourceQuota limita o total que um namespace pode reservar. Juntos, controlam as declarações de requests, limits e contagens de objetos admitidos por namespace, impedindo que um deploy esquecido monopolize as cotas definidas. Para impor também um teto de uso de CPU em tempo de execução, adicione os campos default e max para CPU no LimitRange e limits.cpu no ResourceQuota, tendo em mente o risco de throttling.
apiVersion: v1
kind: LimitRange
metadata:
name: padrao-recursos
namespace: producao
spec:
limits:
- type: Container
defaultRequest:
cpu: "50m"
memory: "64Mi"
default:
memory: "256Mi"
max:
memory: "1Gi"
apiVersion: v1
kind: ResourceQuota
metadata:
name: quota-producao
namespace: producao
spec:
hard:
requests.cpu: "1"
requests.memory: 1Gi
limits.memory: 2Gi
pods: "20"
Aplique os dois e confira o estado:
kubectl apply -f limitrange.yaml -f quota.yaml
kubectl describe resourcequota quota-producao -n producao
A saída lista cada recurso com as colunas Used e Hard. Quando um namespace tem ResourceQuota para CPU ou memória, todo pod novo precisa declarar requests e limits correspondentes; o LimitRange com valores padrão resolve isso sem editar cada manifesto.
Dimensione a quota de acordo com a capacidade do nó, deixando margem para o sistema e para o control plane. Para planejar a capacidade do VPS em si, veja VPS para Docker: como dimensionar memória, CPU e disco.
Escalar réplicas com o HPA
O Horizontal Pod Autoscaler (HPA) ajusta o número de réplicas conforme a utilização. Ele calcula a utilização como porcentagem do request, por isso só funciona com requests definidos e realistas. Crie um HPA para o Deployment de exemplo:
kubectl autoscale deployment app-web -n producao --cpu-percent=70 --min=1 --max=3
Atenção: ao criar o HPA, ele passa a gerenciar o número de réplicas do Deployment. Em re-aplicações do manifesto, omita o campo spec.replicas para evitar conflito entre o valor fixado no YAML e o valor controlado pelo HPA.
Acompanhe o comportamento:
kubectl get hpa -n producao
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
app-web Deployment/app-web cpu: 12%/70% 1 3 1 2m
Se a coluna TARGETS mostrar <unknown>, o metrics-server não está respondendo ou o pod não tem request de CPU. Em um VPS de nó único, o HPA não cria capacidade nova: ele redistribui o que o nó já tem. Por isso, mantenha o --max compatível com a folga real do servidor, senão as réplicas novas ficam em estado Pending.
O HPA reduz o consumo fora do pico. Em um VPS fixo, isso só se converte em economia se permitir reduzir posteriormente o plano ou a quantidade de nós. Em cargas estáveis e pequenas, um número fixo de réplicas com requests bem calibrados costuma ser mais simples e igualmente econômico.
Eliminar desperdício e reduzir o custo do cluster
Depois de calibrar os pods, procure o que não deveria estar rodando. Liste tudo que consome recursos e compare com o que você realmente usa:
kubectl get pods -A
kubectl top pods -A --sort-by=cpu
kubectl get deployments -A
Ações que reduzem o consumo sem trocar de plano de VPS:
- Remova Deployments, Jobs e namespaces de teste esquecidos.
- Reduza réplicas de ambientes de homologação para 1.
- Evite agentes de monitoramento pesados; um stack completo de observabilidade pode consumir mais que a aplicação. Prefira coleta enxuta.
- Configure rotação e limite de logs dos containers para não encher o disco.
- Use imagens menores (variantes slim ou alpine, quando compatíveis) para reduzir disco e tempo de pull.
Para escalar a zero um workload que não precisa ficar ativo:
kubectl create namespace homologacao # se o namespace ainda não existir
kubectl scale deployment app-teste -n homologacao --replicas=0
Esse comando não apaga o Deployment: ele apenas encerra os pods, e você pode voltar com --replicas=1. Por fim, revise o dimensionamento do VPS. Se, após os ajustes, o uso do nó ficar consistentemente baixo, um plano menor pode bastar. Outros ajustes gerais de sistema estão em Checklist para Otimização de VPS Linux: 15 Ajustes Essenciais.
Problemas comuns e como resolver
Sintoma: pods ficam em Pending com "Insufficient memory" ou "Insufficient cpu"
Causa: a soma dos requests excede a capacidade alocável do nó, mesmo que o uso real seja baixo.
Solução: rode kubectl describe pod NOME -n NAMESPACE e leia a seção Events. Compare requests com o uso medido via kubectl top e reduza os que estiverem superdimensionados. Remova workloads ociosos antes de aumentar o VPS.
Sintoma: container reinicia com status OOMKilled
Causa possível: estouro do limite de memória do container ou pressão global de memória no nó. Um container sem limite definido também pode ser encerrado pelo OOM killer do kernel quando a memória do nó está escassa.
Solução: confirme com kubectl describe pod (campo Last State: Terminated, Reason: OOMKilled) e verifique métricas, eventos e logs do kernel/kubelet com journalctl -k e journalctl -u k3s antes de aumentar o limite. Se o problema for limite do container, aumente-o com base no pico medido; se for pressão no nó, revise o total de limits definidos no namespace ou corrija vazamento de memória na aplicação.
Sintoma: kubectl top retorna "Metrics API not available"
Causa: o metrics-server não está instalado, não está pronto ou não consegue acessar os kubelets.
Solução: verifique o pod com kubectl get pods -n kube-system e leia os logs com kubectl logs -n kube-system deploy/metrics-server. Aguarde alguns instantes após a instalação, pois a primeira coleta não é imediata.
Sintoma: HPA mostra TARGETS como <unknown>
Causa: o Deployment não define request de CPU ou o metrics-server não está entregando métricas.
Solução: adicione resources.requests.cpu ao manifesto e confirme que kubectl top pods funciona.
Sintoma: aplicação lenta mesmo com CPU sobrando no nó
Causa: limite de CPU baixo causando throttling do container.
Solução: aumente ou remova o limite de CPU e mantenha apenas o request, monitorando o efeito sobre os demais pods.
Perguntas frequentes
Como reduzir custos de Kubernetes em VPS Linux?
Comece medindo o consumo real dos pods com kubectl top e ajuste requests e limits para valores próximos do uso observado. Depois use LimitRange e ResourceQuota por namespace, remova workloads ociosos e escolha uma distribuição leve, como K3s, para reduzir o consumo do próprio control plane.
Qual a diferença entre requests e limits no Kubernetes?
Requests é a quantidade de CPU e memória que o scheduler reserva para o pod ao decidir em qual nó ele roda. Limits é o teto de uso: ao ultrapassar o limite de CPU o container sofre throttling, e ao ultrapassar o de memória ele pode ser encerrado por OOM kill.
Kubernetes roda bem em um VPS pequeno?
Roda, desde que você use uma distribuição leve como K3s ou MicroK8s e limite o número de componentes extras. O control plane tem um consumo basal de memória e seu uso cresce conforme o tamanho e a atividade do cluster, então em VPS de poucos GB de RAM é essencial manter poucos serviços auxiliares e dimensionar requests com cuidado.
Para que serve o HPA e ele ajuda a economizar?
O Horizontal Pod Autoscaler ajusta o número de réplicas de um Deployment conforme a utilização de CPU ou memória, usando dados do metrics-server. Ele evita manter réplicas sobrando fora do horário de pico, mas só funciona bem se os requests refletirem o consumo real do pod.
Como ver quanto de CPU e memória cada pod consome?
Instale o metrics-server no cluster e execute kubectl top pods -A para ver o consumo por pod, e kubectl top nodes para ver os nós. Compare esses valores com os requests definidos nos manifestos para encontrar pods superdimensionados.
Conclusão
Reduzir o custo de um cluster em VPS depende de medir primeiro e ajustar depois: a distribuição leve diminui o piso de consumo, e requests e limits calibrados evitam pagar por capacidade reservada e não usada.
- Instale o metrics-server e registre o uso médio e o pico de cada pod com
kubectl top. - Ajuste requests e limits, e proteja cada namespace com LimitRange e ResourceQuota.
- Remova workloads ociosos e reavalie o plano do VPS depois de uma semana de uso medido.
Leia também
- Checklist: Kubernetes ou Docker Compose para VPS em 2026
- Otimizar Kubernetes vs Docker no Rocky 10: checklist prático
- n8n no VPS Linux: instale e automatize em 2026
Precisa de ajuda com Kubernetes em VPS?
Um VPS com recursos bem dimensionados é a base para um cluster enxuto e estável. Escolha um plano que caiba na sua carga real e ajuste conforme a medição.