StatefulSets e Armazenamento Persistente no Kubernetes
Implante aplicativos com estado com dimensionamento ordenado e dados persistentes.
Os StatefulSets do Kubernetes são a solução ideal para gerenciar aplicações com estado 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 nível de produção.
Esta bela imagem foi gerada pelo modelo de IA Flux 1 dev.
O que são StatefulSets?
Os StatefulSets são objetos de API de carga de trabalho do Kubernetes projetados especificamente para gerenciar aplicações com estado. Diferente das Deployments, que tratam todos os pods como intercambiáveis, os StatefulSets mantêm uma identidade única para cada pod com garantias sobre ordenação e unicidade.
Principais Características:
- Identificadores de Rede Estáveis: Cada pod recebe um hostname previsível que persiste através de reinicializações
- Armazenamento Persistente: PersistentVolumeClaims (PVCs) dedicados que seguem os pods através de reprogramações
- Implantação Ordenada: Os pods são criados sequencialmente (0, 1, 2…) e encerrados em ordem inversa
- Atualizações Ordenadas: As atualizações rolantes ocorrem em ordem, garantindo a estabilidade da aplicação
Os StatefulSets são críticos 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 de dados importam.
Compreendendo o Armazenamento Persistente no Kubernetes
O Kubernetes fornece uma camada de abstração de armazenamento sofisticada que desacopla o gerenciamento de armazenamento do ciclo de vida dos pods:
Componentes de Armazenamento
PersistentVolume (PV): Uma unidade de armazenamento no cluster provisionada por um administrador ou criada dinamicamente via uma StorageClass. Os PVs existem independentemente dos pods.
PersistentVolumeClaim (PVC): Uma solicitação de armazenamento por um pod. Os PVCs vinculam-se a PVs disponíveis que correspondem aos seus requisitos (tamanho, modo de acesso, classe de armazenamento).
StorageClass: Define diferentes “classes” de armazenamento com vários provisionadores (AWS EBS, GCE PD, Azure Disk, NFS, etc.) e parâmetros como replicação, níveis 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 de StatefulSets
Os StatefulSets usam volumeClaimTemplates para criar automaticamente PersistentVolumeClaims para cada réplica do pod. Isso é fundamentalmente diferente das Deployments:
Como os 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 dedicado de 10GB. Se mysql-1 for excluído ou reprogramado, o Kubernetes o recria e reanexa o mesmo PVC data-mysql-1, preservando todos os dados.
Criando um Service Headless para StatefulSets
Os StatefulSets requerem um Service Headless para fornecer identidades de rede estáveis:
apiVersion: v1
kind: Service
metadata:
name: mysql-service
spec:
clusterIP: None # Isso o torna 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
As aplicações podem se conectar diretamente a instâncias específicas de pods usando esses nomes DNS estáveis.
Padrões de Implantação de StatefulSets
Para equipes que gerenciam implantações complexas do Kubernetes, os Helm Charts fornecem 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 StatefulSets em diferentes ambientes.
Escalonamento Ordenado
Ao escalar de 3 para 5 réplicas:
kubectl scale statefulset mysql --replicas=5
O Kubernetes cria pods em ordem: mysql-3 → aguarda Ready → mysql-4
Ao reduzir de 5 para 3 réplicas:
kubectl scale statefulset mysql --replicas=3
O Kubernetes encerra em ordem inversa: mysql-4 → aguarda término → mysql-3
Atualizações Rolantes (Rolling Updates)
Os StatefulSets suportam duas estratégias de atualização:
OnDelete: Atualizações manuais — os pods atualizam apenas quando você os exclui RollingUpdate: Atualizações automáticas sequenciais em ordem ordinal inversa
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 2 # Atualiza apenas pods com ordinal >= 2
O parâmetro partition habilita implantações canary — você pode atualizar pods de números altos primeiro e testar antes de estender para todas as réplicas.
Melhores 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 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 # Mantém PVCs quando o StatefulSet é excluído
whenScaled: Delete # Exclui PVCs ao reduzir escala
Opções:
- Retain: Mantém PVCs (comportamento padrão, mais seguro)
- Delete: Exclui automaticamente PVCs (útil para ambientes de desenvolvimento)
Estratégias de Backup
Instantâneos de Volume (Volume Snapshots): Use recursos VolumeSnapshot para criar backups pontuais
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: mysql-snapshot-20251113
spec:
volumeSnapshotClassName: csi-snapclass
source:
persistentVolumeClaimName: data-mysql-0
Backups ao Nível de 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 ao nível da aplicação (replicação MySQL, replicação de streaming PostgreSQL) como primeira linha de defesa
Casos de Uso no Mundo Real
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 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)
O 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 Kubernetes usados nesta seção, consulte a Lista de Comandos Kubernetes (CheatSheet).
Verificar Status do StatefulSet
# Ver detalhes do StatefulSet
kubectl get statefulset mysql
kubectl describe statefulset mysql
# Verificar ordem de criação e status dos pods
kubectl get pods -l app=mysql -w
# Verificar 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 Encerra: Verifique bloqueios ao 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 porcentagem de uso do PVC
- Desempenho de I/O: Rastreie IOPS, throughput e latência
- Reinicializações de Pod: Reinicializações frequentes podem indicar problemas de armazenamento
- Tempo de Vinculação de 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 homelab ou clusters pequenos, revise nossa comparação abrangente de distribuições Kubernetes para escolher a plataforma certa para seus requisitos de carga de trabalho.
De Deployment para StatefulSet
- Crie StatefulSet com volumeClaimTemplates
- Reduza a escala da Deployment de forma graciosa
- Restaure dados de backups para os pods do StatefulSet
- Atualize referências DNS/Service
- Exclua a Deployment antiga e os PVCs
Backup Antes da Migração
# Criar instantâneo dos PVCs existentes
kubectl get pvc -o yaml > pvc-backup.yaml
# Criar instantâneos de volume
kubectl apply -f volume-snapshot.yaml
Considerações de Segurança
Criptografia de Armazenamento
Habilite criptografia em repouso usando parâmetros de 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 pod-a-pod:
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
Níveis de Desempenho de Armazenamento
Escolha StorageClasses apropriadas com base na carga de trabalho:
- Alto IOPS: Bancos de dados com leitura/escrita aleatória pesada (gp3, io2)
- Alto Throughput: Agregação de logs, análises (st1, sc1)
- Equilibrado: Aplicações de uso geral (gp3)
Distribuição de Pods
Use anti-affinity de pods para distribuir pods de StatefulSets através de 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 com Estado com Init Containers
Use init containers 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 Multi-Container para Sidecars
Adicione sidecars de backup ou agentes de monitoramento:
spec:
template:
spec:
containers:
- name: mysql
image: mysql:8.0
# ... mysql config ...
- 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 StatefulSets do Kubernetes
- Volumes Persistentes
- Classes de Armazenamento
- Instantâneos de Volume
- Melhores Práticas de StatefulSet
- Drivers CSI
- Soluções de Backup Velero
- Armazenamento Rook Ceph
- Lista de Comandos Kubernetes (CheatSheet)
- Instalar Kubernetes com Kubespray
- Comparação de Distribuições Kubernetes para um Homelab de 3 Nós
- Distribuições do Kubernetes - visão geral rápida de kubeadm, k3s, MicroK8s, Minikube, Talos Linux e RKE2
- Domine Helm Charts: Guia de Gerenciamento de Pacotes Kubernetes