StatefulSets & Archiviazione persistente in Kubernetes
Distribuisci applicazioni stateful con scalabilità ordinata e dati persistenti
Kubernetes StatefulSets sono la soluzione ideale per gestire applicazioni stateful che richiedono identità stabili, archiviazione persistente e modelli di distribuzione ordinati—essenziali per database, sistemi distribuiti e strati di caching.
Se sei nuovo a Kubernetes o stai configurando un cluster, considera di esplorare distribuzioni Kubernetes come k3s o MicroK8s per lo sviluppo, o installare Kubernetes con Kubespray per cluster a livello di produzione.
Questa bella immagine è generata da modello AI Flux 1 dev.
Cosa sono i StatefulSets?
I StatefulSets sono un oggetto API di lavoro Kubernetes progettato specificamente per gestire applicazioni stateful. A differenza delle Deployments che trattano tutti i pod come intercambiabili, i StatefulSets mantengono un’identità unica per ogni pod con garanzie riguardo all’ordinamento e all’unicità.
Funzionalità principali:
- Identificatori di rete stabili: Ogni pod riceve un nome host prevedibile che persiste anche dopo i riavvii
- Archiviazione persistente: Richieste di PersistentVolumeClaims dedicate che seguono i pod anche durante i riassegnamenti
- Distribuzione ordinata: I pod vengono creati in modo sequenziale (0, 1, 2…) e terminano nell’ordine inverso
- Aggiornamenti ordinati: Gli aggiornamenti rolling procedono nell’ordine, garantendo la stabilità dell’applicazione
I StatefulSets sono fondamentali per applicazioni come PostgreSQL, MySQL, MongoDB, Cassandra, Elasticsearch, Kafka, ZooKeeper, Redis e etcd—qualsiasi carico di lavoro in cui l’identità del pod e la persistenza dei dati siano importanti.
Comprendere l’archiviazione persistente in Kubernetes
Kubernetes fornisce uno strato di astrazione avanzato per l’archiviazione che separa la gestione dell’archiviazione dal ciclo di vita dei pod:
Componenti di archiviazione
PersistentVolume (PV): Un frammento di archiviazione nel cluster provvisto da un amministratore o creato dinamicamente tramite una StorageClass. I PV esistono indipendentemente dai pod.
PersistentVolumeClaim (PVC): Una richiesta di archiviazione da parte di un pod. I PVC si legano a PV disponibili che corrispondono ai loro requisiti (dimensione, modalità di accesso, classe di archiviazione).
StorageClass: Definisce diverse “classi” di archiviazione con vari provveditori (AWS EBS, GCE PD, Azure Disk, NFS, ecc.) e parametri come replicazione, livelli di prestazioni e politiche di backup.
Modalità di accesso
- ReadWriteOnce (RWO): Volume montato in lettura/scrittura da un singolo nodo
- ReadOnlyMany (ROX): Volume montato in sola lettura da molti nodi
- ReadWriteMany (RWX): Volume montato in lettura/scrittura da molti nodi (richiede backend di archiviazione speciali)
Architettura di archiviazione dei StatefulSets
I StatefulSets utilizzano volumeClaimTemplates per creare automaticamente PersistentVolumeClaims per ogni replica del pod. Questo è fondamentalmente diverso dalle Deployments:
Come funzionano le volumeClaimTemplates
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 crei questo StatefulSet:
- Kubernetes crea il pod
mysql-0e il PVCdata-mysql-0 - Poi crea il pod
mysql-1e il PVCdata-mysql-1 - Infine crea il pod
mysql-2e il PVCdata-mysql-2
Ogni pod riceve il proprio 10 GB di volume persistente dedicato. Se mysql-1 viene eliminato o riassegnato, Kubernetes lo ricrea e riconnette lo stesso PVC data-mysql-1, preservando tutti i dati.
Creare un servizio headless per i StatefulSets
I StatefulSets richiedono un servizio headless per fornire identità di rete stabili:
apiVersion: v1
kind: Service
metadata:
name: mysql-service
spec:
clusterIP: None # Questo lo rende un servizio headless
selector:
app: mysql
ports:
- port: 3306
name: mysql
Questo crea voci DNS per ogni pod:
mysql-0.mysql-service.default.svc.cluster.localmysql-1.mysql-service.default.svc.cluster.localmysql-2.mysql-service.default.svc.cluster.local
Le applicazioni possono connettersi direttamente a istanze specifiche del pod utilizzando questi nomi DNS stabili.
Pattern di distribuzione dei StatefulSets
Per i team che gestiscono distribuzioni complesse di Kubernetes, Helm Charts forniscono un modo potente per imballare e distribuire i StatefulSets con modelli, versionamento e gestione delle dipendenze. Helm semplifica la gestione delle configurazioni dei StatefulSet in diversi ambienti.
Scalabilità ordinata
Quando si scalano da 3 a 5 repliche:
kubectl scale statefulset mysql --replicas=5
Kubernetes crea i pod nell’ordine: mysql-3 → attende che sia pronto → mysql-4
Quando si scalano da 5 a 3 repliche:
kubectl scale statefulset mysql --replicas=3
Kubernetes termina nell’ordine inverso: mysql-4 → attende la terminazione → mysql-3
Aggiornamenti rolling
I StatefulSets supportano due strategie di aggiornamento:
OnDelete: Aggiornamenti manuali—i pod vengono aggiornati solo quando li elimini RollingUpdate: Aggiornamenti automatici sequenziali nell’ordine inverso
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 2 # Aggiorna solo i pod con ordinal >= 2
Il parametro partition abilita le distribuzioni canary—puoi aggiornare prima i pod con numeri più alti e testare prima di distribuire a tutte le repliche.
Best Practices per l’archiviazione
Provisioning dinamico
Utilizza sempre le StorageClasses per il provisioning dinamico dei volumi:
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: Abilita il ridimensionamento dei PVC senza ricrearli
reclaimPolicy: Retain mantiene i dati del PV dopo l’eliminazione del PVC, Delete li elimina automaticamente
Politiche di conservazione dei PVC
Kubernetes 1.23+ supporta persistentVolumeClaimRetentionPolicy:
spec:
persistentVolumeClaimRetentionPolicy:
whenDeleted: Retain # Conserva i PVC quando viene eliminato il StatefulSet
whenScaled: Delete # Elimina i PVC quando si riduce la scala
Opzioni:
- Retain: Conserva i PVC (comportamento predefinito, più sicuro)
- Delete: Elimina automaticamente i PVC (utile per ambienti di sviluppo)
Strategie di backup
Snapshots del volume: Utilizza le risorse VolumeSnapshot per creare backup puntuali nel tempo
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: mysql-snapshot-20251113
spec:
volumeSnapshotClassName: csi-snapclass
source:
persistentVolumeClaimName: data-mysql-0
Backup a livello di applicazione: Utilizza strumenti come mysqldump, pg_dump o Velero per i backup specifici del database
Replicazione distribuita: Configura la replicazione a livello di applicazione (replicazione MySQL, replicazione streaming PostgreSQL) come prima linea di difesa
Caso d’uso reale
Cluster del database (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 distribuita (Redis)
Per i cluster Redis, è necessario utilizzare sia un StatefulSet che una configurazione attenta:
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
Coda di messaggi (Kafka)
Kafka richiede sia l’archiviazione persistente per i log che identità di rete stabili per la coordinazione dei broker:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: kafka
spec:
serviceName: kafka-service
replicas: 3
selector:
match标签:
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
Monitoraggio e risoluzione dei problemi
Per un riferimento completo dei comandi Kubernetes utilizzati in questa sezione, vedi il Kubernetes Cheatsheet.
Verifica lo stato dei StatefulSets
# Visualizza i dettagli del StatefulSet
kubectl get statefulset mysql
kubectl describe statefulset mysql
# Controlla l'ordine di creazione e lo stato dei pod
kubectl get pods -l app=mysql -w
# Visualizza lo stato dei PVC
kubectl get pvc
kubectl describe pvc data-mysql-0
Problemi comuni
Pod bloccato in stato Pending: Controlla lo stato del PVC e la disponibilità dell’archiviazione
kubectl describe pod mysql-0
kubectl get events --sort-by='.lastTimestamp'
Archiviazione piena: Espandi il PVC se la StorageClass lo consente
kubectl patch pvc data-mysql-0 -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'
Pod che non termina: Controlla i blocchi a livello di applicazione o i problemi di smontaggio del volume
kubectl delete pod mysql-0 --grace-period=0 --force
Metriche da monitorare
- Utilizzo dell’archiviazione: Monitora la capacità e la percentuale di utilizzo del PVC
- Prestazioni I/O: Traccia IOPS, throughput e latenza
- Riavvii del pod: I riavvii frequenti possono indicare problemi di archiviazione
- Tempo di binding del PVC: Un binding lento suggerisce problemi di provisioning
Strategie di migrazione
Quando si migra ai StatefulSets, assicurati che il cluster Kubernetes sia correttamente configurato. Per le configurazioni di laboratorio domestico o piccoli cluster, consulta la nostra comparazione completa delle distribuzioni Kubernetes per scegliere la piattaforma giusta per i requisiti del tuo carico di lavoro.
Dalla Deployment ai StatefulSets
- Crea un StatefulSet con volumeClaimTemplates
- Scala giù la Deployment in modo graduale
- Ripristina i dati dai backup ai pod del StatefulSet
- Aggiorna le referenze DNS/Servizio
- Elimina l’antica Deployment e i PVC
Backup prima della migrazione
# Snapshot dei PVC esistenti
kubectl get pvc -o yaml > pvc-backup.yaml
# Crea snapshot del volume
kubectl apply -f volume-snapshot.yaml
Considerazioni sulla sicurezza
Crittografia dell’archiviazione
Abilita la crittografia a riposo utilizzando i parametri della 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
Controllo degli accessi
Utilizza RBAC per limitare chi può creare/modificare i StatefulSets e i PVC:
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"]
Politiche di rete
Limita la comunicazione tra i 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
Ottimizzazione delle prestazioni
Livelli di prestazioni dell’archiviazione
Scegli le StorageClasses appropriate in base al carico di lavoro:
- Alta IOPS: Database con letture/scritture casuali pesanti (gp3, io2)
- Alta throughput: Aggregazione dei log, analisi (st1, sc1)
- Equilibrata: Applicazioni generali (gp3)
Distribuzione dei pod
Utilizza l’anti-affinità dei pod per distribuire i pod dei StatefulSet tra zone di disponibilità:
spec:
template:
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: mysql
topologyKey: topology.kubernetes.io/zone
Richieste e limiti delle risorse
Imposta le risorse appropriate per prestazioni costanti:
resources:
requests:
cpu: "2"
memory: "4Gi"
ephemeral-storage: "10Gi"
limits:
cpu: "4"
memory: "8Gi"
ephemeral-storage: "20Gi"
Pattern avanzati
Applicazione stateful con init containers
Utilizza init containers per l’inizializzazione del database:
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
Pod multi-container per sidecar
Aggiungi sidecar per backup o agenti di monitoraggio:
spec:
template:
spec:
containers:
- name: mysql
image: mysql:8.0
# ... configurazione mysql ...
- name: backup-sidecar
image: mysql-backup:latest
volumeMounts:
- name: data
mountPath: /var/lib/mysql
readOnly: true
ConfigMaps per la configurazione dinamica
Separa la configurazione dalla definizione del 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
Link utili
- Documentazione Kubernetes StatefulSets
- Persistent Volumes
- Storage Classes
- Volume Snapshots
- Best Practices per i StatefulSets
- Driver CSI
- Soluzioni di backup Velero
- Rook Ceph Storage
- Kubernetes Cheatsheet
- Installare Kubernetes con Kubespray
- Confronto delle distribuzioni Kubernetes per un laboratorio domestico a 3 nodi
- Distribuzioni Kubernetes - panoramica rapida di kubeadm, k3s, MicroK8s, Minikube, Talos Linux e RKE2
- Master Helm Charts: Guida alla gestione dei pacchetti Kubernetes