K8s em Exemplos: StatefulSets

StatefulSets fornecem identidades estáveis de Pod e storage persistente. Diferente de Deployments, Pods não são intercambiáveis. Eles mantêm o mesmo nome, DNS e storage entre restarts. Use para: bancos de dados, caches, Kafka.

statefulset.yaml

StatefulSet requer serviceName apontando para um Service headless. Pods recebem nomes ordinais: postgres-0, postgres-1, postgres-2.

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:15
          ports:
            - containerPort: 5432
headless-service.yaml

Service Headless (clusterIP: None) fornece DNS estável para cada Pod. Entradas DNS: postgres-0.postgres.default.svc.cluster.local, postgres-1.postgres.default.svc.cluster.local. É assim que Pods descobrem uns aos outros para clustering.

apiVersion: v1
kind: Service
metadata:
  name: postgres
spec:
  clusterIP: None
  selector:
    app: postgres
  ports:
    - port: 5432
statefulset-storage.yaml

Cada Pod recebe um volume persistente via volumeClaimTemplates. PVCs são nomeados nomevolume-nomepod: data-postgres-0, data-postgres-1, data-postgres-2. Volumes sobrevivem restarts e reagendamento de Pod.

spec:
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: gp3
        resources:
          requests:
            storage: 10Gi
  template:
    spec:
      containers:
        - name: postgres
          volumeMounts:
            - name: data
              mountPath: /var/lib/postgresql/data
statefulset-policy.yaml

Políticas de gerenciamento de Pod controlam ordem de inicialização. OrderedReady (padrão) inicia Pods sequencialmente (postgres-0 → postgres-1 → postgres-2) e para em ordem reversa. Parallel inicia/para todos simultaneamente.

spec:
  podManagementPolicy: OrderedReady
  replicas: 3
statefulset-update.yaml

Estratégias de update: RollingUpdate (padrão) atualiza Pods em ordem reversa (N-1 → 0). OnDelete só atualiza quando Pod é deletado manualmente. partition: 1 significa postgres-0 fica na versão antiga enquanto postgres-1, postgres-2 recebem nova versão. Defina partition: 0 para completar rollout.

spec:
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      partition: 1
statefulset-retention.yaml

PVCs persistem após deleção do StatefulSet por padrão. whenDeleted: Delete deleta PVCs quando StatefulSet é deletado. whenScaled: Retain (padrão) mantém PVCs no scale down. Delete manualmente para recuperar storage.

spec:
  persistentVolumeClaimRetentionPolicy:
    whenDeleted: Delete
    whenScaled: Retain
terminal

Scale up cria postgres-3, postgres-4 em ordem. Scale down remove postgres-4, postgres-3 em ordem reversa e espera cada um terminar. PVCs NÃO são deletados no scale down: data-postgres-3 e data-postgres-4 ainda existem.

$ kubectl scale statefulset postgres --replicas=5
statefulset.apps/postgres scaled

$ kubectl scale statefulset postgres --replicas=3
statefulset.apps/postgres scaled

$ kubectl get pvc
NAME              STATUS   VOLUME       CAPACITY
data-postgres-0   Bound    pv-abc123    10Gi
data-postgres-1   Bound    pv-def456    10Gi
data-postgres-2   Bound    pv-ghi789    10Gi
data-postgres-3   Bound    pv-jkl012    10Gi
data-postgres-4   Bound    pv-mno345    10Gi
terminal

Debug StatefulSets verificando ordenação de Pod, binding de PVC e DNS do Service headless. Problemas comuns: PVC preso pendente (sem storage), Pod preso inicializando (Pod anterior não está ready).

$ kubectl get pods -l app=postgres -w
NAME         READY   STATUS    AGE
postgres-0   1/1     Running   5m
postgres-1   1/1     Running   4m
postgres-2   1/1     Running   3m

$ kubectl get pvc -l app=postgres
NAME              STATUS   VOLUME
data-postgres-0   Bound    pvc-abc123
data-postgres-1   Bound    pvc-def456
data-postgres-2   Bound    pvc-ghi789

$ kubectl run -it --rm debug --image=busybox -- \
    nslookup postgres-0.postgres.default.svc.cluster.local
Name:      postgres-0.postgres.default.svc.cluster.local
Address 1: 10.244.0.15

$ kubectl describe statefulset postgres

Índice | GitHub | Use as setas do teclado para navegar |