Gerenciamento de configurações em produção: ConfigMaps e Secrets
1. Fundamentos da separação entre código e configuração
Em ambientes de produção, um dos princípios mais importantes da engenharia de software é a separação entre código e configuração. Quando configurações como URLs de banco de dados, chaves de API ou parâmetros de ambiente ficam hardcoded no código-fonte, cada alteração exige uma nova compilação, novo build de imagem e novo deploy. Isso torna o processo lento, propenso a erros e incompatível com práticas modernas de CI/CD.
O Kubernetes resolve esse problema com um modelo declarativo, onde ConfigMaps e Secrets são recursos nativos que permitem injetar configurações em Pods sem modificar as imagens dos containers. Dessa forma, uma mesma imagem pode ser promovida entre ambientes (dev, staging, prod) simplesmente alterando os objetos de configuração.
2. ConfigMaps: armazenando dados de configuração não sensíveis
ConfigMaps são objetos do Kubernetes projetados para armazenar dados de configuração não confidenciais em pares chave-valor. Eles podem ser criados a partir de literais, arquivos ou diretórios inteiros.
Criação a partir de literais:
kubectl create configmap app-config --from-literal=LOG_LEVEL=debug --from-literal=MAX_CONNECTIONS=100
Criação a partir de arquivos:
# arquivo: application.properties
kubectl create configmap app-properties --from-file=./application.properties
Injeção como variáveis de ambiente no Pod:
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:1.0
envFrom:
- configMapRef:
name: app-config
Injeção como volume montado (atualização automática):
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:1.0
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: app-config
Boas práticas: nomeie ConfigMaps com escopo claro (frontend-config, api-config), use namespaces para isolar ambientes e evite armazenar dados sensíveis neles.
3. Secrets: protegendo dados sensíveis em produção
Secrets são similares aos ConfigMaps, mas projetados para dados sensíveis como senhas, tokens e chaves SSH. É fundamental entender que Secrets não são criptografados por padrão — eles apenas usam codificação base64. A segurança real vem da criptografia em repouso no etcd e do controle de acesso via RBAC.
Criação manual:
kubectl create secret generic db-credentials \
--from-literal=username=admin \
--from-literal=password=S3nh@F0rt3
Criação a partir de arquivos:
kubectl create secret generic tls-secret \
--from-file=tls.crt=./cert.pem \
--from-file=tls.key=./key.pem
Consumo como variáveis de ambiente:
apiVersion: v1
kind: Pod
metadata:
name: db-pod
spec:
containers:
- name: app
image: myapp:1.0
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
Consumo como volume montado (recomendado para atualizações dinâmicas):
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:1.0
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: db-credentials
4. Estratégias de atualização sem downtime
Em produção, atualizar configurações sem interromper o serviço é essencial. Quando ConfigMaps e Secrets são montados como volumes, o kubelet sincroniza as mudanças automaticamente. Porém, a aplicação precisa ser capaz de detectar alterações nos arquivos montados.
Exemplo de aplicação que recarrega configuração automaticamente:
# Aplicação Node.js que monitora alterações no arquivo de configuração
const fs = require('fs');
const configPath = '/etc/config/app.properties';
function loadConfig() {
const data = fs.readFileSync(configPath, 'utf8');
console.log('Configuração recarregada:', data);
}
fs.watchFile(configPath, (curr, prev) => {
console.log('Arquivo modificado, recarregando...');
loadConfig();
});
loadConfig();
Limitações: O tempo de propagação pode levar alguns minutos (padrão: 60 segundos de sincronização). Para ambientes críticos, considere usar ConfigMaps imutáveis com rolling update:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config-v2
immutable: true
data:
LOG_LEVEL: warn
MAX_CONNECTIONS: 200
Com ConfigMaps imutáveis, você cria uma nova versão (app-config-v2) e atualiza a referência no Deployment, que fará um rolling update gradual.
5. Gerenciamento de ciclo de vida e versionamento
Para ambientes críticos, a imutabilidade de ConfigMaps e Secrets é uma prática recomendada. Ela impede alterações acidentais e permite rastrear qual versão da configuração estava ativa em cada deploy.
Estratégia de nomenclatura:
api-config-v1 # Versão inicial
api-config-v2 # Após alteração de parâmetros
api-config-v3 # Nova alteração
Política de limpeza: Após confirmar que uma versão antiga não está mais em uso, remova-a:
kubectl delete configmap api-config-v1
Garbage collection: Use labels para agrupar ConfigMaps por release e facilitar a limpeza:
kubectl delete configmap -l release=v1.0
6. Segurança avançada e integração com ferramentas externas
Para ambientes de produção reais, a segurança dos Secrets deve ir além do básico.
Criptografia em repouso no etcd:
# /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aesgcm:
keys:
- name: key1
secret: c2VjcmV0LWtleS0xMjM0NTY3ODkw
- identity: {}
Integração com HashiCorp Vault usando o CSI Driver:
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: vault-db-secret
spec:
provider: vault
parameters:
vaultAddress: "https://vault.example.com"
roleName: "app-role"
objects: |
- objectName: "db-password"
secretPath: "secret/data/db"
secretKey: "password"
RBAC para controle de acesso:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list"]
7. Casos de uso práticos e padrões de produção
Configuração de múltiplos ambientes:
# Namespace: dev
kubectl create configmap app-config -n dev \
--from-literal=DB_URL=localhost:5432 \
--from-literal=LOG_LEVEL=debug
# Namespace: prod
kubectl create configmap app-config -n prod \
--from-literal=DB_URL=prod-db.internal:5432 \
--from-literal=LOG_LEVEL=warn
Credenciais de banco de dados como Secrets:
kubectl create secret generic db-credentials \
--from-literal=username=app_user \
--from-literal=password=$(openssl rand -base64 32)
Combinação com Helm charts:
# values.yaml
config:
logLevel: info
maxConnections: 100
secrets:
dbPassword: "CHANGE_ME"
# templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-config
data:
LOG_LEVEL: {{ .Values.config.logLevel }}
MAX_CONNECTIONS: {{ .Values.config.maxConnections | quote }}
Esse padrão permite versionar templates e injetar valores específicos por ambiente, mantendo Secrets protegidos em sistemas externos como Vault ou AWS Secrets Manager.
Referências
- Kubernetes Documentation: ConfigMaps — Documentação oficial sobre criação, gerenciamento e consumo de ConfigMaps no Kubernetes.
- Kubernetes Documentation: Secrets — Guia completo sobre Secrets, incluindo criação, segurança e melhores práticas.
- Kubernetes Documentation: Encryption at Rest — Tutorial oficial para configurar criptografia de dados em repouso no etcd.
- HashiCorp Vault CSI Provider — Tutorial oficial de integração do Vault com Kubernetes usando o Secrets Store CSI Driver.
- Kubernetes RBAC Documentation — Documentação detalhada sobre controle de acesso baseado em papéis para recursos como Secrets e ConfigMaps.
- Helm: ConfigMaps and Secrets Best Practices — Guia de boas práticas da Helm para gerenciar ConfigMaps e Secrets em charts.