Namespaces em Kubernetes: Isolamento, ResourceQuotas e LimitRanges
Namespaces são um dos conceitos fundamentais do Kubernetes, funcionando como partições lógicas dentro de um cluster. Eles permitem que múltiplos projetos, times ou ambientes (desenvolvimento, staging, produção) coexistam no mesmo cluster físico sem conflitos. Cada namespace possui seu próprio escopo de nomes para recursos como Pods, Services e Deployments, e pode ter políticas de acesso, quotas de recursos e restrições independentes.
O grande diferencial dos namespaces é que eles não são apenas uma questão de organização visual — eles implementam um verdadeiro isolamento lógico. Um desenvolvedor trabalhando no namespace dev não consegue acessar nem ver recursos do namespace prod sem permissões explícitas. Isso é essencial em ambientes corporativos onde segurança e separação de responsabilidades são críticas.
Por que usar Namespaces?
Quando você trabalha com Kubernetes em produção, é raro ter apenas um projeto ou um único time. A maioria das organizações enfrenta o desafio de múltiplas aplicações compartilhando a mesma infraestrutura. Sem namespaces, teríamos conflitos de nomenclatura (dois serviços com o mesmo nome), gerenciamento caótico de permissões, e seria impossível aplicar políticas diferenciadas por projeto.
Namespaces resolvem esse problema oferecendo isolamento de nomes, separação de recursos, controle de acesso granular (via RBAC) e a possibilidade de aplicar quotas e limites específicos por projeto. Além disso, facilitam a limpeza — deletar um namespace remove automaticamente todos os seus recursos.
Isolamento Através de Namespaces
Criação e Gerenciamento Básico
Criar um namespace em Kubernetes é direto. Você pode fazer isso via YAML ou comando kubectl:
kubectl create namespace producao
kubectl create namespace desenvolvimento
kubectl create namespace staging
O equivalente em YAML (mais recomendado para ambientes de produção) seria:
apiVersion: v1
kind: Namespace
metadata:
name: producao
labels:
ambiente: produção
criticidade: alta
---
apiVersion: v1
kind: Namespace
metadata:
name: desenvolvimento
labels:
ambiente: dev
criticidade: baixa
Você pode listar, descrever e deletar namespaces normalmente:
kubectl get namespaces
kubectl describe namespace producao
kubectl delete namespace desenvolvimento
Isolamento de Nomes e Acesso
O isolamento começa com nomes: um Pod chamado api-server no namespace producao é completamente diferente de um Pod api-server no namespace desenvolvimento. Internamente, o Kubernetes qualifica nomes como api-server.producao.svc.cluster.local, garantindo unicidade.
Para acessar um serviço em outro namespace, você usa:
# Dentro do mesmo namespace
curl http://api-server:8080
# De outro namespace
curl http://api-server.producao.svc.cluster.local:8080
Esse isolamento de nomes é apenas o primeiro nível. O acesso real é controlado por RBAC (Role-Based Access Control). Por exemplo, um usuário pode ter permissão para listar Pods apenas no namespace desenvolvimento, mas não em producao. Aqui está um exemplo prático:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: dev-reader
namespace: desenvolvimento
rules:
- apiGroups: [""]
resources: ["pods", "services"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: dev-reader-binding
namespace: desenvolvimento
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: dev-reader
subjects:
- kind: User
name: desenvolvedor@empresa.com
apiGroup: rbac.authorization.k8s.io
Com essa configuração, desenvolvedor@empresa.com pode fazer kubectl get pods -n desenvolvimento, mas kubectl get pods -n producao resultará em "forbidden".
ResourceQuotas: Controlando Consumo de Recursos
O Problema da Falta de Limites
Sem controle, um desenvolvedor desatento pode deployar uma aplicação com bug que consome toda a memória do cluster, prejudicando outros projetos. ResourceQuotas são o mecanismo que previne isso, estabelecendo limites de consumo total por namespace.
Uma ResourceQuota define quantos recursos (CPU, memória, número de Pods, etc.) um namespace inteiro pode usar. Diferentemente de um LimitRange (que veremos depois), a quota é um total para todo o namespace. Se você definir uma quota de 10 Gi de memória, qualquer tentativa de deployar Pods que ultrapassem esse total será rejeitada.
Criando e Aplicando Quotas
Aqui está um exemplo prático de ResourceQuota para um namespace de desenvolvimento:
apiVersion: v1
kind: ResourceQuota
metadata:
name: dev-quota
namespace: desenvolvimento
spec:
hard:
requests.cpu: "10"
requests.memory: "20Gi"
limits.cpu: "20"
limits.memory: "40Gi"
pods: "100"
services: "10"
persistentvolumeclaims: "5"
scopeSelector:
matchExpressions:
- operator: In
scopeName: PriorityClass
values: ["default"]
Essa quota significa:
- O namespace pode ter no máximo 100 Pods
- A soma de todos os requests.cpu dos Pods não pode exceder 10 unidades
- A soma de todos os requests.memory dos Pods não pode exceder 20 Gi
- A soma de todos os limits.cpu não pode exceder 20 unidades
- A soma de todos os limits.memory não pode exceder 40 Gi
- No máximo 10 Services e 5 PersistentVolumeClaims
Vamos criar um Deployment que respeita essa quota:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-app
namespace: desenvolvimento
spec:
replicas: 3
selector:
matchLabels:
app: api-app
template:
metadata:
labels:
app: api-app
spec:
containers:
- name: api
image: nginx:latest
resources:
requests:
cpu: "500m" # 0.5 unidades de CPU
memory: "256Mi" # 256 MiB de memória
limits:
cpu: "1000m" # Máximo 1 unidade de CPU
memory: "512Mi" # Máximo 512 MiB
Com 3 replicas, esse Deployment consumirá:
- Requests: 1.5 CPUs e 768 Mi de memória
- Limits: 3 CPUs e 1.5 Gi de memória
Ainda dentro da quota. Mas se tentarmos escalar para 15 replicas, o scheduler rejeitará os Pods por exceder a quota.
Verificando Quota
kubectl describe resourcequota dev-quota -n desenvolvimento
Você verá algo como:
Used Hard
---- ----
limits.cpu 3 20
limits.memory 1500Mi 40Gi
pods 3 100
requests.cpu 1500m 10
requests.memory 768Mi 20Gi
services 1 10
LimitRanges: Impondo Restrições Individuais
Quando ResourceQuota Não é Suficiente
ResourceQuota controla o total consumido por um namespace, mas não impede que um único Pod use recursos excessivos. Imagine um namespace com quota de 20 Gi de memória: um único container poderia consumir 19 Gi, deixando 1 Gi para todos os outros Pods. LimitRange resolve isso definindo limites e requests padrão, mínimos e máximos por Pod ou container.
LimitRange é uma política de sanidade. Ela garante que nenhum container seja extremamente ganancioso, e que desenvolvedores que se esqueçam de especificar recursos recebam defaults sensatos. É uma camada adicional de proteção que funciona em conjunto com ResourceQuota.
Implementando LimitRanges
Aqui está um LimitRange bem estruturado para um namespace de desenvolvimento:
apiVersion: v1
kind: LimitRange
metadata:
name: dev-limits
namespace: desenvolvimento
spec:
limits:
# Limites para containers
- type: Container
max:
cpu: "2000m"
memory: "2Gi"
min:
cpu: "100m"
memory: "128Mi"
default:
cpu: "500m"
memory: "512Mi"
defaultRequest:
cpu: "250m"
memory: "256Mi"
maxLimitRequestRatio:
cpu: "2"
memory: "2"
# Limites para Pods (soma de todos os containers)
- type: Pod
max:
cpu: "4000m"
memory: "4Gi"
min:
cpu: "200m"
memory: "256Mi"
# Limites para PersistentVolumeClaims
- type: PersistentVolumeClaim
max:
storage: "10Gi"
min:
storage: "1Gi"
Isso significa:
- Cada container pode ter no máximo 2 CPUs e 2 Gi de memória, mínimo 100m de CPU e 128 Mi de memória
- Se um container não especificar recursos, recebe defaults: 500m CPU e 512 Mi memória
- A razão entre limit e request não pode exceder 2 (ex: se request é 500m, limit máximo é 1000m)
- Cada Pod (soma de todos os containers) pode ter no máximo 4 CPUs e 4 Gi, mínimo 200m e 256 Mi
- Cada PersistentVolumeClaim deve estar entre 1 Gi e 10 Gi
Comportamento com LimitRange
Quando você tenta criar um Pod sem especificar recursos:
apiVersion: v1
kind: Pod
metadata:
name: app-sem-recursos
namespace: desenvolvimento
spec:
containers:
- name: app
image: nginx:latest
# Sem spec de resources
O LimitRange automaticamente injeta os defaults:
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
Se você tentar criar um Pod que viola o LimitRange:
apiVersion: v1
kind: Pod
metadata:
name: app-excessivo
namespace: desenvolvimento
spec:
containers:
- name: app
image: nginx:latest
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "5000m" # Viola o máximo de 2000m
memory: "2Gi"
Você receberá um erro: Pod violates LimitRange: limits.cpu: Invalid value: "5000m": must be less than or equal to 2000m
Exemplo Completo: Configurando um Ambiente Multi-tenant
Vamos combinar tudo em um cenário real: uma empresa com três ambientes (desenvolvimento, staging, produção) e políticas diferenciadas para cada um.
---
# NAMESPACE DESENVOLVIMENTO
apiVersion: v1
kind: Namespace
metadata:
name: desenvolvimento
labels:
ambiente: dev
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: dev-quota
namespace: desenvolvimento
spec:
hard:
requests.cpu: "5"
requests.memory: "10Gi"
limits.cpu: "10"
limits.memory: "20Gi"
pods: "50"
---
apiVersion: v1
kind: LimitRange
metadata:
name: dev-limits
namespace: desenvolvimento
spec:
limits:
- type: Container
max:
cpu: "1000m"
memory: "1Gi"
min:
cpu: "100m"
memory: "128Mi"
defaultRequest:
cpu: "250m"
memory: "256Mi"
---
# NAMESPACE STAGING
apiVersion: v1
kind: Namespace
metadata:
name: staging
labels:
ambiente: staging
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: staging-quota
namespace: staging
spec:
hard:
requests.cpu: "20"
requests.memory: "50Gi"
limits.cpu: "40"
limits.memory: "100Gi"
pods: "100"
---
apiVersion: v1
kind: LimitRange
metadata:
name: staging-limits
namespace: staging
spec:
limits:
- type: Container
max:
cpu: "4000m"
memory: "4Gi"
min:
cpu: "100m"
memory: "128Mi"
defaultRequest:
cpu: "500m"
memory: "512Mi"
---
# NAMESPACE PRODUÇÃO
apiVersion: v1
kind: Namespace
metadata:
name: producao
labels:
ambiente: prod
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: prod-quota
namespace: producao
spec:
hard:
requests.cpu: "100"
requests.memory: "200Gi"
limits.cpu: "200"
limits.memory: "400Gi"
pods: "500"
---
apiVersion: v1
kind: LimitRange
metadata:
name: prod-limits
namespace: producao
spec:
limits:
- type: Container
max:
cpu: "8000m"
memory: "8Gi"
min:
cpu: "100m"
memory: "128Mi"
defaultRequest:
cpu: "1000m"
memory: "1Gi"
Agora você pode deployar aplicações em cada namespace com confiança:
kubectl apply -f namespaces.yaml
kubectl get resourcequotas -n desenvolvimento
kubectl describe limitrange dev-limits -n desenvolvimento
Conclusão
Os três conceitos apresentados trabalham em camadas complementares: Namespaces fornecem isolamento lógico e segurança no nível de controle de acesso, ResourceQuotas garantem que um namespace não consuma mais que sua parcela justa de recursos do cluster, e LimitRanges protegem contra containers individuais problemáticos e estabelecem defaults sensatos. Juntos, eles são a base de uma estratégia sólida de multi-tenancy em Kubernetes, permitindo que múltiplos projetos coexistam pacificamente em um cluster compartilhado sem risco de um prejudicar o outro.