Como usar o Kustomize para gerenciar variações de deploy por ambiente
1. Introdução ao Kustomize e o problema da variação entre ambientes
Manter múltiplos ambientes Kubernetes (dev, staging, production) é um dos maiores desafios na adoção de contêineres. Cada ambiente exige configurações diferentes — número de réplicas, recursos de CPU/memória, variáveis de ambiente, nomes de imagens e secrets. A abordagem ingênua de copiar e colar manifests resulta em duplicação massiva, inconsistências e erros humanos.
O Kustomize resolve esse problema de forma elegante. É uma ferramenta declarativa nativa do kubectl (desde a versão 1.14) que permite personalizar configurações YAML sem usar templates ou linguagens de script. Diferente do Helm, que usa templates Go com lógica condicional, o Kustomize opera puramente com patches e sobreposições, mantendo os manifests originais intactos e legíveis.
As vantagens são claras: simplicidade, ausência de linguagem de template, reutilização de bases comuns e integração direta com kubectl apply -k.
2. Estrutura de diretórios e conceitos fundamentais
A estrutura recomendada para projetos Kustomize segue o padrão base/overlays:
meu-app/
├── base/
│ ├── kustomization.yaml
│ ├── deployment.yaml
│ ├── service.yaml
│ └── configmap.yaml
└── overlays/
├── dev/
│ └── kustomization.yaml
├── staging/
│ └── kustomization.yaml
└── production/
└── kustomization.yaml
O arquivo kustomization.yaml é o coração do sistema. Ele declara quais recursos incluir, quais patches aplicar e como gerar ConfigMaps e Secrets.
O Kustomize suporta duas estratégias de patch:
- Strategic Merge Patch: específico do Kubernetes, faz merge inteligente de listas e maps
- JSON Patch 6902: operações padronizadas (add, remove, replace) para alterações precisas
A ordem de resolução é: base → patches estratégicos → patches JSON → geradores → transformers.
3. Criando uma base reutilizável com recursos comuns
A base deve conter apenas o que é comum a todos os ambientes. Exemplo de base/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- configmap.yaml
commonLabels:
app: meu-app
managed-by: kustomize
E o base/deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: meu-app
spec:
replicas: 1
selector:
matchLabels:
app: meu-app
template:
metadata:
labels:
app: meu-app
spec:
containers:
- name: app
image: minha-imagem:latest
ports:
- containerPort: 8080
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"
Note que usamos valores genéricos. As variações virão nos overlays. O namePrefix e nameSuffix são recursos úteis para evitar conflitos:
# dentro de overlays/dev/kustomization.yaml
namePrefix: dev-
nameSuffix: -v1
Isso transformaria meu-app em dev-meu-app-v1.
4. Personalizando por ambiente com overlays e patches
Cada overlay herda a base e aplica suas próprias modificações. Exemplo para overlays/production/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- patch: |-
- op: replace
path: /spec/replicas
value: 5
- op: replace
path: /spec/template/spec/containers/0/resources/requests/cpu
value: "500m"
- op: replace
path: /spec/template/spec/containers/0/resources/limits/cpu
value: "1000m"
target:
kind: Deployment
name: meu-app
Para dev, usamos patches estratégicos que são mais legíveis:
# overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patchesStrategicMerge:
- patch-deployment.yaml
E o arquivo overlays/dev/patch-deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: meu-app
spec:
replicas: 1
template:
spec:
containers:
- name: app
image: minha-imagem:dev-latest
resources:
requests:
memory: "32Mi"
cpu: "50m"
5. Gerenciando ConfigMaps e Secrets específicos por ambiente
O configMapGenerator cria ConfigMaps a partir de arquivos ou literais, evitando duplicação:
# overlays/production/kustomization.yaml
configMapGenerator:
- name: app-config
literals:
- LOG_LEVEL=info
- DB_HOST=db.production.svc.cluster.local
files:
- config/app.properties
Para secrets, usamos secretGenerator:
secretGenerator:
- name: app-secrets
literals:
- DB_PASSWORD=senha-segura
files:
- secrets/tls.crt
⚠️ Atenção: nunca versionar secrets em texto plano. Use ferramentas como sops (Mozilla) ou Sealed Secrets (Bitnami) para criptografar os dados antes de commit.
6. Trabalhando com múltiplos clusters e namespaces
Para definir namespaces diferentes por ambiente:
# overlays/production/kustomization.yaml
namespace: production
resources:
- ../../base
patchesStrategicMerge:
- patch-namespace.yaml
O patch para alterar namespace em todos os recursos:
# patch-namespace.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: meu-app
namespace: production
Isso garante isolamento completo entre ambientes, mesmo que compartilhem o mesmo cluster.
Para clusters remotos, combine Kustomize com kubectl:
kubectl apply -k overlays/production --context=prod-cluster
7. Fluxo de trabalho e integração com CI/CD
O comando mais útil é kubectl kustomize para visualizar o YAML final sem aplicar:
kubectl kustomize overlays/production > output.yaml
Em pipelines CI/CD, a integração é direta. Exemplo com GitHub Actions:
# .github/workflows/deploy.yml
- name: Deploy to Production
run: |
kubectl apply -k overlays/production --context=prod-cluster
Estratégia por branch:
- Branch main → overlay staging
- Branch release/* → overlay production
- Branch feature/* → overlay dev com prefixo único
Versionamento no Git permite revisar diffs entre ambientes:
git diff HEAD~1 -- overlays/production/
8. Boas práticas, armadilhas comuns e próximos passos
Boas práticas:
- Mantenha a base o mais genérica possível
- Use components para patches reutilizáveis entre overlays
- Prefira patches estratégicos para alterações simples
- Documente cada overlay com comentários no kustomization.yaml
Armadilhas comuns:
- Esquecer de atualizar namePrefix ao criar novo overlay
- Usar patches JSON quando patches estratégicos seriam mais claros
- Ignorar a ordem de aplicação dos patches
Limitações:
- Kustomize não suporta lógica condicional (if/else)
- Para cenários complexos, considere Helm com Kustomize como pós-processador
- Recursos avançados: plugins customizados e transformers permitem extensibilidade
Próximos passos: explore Kustomize Components para criar blocos reutilizáveis de configuração, e Kustomize Plugins para integração com ferramentas externas como Vault ou AWS Secrets Manager.
Referências
- Documentação oficial do Kustomize — Guia completo de referência, exemplos e melhores práticas da ferramenta
- Kubernetes SIG: Kustomize User Guide — Tutorial oficial da comunidade Kubernetes sobre gerenciamento de configurações com Kustomize
- Kustomize: The Right Way to Manage Kubernetes Configurations — Tutorial prático da DigitalOcean com exemplos reais de overlays e patches
- Managing Kubernetes Configurations with Kustomize — Guia do Google Cloud Platform para uso de Kustomize em ambientes de produção
- Kustomize vs Helm: When to Use Each — Comparativo da Red Hat entre Kustomize e Helm, com recomendações de uso