Docker & Kubernetes

Boas Práticas de Namespaces em Kubernetes: Isolamento, ResourceQuotas e LimitRanges para Times Ágeis

14 min de leitura

Boas Práticas de Namespaces em Kubernetes: Isolamento, ResourceQuotas e LimitRanges para Times Ágeis

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 não consegue acessar nem ver recursos do namespace 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

<h2>Namespaces em Kubernetes: Isolamento, ResourceQuotas e LimitRanges</h2>

<p>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.</p>

<p>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 <code>dev</code> não consegue acessar nem ver recursos do namespace <code>prod</code> sem permissões explícitas. Isso é essencial em ambientes corporativos onde segurança e separação de responsabilidades são críticas.</p>

<h3>Por que usar Namespaces?</h3>

<p>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.</p>

<p>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.</p>

<h2>Isolamento Através de Namespaces</h2>

<h3>Criação e Gerenciamento Básico</h3>

<p>Criar um namespace em Kubernetes é direto. Você pode fazer isso via YAML ou comando kubectl:</p>

<pre><code class="language-bash">kubectl create namespace producao

kubectl create namespace desenvolvimento

kubectl create namespace staging</code></pre>

<p>O equivalente em YAML (mais recomendado para ambientes de produção) seria:</p>

<pre><code class="language-yaml">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</code></pre>

<p>Você pode listar, descrever e deletar namespaces normalmente:</p>

<pre><code class="language-bash">kubectl get namespaces

kubectl describe namespace producao

kubectl delete namespace desenvolvimento</code></pre>

<h3>Isolamento de Nomes e Acesso</h3>

<p>O isolamento começa com nomes: um Pod chamado <code>api-server</code> no namespace <code>producao</code> é completamente diferente de um Pod <code>api-server</code> no namespace <code>desenvolvimento</code>. Internamente, o Kubernetes qualifica nomes como <code>api-server.producao.svc.cluster.local</code>, garantindo unicidade.</p>

<p>Para acessar um serviço em outro namespace, você usa:</p>

<pre><code class="language-bash"># Dentro do mesmo namespace

curl http://api-server:8080

De outro namespace

curl http://api-server.producao.svc.cluster.local:8080</code></pre>

<p>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 <code>desenvolvimento</code>, mas não em <code>producao</code>. Aqui está um exemplo prático:</p>

<pre><code class="language-yaml">apiVersion: rbac.authorization.k8s.io/v1

kind: Role

metadata:

name: dev-reader

namespace: desenvolvimento

rules:

  • apiGroups: [&quot;&quot;]

resources: [&quot;pods&quot;, &quot;services&quot;]

verbs: [&quot;get&quot;, &quot;list&quot;]

---

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</code></pre>

<p>Com essa configuração, <code>desenvolvedor@empresa.com</code> pode fazer <code>kubectl get pods -n desenvolvimento</code>, mas <code>kubectl get pods -n producao</code> resultará em &quot;forbidden&quot;.</p>

<h2>ResourceQuotas: Controlando Consumo de Recursos</h2>

<h3>O Problema da Falta de Limites</h3>

<p>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.</p>

<p>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.</p>

<h3>Criando e Aplicando Quotas</h3>

<p>Aqui está um exemplo prático de ResourceQuota para um namespace de desenvolvimento:</p>

<pre><code class="language-yaml">apiVersion: v1

kind: ResourceQuota

metadata:

name: dev-quota

namespace: desenvolvimento

spec:

hard:

requests.cpu: &quot;10&quot;

requests.memory: &quot;20Gi&quot;

limits.cpu: &quot;20&quot;

limits.memory: &quot;40Gi&quot;

pods: &quot;100&quot;

services: &quot;10&quot;

persistentvolumeclaims: &quot;5&quot;

scopeSelector:

matchExpressions:

  • operator: In

scopeName: PriorityClass

values: [&quot;default&quot;]</code></pre>

<p>Essa quota significa:</p>

<ul>

<li>O namespace pode ter no máximo 100 Pods</li>

<li>A soma de todos os <code>requests.cpu</code> dos Pods não pode exceder 10 unidades</li>

<li>A soma de todos os <code>requests.memory</code> dos Pods não pode exceder 20 Gi</li>

<li>A soma de todos os <code>limits.cpu</code> não pode exceder 20 unidades</li>

<li>A soma de todos os <code>limits.memory</code> não pode exceder 40 Gi</li>

<li>No máximo 10 Services e 5 PersistentVolumeClaims</li>

</ul>

<p>Vamos criar um Deployment que respeita essa quota:</p>

<pre><code class="language-yaml">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: &quot;500m&quot; # 0.5 unidades de CPU

memory: &quot;256Mi&quot; # 256 MiB de memória

limits:

cpu: &quot;1000m&quot; # Máximo 1 unidade de CPU

memory: &quot;512Mi&quot; # Máximo 512 MiB</code></pre>

<p>Com 3 replicas, esse Deployment consumirá:</p>

<ul>

<li>Requests: 1.5 CPUs e 768 Mi de memória</li>

<li>Limits: 3 CPUs e 1.5 Gi de memória</li>

</ul>

<p>Ainda dentro da quota. Mas se tentarmos escalar para 15 replicas, o scheduler rejeitará os Pods por exceder a quota.</p>

<h3>Verificando Quota</h3>

<pre><code class="language-bash">kubectl describe resourcequota dev-quota -n desenvolvimento</code></pre>

<p>Você verá algo como:</p>

<pre><code>Used Hard

---- ----

limits.cpu 3 20

limits.memory 1500Mi 40Gi

pods 3 100

requests.cpu 1500m 10

requests.memory 768Mi 20Gi

services 1 10</code></pre>

<h2>LimitRanges: Impondo Restrições Individuais</h2>

<h3>Quando ResourceQuota Não é Suficiente</h3>

<p>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.</p>

<p>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.</p>

<h3>Implementando LimitRanges</h3>

<p>Aqui está um LimitRange bem estruturado para um namespace de desenvolvimento:</p>

<pre><code class="language-yaml">apiVersion: v1

kind: LimitRange

metadata:

name: dev-limits

namespace: desenvolvimento

spec:

limits:

Limites para containers

  • type: Container

max:

cpu: &quot;2000m&quot;

memory: &quot;2Gi&quot;

min:

cpu: &quot;100m&quot;

memory: &quot;128Mi&quot;

default:

cpu: &quot;500m&quot;

memory: &quot;512Mi&quot;

defaultRequest:

cpu: &quot;250m&quot;

memory: &quot;256Mi&quot;

maxLimitRequestRatio:

cpu: &quot;2&quot;

memory: &quot;2&quot;

Limites para Pods (soma de todos os containers)

  • type: Pod

max:

cpu: &quot;4000m&quot;

memory: &quot;4Gi&quot;

min:

cpu: &quot;200m&quot;

memory: &quot;256Mi&quot;

Limites para PersistentVolumeClaims

  • type: PersistentVolumeClaim

max:

storage: &quot;10Gi&quot;

min:

storage: &quot;1Gi&quot;</code></pre>

<p>Isso significa:</p>

<ul>

<li><strong>Cada container</strong> pode ter no máximo 2 CPUs e 2 Gi de memória, mínimo 100m de CPU e 128 Mi de memória</li>

<li>Se um container não especificar recursos, recebe defaults: 500m CPU e 512 Mi memória</li>

<li>A razão entre limit e request não pode exceder 2 (ex: se request é 500m, limit máximo é 1000m)</li>

<li><strong>Cada Pod</strong> (soma de todos os containers) pode ter no máximo 4 CPUs e 4 Gi, mínimo 200m e 256 Mi</li>

<li><strong>Cada PersistentVolumeClaim</strong> deve estar entre 1 Gi e 10 Gi</li>

</ul>

<h3>Comportamento com LimitRange</h3>

<p>Quando você tenta criar um Pod sem especificar recursos:</p>

<pre><code class="language-yaml">apiVersion: v1

kind: Pod

metadata:

name: app-sem-recursos

namespace: desenvolvimento

spec:

containers:

  • name: app

image: nginx:latest

Sem spec de resources</code></pre>

<p>O LimitRange automaticamente injeta os defaults:</p>

<pre><code class="language-yaml">resources:

requests:

cpu: &quot;250m&quot;

memory: &quot;256Mi&quot;

limits:

cpu: &quot;500m&quot;

memory: &quot;512Mi&quot;</code></pre>

<p>Se você tentar criar um Pod que viola o LimitRange:</p>

<pre><code class="language-yaml">apiVersion: v1

kind: Pod

metadata:

name: app-excessivo

namespace: desenvolvimento

spec:

containers:

  • name: app

image: nginx:latest

resources:

requests:

cpu: &quot;100m&quot;

memory: &quot;128Mi&quot;

limits:

cpu: &quot;5000m&quot; # Viola o máximo de 2000m

memory: &quot;2Gi&quot;</code></pre>

<p>Você receberá um erro: <code>Pod violates LimitRange: limits.cpu: Invalid value: &quot;5000m&quot;: must be less than or equal to 2000m</code></p>

<h2>Exemplo Completo: Configurando um Ambiente Multi-tenant</h2>

<p>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.</p>

<pre><code class="language-yaml">---

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: &quot;5&quot;

requests.memory: &quot;10Gi&quot;

limits.cpu: &quot;10&quot;

limits.memory: &quot;20Gi&quot;

pods: &quot;50&quot;

---

apiVersion: v1

kind: LimitRange

metadata:

name: dev-limits

namespace: desenvolvimento

spec:

limits:

  • type: Container

max:

cpu: &quot;1000m&quot;

memory: &quot;1Gi&quot;

min:

cpu: &quot;100m&quot;

memory: &quot;128Mi&quot;

defaultRequest:

cpu: &quot;250m&quot;

memory: &quot;256Mi&quot;

---

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: &quot;20&quot;

requests.memory: &quot;50Gi&quot;

limits.cpu: &quot;40&quot;

limits.memory: &quot;100Gi&quot;

pods: &quot;100&quot;

---

apiVersion: v1

kind: LimitRange

metadata:

name: staging-limits

namespace: staging

spec:

limits:

  • type: Container

max:

cpu: &quot;4000m&quot;

memory: &quot;4Gi&quot;

min:

cpu: &quot;100m&quot;

memory: &quot;128Mi&quot;

defaultRequest:

cpu: &quot;500m&quot;

memory: &quot;512Mi&quot;

---

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: &quot;100&quot;

requests.memory: &quot;200Gi&quot;

limits.cpu: &quot;200&quot;

limits.memory: &quot;400Gi&quot;

pods: &quot;500&quot;

---

apiVersion: v1

kind: LimitRange

metadata:

name: prod-limits

namespace: producao

spec:

limits:

  • type: Container

max:

cpu: &quot;8000m&quot;

memory: &quot;8Gi&quot;

min:

cpu: &quot;100m&quot;

memory: &quot;128Mi&quot;

defaultRequest:

cpu: &quot;1000m&quot;

memory: &quot;1Gi&quot;</code></pre>

<p>Agora você pode deployar aplicações em cada namespace com confiança:</p>

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

kubectl get resourcequotas -n desenvolvimento

kubectl describe limitrange dev-limits -n desenvolvimento</code></pre>

<h2>Conclusão</h2>

<p>Os três conceitos apresentados trabalham em camadas complementares: <strong>Namespaces</strong> fornecem isolamento lógico e segurança no nível de controle de acesso, <strong>ResourceQuotas</strong> garantem que um namespace não consuma mais que sua parcela justa de recursos do cluster, e <strong>LimitRanges</strong> 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.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/" target="_blank" rel="noopener noreferrer">Kubernetes Documentation: Namespaces</a></li>

<li><a href="https://kubernetes.io/docs/concepts/policy/resource-quotas/" target="_blank" rel="noopener noreferrer">Kubernetes Documentation: Resource Quotas</a></li>

<li><a href="https://kubernetes.io/docs/concepts/policy/limit-range/" target="_blank" rel="noopener noreferrer">Kubernetes Documentation: Limit Ranges</a></li>

<li><a href="https://kubernetes.io/docs/concepts/configuration/overview/" target="_blank" rel="noopener noreferrer">Kubernetes Best Practices: Resource Management</a></li>

<li><a href="https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/" target="_blank" rel="noopener noreferrer">Managing Resources for Containers - Kubernetes Official</a></li>

</ul>

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

Comentários

Mais em Docker & Kubernetes

Network Policies em Kubernetes: Isolamento de Rede entre Pods: Do Básico ao Avançado
Network Policies em Kubernetes: Isolamento de Rede entre Pods: Do Básico ao Avançado

Network Policies em Kubernetes: Isolamento de Rede entre Pods Network Policie...

Boas Práticas de Flux CD: GitOps Alternativo com Kustomize e Helm Controller para Times Ágeis
Boas Práticas de Flux CD: GitOps Alternativo com Kustomize e Helm Controller para Times Ágeis

O que é Flux CD e por que GitOps? Flux CD é um operador Kubernetes que implem...

Boas Práticas de Imagens Docker: Layers, Union Filesystem e Como o Build Realmente Funciona para Times Ágeis
Boas Práticas de Imagens Docker: Layers, Union Filesystem e Como o Build Realmente Funciona para Times Ágeis

Introdução: O Que São Layers e Por Que Importam Docker revolucionou a forma c...