O gerenciamento eficiente de recursos CPU e memória é um dos pilares fundamentais para a estabilidade, performance e custos operacionais em ambientes Kubernetes e OpenShift. Sem uma configuração adequada, aplicações podem consumir recursos desproporcionalmente, causando instabilidade no nó (node), falhas em outros pods críticos ou degradação geral do cluster. Este tutorial técnico detalha como configurar, monitorar e otimizar os limites (limits) e solicitações (requests) de recursos no OpenShift, garantindo que sua infraestrutura virtualizada opere com máxima eficiência.
Entendendo Requests e Limits
No ecossistema Kubernetes, subjacente ao OpenShift, o scheduler utiliza duas métricas principais para decidir onde alojar um pod: requests e limits. Compreender a distinção entre eles é crucial para uma gestão de recursos eficaz.
Solicitações (Requests): Representam a quantidade garantida de CPU ou memória que o container precisa para funcionar corretamente. O scheduler do Kubernetes usa os requests para decidir em qual nó colocar o pod. Ele garante que, ao agendar o pod naquele nó, haja recursos suficientes disponíveis para atender àquela solicitação. Se um container precisar de mais recursos do que o solicitado durante a execução, ele pode usar até o limite definido, mas o scheduler não reserva isso antecipadamente.
Limites (Limits): Definem o teto máximo de CPU ou memória que um container é permitido utilizar. Se um pod exceder o limite de CPU, seu processo será throttled (limitado), resultando em latência aumentada e possível degradação de performance. Se um pod exceder o limite de memória, o sistema operacional do nó (kernel Linux) invocará o OOM Killer (Out of Memory Killer), matando o processo do container para salvar o restante do sistema. Portanto, os limites atuam como uma medida de proteção contra consumo descontrolado.
Configuração via YAML de Deployments
A maneira mais comum e recomendada de definir esses recursos é diretamente no manifesto YAML do seu Deployment ou StatefulSet. Abaixo, apresentamos um exemplo prático de configuração para uma aplicação web típica.
apiVersion: apps/v1
kind: Deployment
metadata:
name: minha-aplicacao
namespace: meu-projeto
spec:
replicas: 3
selector:
matchLabels:
app: minha-aplicacao
template:
metadata:
labels:
app: minha-aplicacao
spec:
containers:
- name: app-container
image: registry.redhat.io/myapp:v1.0
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
Neste exemplo, cada réplica da aplicação solicita 250 millicores de CPU e 256 MiB de memória. O scheduler garantirá que esses recursos estejam disponíveis nos nós antes de agendar o pod. No entanto, a aplicação é permitida a usar até 500 millicores de CPU e 512 MiB de memória se necessário. Note a sintaxe: cpu usa millicores (onde 1 core = 1000m) ou cores inteiros, enquanto memory usa sufixos binários como Ki, Mi, Gi.
Implementação de ResourceQuota por Namespace
Em ambientes multi-tenant ou projetos compartilhados no OpenShift, é essencial evitar que um único namespace consuma todos os recursos disponíveis do cluster. O objeto ResourceQuota permite definir limites agregados para todo um namespace.
Crie um arquivo chamado resource-quota.yaml com a seguinte estrutura:
apiVersion: v1
kind: ResourceQuota
metadata:
name: quota-recursos
namespace: meu-projeto
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "10"
Para aplicar essa configuração, execute o comando:
oc apply -f resource-quota.yaml
Com esta configuração, o namespace meu-projeto não poderá criar pods que, somados, ultrapassem 4 CPUs solicitadas e 8 GiB de memória. Isso impede que uma aplicação mal configurada consuma recursos destinados a outras cargas de trabalho no mesmo projeto.
Otimização com LimitRange
Muitas vezes, desenvolvedores esquecem de definir resources em seus containers, o que pode levar a problemas de escalabilidade ou consumo excessivo. O objeto LimitRange define padrões padrão (default) para recursos no namespace.
Crie um arquivo limit-range.yaml:
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: meu-projeto
spec:
limits:
- default:
cpu: "500m"
memory: "256Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
type: Container
Quando você aplicar este arquivo com oc apply -f limit-range.yaml, qualquer container criado no namespace que não especifique explicitamente seus recursos receberá automaticamente os valores definidos em default e defaultRequest. Isso garante um comportamento consistente e previne a falta de definição de recursos.
Monitoramento e Análise de Uso Real
A teoria é importante, mas a prática exige dados. O OpenShift fornece ferramentas poderosas para monitorar o consumo real versus os recursos alocados. O painel do Prometheus integrado ao OpenShift Console é ideal para visualizar métricas em tempo real.
Identificando Subutilização
Se você notar que um pod está utilizando apenas 10% de seu limite de CPU, é provável que seus limits estejam superestimados. Isso pode impedir que outros pods sejam agendados no mesmo nó, pois o scheduler acredita que há menos recursos disponíveis do que realmente existem. No console do OpenShift, navegue até a aba "Monitoring" e selecione "Pods". Filtre por seu namespace e observe as métricas de CPU e Memory Usage em relação aos Limits.
Identificando Overcommit e Throttling
A subutilização de memória é menos crítica, pois o kernel Linux libera memória não utilizada para outros processos. No entanto, a subutilização de CPU indica ineficiência. Por outro lado, se você observar picos constantes de CPU próximos ao limite ou métricas de Throttled Time no Prometheus, significa que sua aplicação está sendo impedida de usar mais poder de processamento do que o permitido. Nesse caso, considere aumentar o limit de CPU.
Para verificar throttling via CLI, você pode consultar as métricas diretamente:
oc adm top pod -n meu-projeto
Este comando mostra o uso atual de CPU e memória dos pods. Compare os valores com os definidos no YAML. Se o uso for consistentemente alto perto do limite, ajuste a configuração.
Configurações Avançadas: QoS Classes
O Kubernetes classifica os pods em três classes de Qualidade de Serviço (QoS) baseadas na relação entre requests e limits:
- Guaranteed: Quando
requestssão iguais alimitspara todos os containers no pod. Esses pods têm a maior prioridade durante o eviction (remoção forçada) de recursos. - Burstable: Quando
requestssão menores quelimits, ou se apenas alguns containers têm recursos definidos. Esta é a configuração mais comum, mas oferece garantia menor contra evicções sob pressão de recursos no nó. - BestEffort: Quando nenhum recurso é definido para nenhum container. Esses pods são os primeiros a ser removidos quando o nó fica sem recursos.
Para aplicações críticas do OpenShift, recomenda-se fortemente configurar as classes como Guaranteed. Isso exige que você determine com precisão a necessidade média da aplicação e defina requests e limits iguais. Embora isso reduza a flexibilidade de "burstable" (uso de picos), garante que a aplicação não será removida durante momentos de alta carga no cluster.
Cenário Prático: Ajuste Dinâmico
Vamos simular um ajuste na configuração de uma aplicação existente. Suponha que você tenha um Deployment chamado web-frontend e precise ajustar os recursos devido a mudanças no tráfego.
Primeiro, edite o deployment:
oc edit deployment web-frontend -n meu-projeto
Isso abrirá o editor padrão do sistema. Localize a seção resources dentro do template do pod e altere os valores conforme necessário. Por exemplo, para aumentar a capacidade de memória:
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"
Ao salvar e sair do editor, o OpenShift realizará um rolling update, atualizando os pods gradualmente para respeitar as novas configurações. É crucial verificar se o novo request de memória cabe nos recursos disponíveis do cluster antes de aplicar a mudança, caso contrário, o agendamento falhará.
Boas Práticas e Conclusão
A gestão de recursos no OpenShift não é um evento único, mas um ciclo contínuo de monitoramento e ajuste. Siga estas diretrizes para manter sua infraestrutura saudável:
- Sempre defina Requests e Limits: Nunca dependa dos padrões globais ou deixe os pods sem definições explícitas em ambientes de produção.
- Moneitore o Throttling: Se sua aplicação está lenta, verifique se ela está sendo throttled pela CPU. Aumentar o limit pode resolver, mas investigar a otimização do código é a solução raiz.
- Use ResourceQuotas para governança: Proteja seus namespaces contra consumo excessivo por equipes individuais.
- Teste em Staging: Utilize ambientes de staging para determinar os valores ideais de resources antes de aplicar em produção. Ferramentas de profiling podem ajudar a identificar o consumo real de picos de CPU e memória.
Ao dominar o gerenciamento de CPU e memória no OpenShift, você não apenas melhora a performance das suas aplicações, mas também otimiza a utilização do hardware subjacente, resultando em uma infraestrutura mais robusta, previsível e econômica. Lembre-se: a transparência sobre o consumo de recursos é a chave para um ambiente Kubernetes ou OpenShift bem-sucedido.