StatefulSets & Armazenamento Persistente no Kubernetes
Implante aplicativos stateful com dimensionamento ordenado e dados persistentes
Kubernetes StatefulSets são a solução ideal para gerenciar aplicações stateful que exigem identidades estáveis, armazenamento persistente e padrões de implantação ordenados — essenciais para bancos de dados, sistemas distribuídos e camadas de cache.
Se você é novo no Kubernetes ou está configurando um cluster, considere explorar distribuições do Kubernetes como k3s ou MicroK8s para desenvolvimento, ou instalar Kubernetes com Kubespray para clusters de produção.
Esta imagem agradável foi gerada pelo modelo AI Flux 1 dev.
O que são StatefulSets?
StatefulSets são um objeto de API de carga de trabalho do Kubernetes projetado especificamente para gerenciar aplicações stateful. Ao contrário de Deployments, que tratam todos os pods como intercambiáveis, StatefulSets mantêm uma identidade única para cada pod com garantias sobre a ordem e a unicidade.
Funcionalidades Principais:
- Identificadores de Rede Estáveis: Cada pod recebe um hostname previsível que persiste após reinícios
- Armazenamento Persistente: Reivindicações de Volume Permanente dedicadas que acompanham os pods durante reschedules
- Implantação Ordenada: Os pods são criados sequencialmente (0, 1, 2…) e terminam na ordem inversa
- Atualizações Ordenadas: Atualizações em rolagem prosseguem na ordem, garantindo a estabilidade da aplicação
StatefulSets são fundamentais para aplicações como PostgreSQL, MySQL, MongoDB, Cassandra, Elasticsearch, Kafka, ZooKeeper, Redis e etcd — qualquer carga de trabalho onde a identidade do pod e a persistência dos dados importam.
Entendendo o Armazenamento Persistente no Kubernetes
O Kubernetes fornece uma camada abstrata de armazenamento sofisticada que desconecta o gerenciamento de armazenamento do ciclo de vida do pod:
Componentes de Armazenamento
PersistentVolume (PV): Um pedaço de armazenamento no cluster provisionado por um administrador ou criado dinamicamente via StorageClass. Os PVs existem independentemente dos pods.
PersistentVolumeClaim (PVC): Uma solicitação de armazenamento por um pod. Os PVCs se vinculam a PVs disponíveis que correspondem a seus requisitos (tamanho, modo de acesso, classe de armazenamento).
StorageClass: Define diferentes “classes” de armazenamento com diversos provisionadores (AWS EBS, GCE PD, Azure Disk, NFS, etc.) e parâmetros como replicação, camadas de desempenho e políticas de backup.
Modos de Acesso
- ReadWriteOnce (RWO): Volume montado como leitura-escrita por um único nó
- ReadOnlyMany (ROX): Volume montado como somente leitura por muitos nós
- ReadWriteMany (RWX): Volume montado como leitura-escrita por muitos nós (requer backends de armazenamento especiais)
Arquitetura de Armazenamento do StatefulSet
StatefulSets usam volumeClaimTemplates para criar automaticamente PersistentVolumeClaims para cada réplica do pod. Isso é fundamentalmente diferente de Deployments:
Como volumeClaimTemplates Funcionam
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql-service
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: data
mountPath: /var/lib/mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "fast-ssd"
resources:
requests:
storage: 10Gi
Quando você cria este StatefulSet:
- O Kubernetes cria o pod
mysql-0e o PVCdata-mysql-0 - Em seguida, cria o pod
mysql-1e o PVCdata-mysql-1 - Finalmente, cria o pod
mysql-2e o PVCdata-mysql-2
Cada pod recebe seu próprio volume persistente de 10 GB dedicado. Se o mysql-1 for excluído ou rescheduleado, o Kubernetes o recria e reanexa o mesmo PVC data-mysql-1, preservando todos os dados.
Criando um Serviço Headless para StatefulSets
StatefulSets exigem um Serviço Headless para fornecer identidades de rede estáveis:
apiVersion: v1
kind: Service
metadata:
name: mysql-service
spec:
clusterIP: None # Isso torna-o um serviço headless
selector:
app: mysql
ports:
- port: 3306
name: mysql
Isso cria entradas DNS para cada pod:
mysql-0.mysql-service.default.svc.cluster.localmysql-1.mysql-service.default.svc.cluster.localmysql-2.mysql-service.default.svc.cluster.local
Aplicações podem se conectar diretamente a instâncias específicas de pod usando esses nomes DNS estáveis.
Padrões de Implantação do StatefulSet
Para equipes que gerenciam implantações complexas no Kubernetes, Helm Charts oferecem uma maneira poderosa de empacotar e implantar StatefulSets com modelagem, versionamento e gerenciamento de dependências. O Helm simplifica o gerenciamento de configurações de StatefulSet em diferentes ambientes.
Escalando em Ordem
Ao escalar de 3 para 5 réplicas:
kubectl scale statefulset mysql --replicas=5
O Kubernetes cria os pods em ordem: mysql-3 → aguarda o Ready → mysql-4
Ao escalar de 5 para 3 réplicas:
kubectl scale statefulset mysql --replicas=3
O Kubernetes termina em ordem inversa: mysql-4 → aguarda a terminação → mysql-3
Atualizações em Rolagem
StatefulSets suportam duas estratégias de atualização:
OnDelete: Atualizações manuais — os pods só são atualizados quando você os exclui RollingUpdate: Atualizações automáticas sequenciais em ordem inversa
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 2 # Apenas atualize pods com ordinal >= 2
O parâmetro partition permite implantações canárias — você pode atualizar primeiro os pods com números mais altos e testar antes de implantar em todas as réplicas.
Boas Práticas de Armazenamento
Provisionamento Dinâmico
Sempre use StorageClasses para provisionamento dinâmico de volumes:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp3
iops: "3000"
throughput: "125"
allowVolumeExpansion: true
reclaimPolicy: Retain
allowVolumeExpansion: Habilita o redimensionamento de PVCs sem recriá-los
reclaimPolicy: Retain mantém os dados do PV após a exclusão do PVC, Delete remove-os automaticamente
Políticas de Retenção de PVC
O Kubernetes 1.23+ suporta persistentVolumeClaimRetentionPolicy:
spec:
persistentVolumeClaimRetentionPolicy:
whenDeleted: Retain # Mantenha os PVCs quando o StatefulSet for excluído
whenScaled: Delete # Exclua os PVCs ao escalar para baixo
Opções:
- Retain: Mantenha os PVCs (comportamento padrão, mais seguro)
- Delete: Exclua automaticamente os PVCs (útil para ambientes de desenvolvimento)
Estratégias de Backup
Snapshots de Volume: Use recursos de VolumeSnapshot para criar backups em pontos de tempo
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: mysql-snapshot-20251113
spec:
volumeSnapshotClassName: csi-snapclass
source:
persistentVolumeClaimName: data-mysql-0
Backups no Nível da Aplicação: Use ferramentas como mysqldump, pg_dump ou Velero para backups específicos de banco de dados
Replicação Distribuída: Configure replicação no nível da aplicação (replicação do MySQL, replicação de streaming do PostgreSQL) como primeira linha de defesa
Casos de Uso Reais
Cluster de Banco de Dados (PostgreSQL)
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: postgres
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16
ports:
- containerPort: 5432
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "standard"
resources:
requests:
storage: 20Gi
Cache Distribuído (Redis)
Para clusters Redis, você precisa de ambos StatefulSet e configuração cuidadosa:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
spec:
serviceName: redis-service
replicas: 6
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
command:
- redis-server
- "--appendonly"
- "yes"
- "--appendfsync"
- "everysec"
ports:
- containerPort: 6379
name: redis
volumeMounts:
- name: data
mountPath: /data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 5Gi
Fila de Mensagens (Kafka)
Kafka requer armazenamento persistente para logs e identidades de rede estáveis para coordenação de brokers:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: kafka
spec:
serviceName: kafka-service
replicas: 3
selector:
matchLabels:
app: kafka
template:
metadata:
labels:
app: kafka
spec:
containers:
- name: kafka
image: confluentinc/cp-kafka:7.5.0
ports:
- containerPort: 9092
name: kafka
env:
- name: KAFKA_BROKER_ID
valueFrom:
fieldRef:
fieldPath: metadata.name
volumeMounts:
- name: data
mountPath: /var/lib/kafka/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 100Gi
Monitoramento e Solução de Problemas
Para uma referência abrangente dos comandos do Kubernetes usados nesta seção, veja o Kubernetes Cheatsheet.
Verificar o Status do StatefulSet
# Verificar detalhes do StatefulSet
kubectl get statefulset mysql
kubectl describe statefulset mysql
# Verificar a ordem de criação e o status dos pods
kubectl get pods -l app=mysql -w
# Verificar o status do PVC
kubectl get pvc
kubectl describe pvc data-mysql-0
Problemas Comuns
Pod preso em Pendente: Verifique o status do PVC e a disponibilidade de armazenamento
kubectl describe pod mysql-0
kubectl get events --sort-by='.lastTimestamp'
Armazenamento cheio: Expanda o PVC se a StorageClass permitir
kubectl patch pvc data-mysql-0 -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'
Pod não termina: Verifique bloqueios no nível da aplicação ou problemas de desmontagem de volume
kubectl delete pod mysql-0 --grace-period=0 --force
Métricas para Monitorar
- Uso de Armazenamento: Monitore a capacidade e a porcentagem de uso do PVC
- Desempenho de I/O: Rastreie IOPS, throughput e latência
- Reinícios de Pod: Reinícios frequentes podem indicar problemas de armazenamento
- Tempo de Vinculação do PVC: Vinculação lenta sugere problemas de provisionamento
Estratégias de Migração
Ao migrar para StatefulSets, certifique-se de que seu cluster Kubernetes esteja configurado corretamente. Para configurações de laboratório doméstico ou clusters pequenos, revise nossa comparação abrangente das distribuições do Kubernetes para escolher a plataforma certa para suas necessidades de carga de trabalho.
De Deployment para StatefulSet
- Crie o StatefulSet com volumeClaimTemplates
- Reduza o Deployment de forma suave
- Restaure os dados dos backups para os pods do StatefulSet
- Atualize as referências de DNS/Serviço
- Exclua o antigo Deployment e PVCs
Backup antes da migração
# Faça snapshot dos PVCs existentes
kubectl get pvc -o yaml > pvc-backup.yaml
# Crie snapshots de volume
kubectl apply -f volume-snapshot.yaml
Considerações de Segurança
Criptografia de Armazenamento
Ative criptografia em repouso usando parâmetros da StorageClass:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: encrypted-storage
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp3
encrypted: "true"
kmsKeyId: arn:aws:kms:us-east-1:123456789012:key/abcd-1234
Controle de Acesso
Use RBAC para restringir quem pode criar/modificar StatefulSets e PVCs:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: statefulset-manager
rules:
- apiGroups: ["apps"]
resources: ["statefulsets"]
verbs: ["get", "list", "create", "update", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "create", "delete"]
Políticas de Rede
Restrinja a comunicação entre pods:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: mysql-network-policy
spec:
podSelector:
matchLabels:
app: mysql
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: backend
ports:
- protocol: TCP
port: 3306
Otimização de Desempenho
Camadas de Desempenho de Armazenamento
Escolha as classes de StorageClass apropriadas com base na carga de trabalho:
- Alta IOPS: Bancos de dados com leitura/escrita aleatória intensa (gp3, io2)
- Alta Throughput: Agregação de logs, análise (st1, sc1)
- Equilibrada: Aplicações gerais (gp3)
Distribuição de Pods
Use anti-affinity de pod para distribuir pods de StatefulSet entre zonas de disponibilidade:
spec:
template:
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: mysql
topologyKey: topology.kubernetes.io/zone
Solicitações e Limites de Recursos
Defina recursos apropriados para desempenho consistente:
resources:
requests:
cpu: "2"
memory: "4Gi"
ephemeral-storage: "10Gi"
limits:
cpu: "4"
memory: "8Gi"
ephemeral-storage: "20Gi"
Padrões Avançados
Aplicação Stateful com Containers Iniciais
Use containers iniciais para inicialização de banco de dados:
spec:
template:
spec:
initContainers:
- name: init-mysql
image: mysql:8.0
command:
- bash
- "-c"
- |
if [[ ! -d /var/lib/mysql/mysql ]]; then
mysqld --initialize-insecure --datadir=/var/lib/mysql
fi
volumeMounts:
- name: data
mountPath: /var/lib/mysql
Pods com Múltiplos Containers para Sidecars
Adicione sidecars de backup ou agentes de monitoramento:
spec:
template:
spec:
containers:
- name: mysql
image: mysql:8.0
# ... configuração do mysql ...
- name: backup-sidecar
image: mysql-backup:latest
volumeMounts:
- name: data
mountPath: /var/lib/mysql
readOnly: true
ConfigMaps para Configuração Dinâmica
Separe a configuração da definição do StatefulSet:
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-config
data:
my.cnf: |
[mysqld]
max_connections=200
innodb_buffer_pool_size=2G
---
spec:
template:
spec:
containers:
- name: mysql
volumeMounts:
- name: config
mountPath: /etc/mysql/conf.d
volumes:
- name: config
configMap:
name: mysql-config
Links Úteis
- Documentação do Kubernetes StatefulSets
- Volumes Permanentes
- Classes de Armazenamento
- Snapshots de Volume
- Práticas Recomendadas para StatefulSets
- Drivers CSI
- Soluções de Backup do Velero
- Armazenamento Rook Ceph
- Kubernetes Cheatsheet
- Instale Kubernetes com Kubespray
- Comparação de Distribuições do Kubernetes para um Laboratório Doméstico de 3 Nós
- Distribuições do Kubernetes - visão geral de kubeadm, k3s, MicroK8s, Minikube, Talos Linux e RKE2
- Mestre Helm Charts: Guia de Gerenciamento de Pacotes do Kubernetes