Resource Quotas e LimitRanges: governança de recursos
1. Introdução à Governança de Recursos no Kubernetes
Em ambientes Kubernetes multi-tenant, a governança de recursos não é opcional — é uma necessidade operacional. Sem controles adequados, um único workload pode consumir toda a capacidade do cluster, prejudicando aplicações vizinhas. ResourceQuotas e LimitRanges são as ferramentas nativas do Kubernetes para implementar essa governança.
A governança opera em três camadas conceituais:
- Requests: reserva mínima garantida para o container no nó
- Limits: teto máximo que o container pode consumir (sujeito a throttling em CPU e OOMKill em memória)
- Uso real: métrica observada, que deve ficar entre request e limit
O ResourceQuota atua no nível do namespace, limitando o consumo agregado. O LimitRange opera no nível do pod/container, definindo valores padrão e restrições individuais. Juntos, formam um sistema complementar de controle.
2. ResourceQuotas: Limitando o Consumo por Namespace
Um ResourceQuota é um objeto Kubernetes que restringe o consumo total de recursos computacionais, de armazenamento e a quantidade de objetos dentro de um namespace.
Estrutura básica:
apiVersion: v1
kind: ResourceQuota
metadata:
name: quota-computacional
namespace: dev-team
spec:
hard:
requests.cpu: "4"
requests.memory: "8Gi"
limits.cpu: "8"
limits.memory: "16Gi"
persistentvolumeclaims: "5"
pods: "20"
services: "10"
configmaps: "15"
Quando aplicamos essa quota, qualquer tentativa de criar recursos que excedam esses limites é rejeitada imediatamente pelo API Server. O comando kubectl apply -f quota.yaml registra a política, e o controlador de admissão valida todas as operações subsequentes.
Exemplo de violação: se tentarmos criar um pod com limits.memory: 20Gi em um namespace que já consumiu 12Gi, a API retorna:
Error from server (Forbidden): pods "meu-pod" is forbidden: exceeded quota: quota-computacional, requested: limits.memory=20Gi, used: limits.memory=12Gi, limited: limits.memory=16Gi
3. Tipos de Escopo em ResourceQuotas
Os escopos permitem granularidade fina nas quotas. O Kubernetes suporta quatro escopos padrão:
| Escopo | Descrição |
|---|---|
BestEffort |
Pods sem requests/limits definidos (QoS classe BestEffort) |
NotBestEffort |
Pods com pelo menos um request ou limit definido |
Terminating |
Pods com spec.activeDeadlineSeconds >= 0 |
NotTerminating |
Pods sem deadline definido |
Exemplo prático: limitar pods BestEffort a 1 CPU e 512Mi de memória agregados:
apiVersion: v1
kind: ResourceQuota
metadata:
name: quota-best-effort
namespace: dev-team
spec:
hard:
pods: "10"
scopeSelector:
matchExpressions:
- operator: In
scopeName: BestEffort
Isso impede que workloads sem requests definidos consumam recursos ilimitados — uma prática comum em ambientes de desenvolvimento desorganizados.
4. LimitRanges: Definindo Limites Padrão e Mínimos/Máximos
Enquanto a quota controla o agregado, o LimitRange regula as dimensões individuais dos containers. Ele pode:
- Definir valores padrão de
requestselimits - Estabelecer mínimos e máximos por container/pod
- Forçar a especificação de limites em todos os containers
Exemplo de LimitRange:
apiVersion: v1
kind: LimitRange
metadata:
name: limits-padrao
namespace: dev-team
spec:
limits:
- max:
cpu: "2"
memory: "2Gi"
min:
cpu: "100m"
memory: "128Mi"
default:
cpu: "500m"
memory: "512Mi"
defaultRequest:
cpu: "200m"
memory: "256Mi"
type: Container
Quando um pod é criado sem especificar recursos, o LimitRange injeta automaticamente os valores default como limits e defaultRequest como requests. Se o pod tentar definir valores fora do range min-max, a criação é bloqueada.
5. Interação entre ResourceQuotas e LimitRanges
A ordem de validação é crucial: primeiro o LimitRange aplica defaults e valida mínimos/máximos, depois o ResourceQuota verifica se o consumo agregado não excede o permitido.
Cenário problemático: Suponha uma quota com limits.memory: 8Gi e um LimitRange com default: memory: 1Gi. Se 9 pods forem criados sem especificar memória, o LimitRange injeta 1Gi em cada, totalizando 9Gi — excedendo a quota. O nono pod será rejeitado.
Estratégia para evitar conflitos: Calcule a quota considerando os defaults do LimitRange:
# Quota com folga para 10 pods com default de 1Gi cada
spec:
hard:
limits.memory: "12Gi" # 10Gi para pods + 2Gi de margem
Sempre documente essa relação entre quota e LimitRange para evitar surpresas durante deploys automatizados.
6. Boas Práticas para Governança de Recursos
-
Defina quotas antes de qualquer workload: Crie ResourceQuota e LimitRange como parte do bootstrap do namespace, antes que qualquer pod seja implantado.
-
Monitore ativamente: Use
kubectl describe quota -n <namespace>para ver consumo atual vs hard limit. Ferramentas como Prometheus + Grafana podem alertar quando o uso se aproxima de 80% da quota. -
Use namespaces diferentes para ambientes distintos:
- Produção: quotas mais generosas, LimitRange com defaults conservadores
-
Desenvolvimento: quotas restritas, LimitRange forçando mínimos baixos
-
Revise periodicamente: A análise de utilização histórica ajuda a recalibrar limites. Se um namespace usa consistentemente apenas 30% da quota, reduza-a para liberar recursos.
-
Combine com Horizontal Pod Autoscaler (HPA): Quotas muito apertadas podem impedir o HPA de escalar. Sempre teste cenários de pico.
7. Casos de Uso e Troubleshooting
Problema: Pod não cria com erro de quota
$ kubectl get events -n dev-team --field-selector reason=FailedCreate
1m Warning FailedCreate replicaset/app-7d8f9 Error creating: pods "app-7d8f9-xk4m2" is forbidden: exceeded quota: quota-computacional, requested: pods=1, used: pods=20, limited: pods=20
Solução: Aumente a quota ou reduza o número de réplicas. Use kubectl describe quota para ver o consumo atual.
Problema: Pod fica em Pending sem motivo aparente
O pod pode estar solicitando mais recursos do que qualquer nó pode oferecer. Verifique com:
$ kubectl describe pod app-pendente
Events:
Type Reason Age From Message
Warning FailedScheduling 10s default-scheduler 0/5 nodes are available: 3 Insufficient cpu, 2 Insufficient memory.
Cenário real: Namespace de desenvolvimento com quota de 2 CPUs e 4Gi de memória, LimitRange com default de 500m CPU. Times diferentes criam pods sem especificar recursos — todos recebem 500m, mas rapidamente excedem a quota. A solução foi educar os times a especificar requests realistas e aumentar a quota para 4 CPUs.
Referências
- Kubernetes Official Documentation: Resource Quotas — Documentação oficial completa sobre ResourceQuotas, incluindo todos os recursos gerenciáveis e exemplos de YAML
- Kubernetes Official Documentation: Limit Ranges — Guia oficial sobre LimitRanges, com explicação detalhada de cada campo e tipos de limite
- Kubernetes: Configure Quality of Service for Pods — Tutorial prático sobre classes de QoS (Guaranteed, Burstable, BestEffort) e como LimitRanges as afetam
- Kubernetes Best Practices: Resource Requests and Limits — Artigo do Google Cloud sobre boas práticas, incluindo estratégias de quotas e monitoramento
- Kubernetes Resource Management and Quotas — Tutorial da DigitalOcean com exemplos práticos de ResourceQuota e LimitRange em cenários multi-tenant
- Kubernetes: Managing Compute Resources — Documentação base sobre requests e limits, essencial para entender o funcionamento antes de aplicar quotas