Come Eseguire Aggiornamenti Rolling a Zero Downtime nelle Distribuzioni Kubernetes
Introduzione
Nelle moderne architetture a microservizi, mantenere la disponibilità continua durante gli aggiornamenti delle applicazioni è un requisito non negoziabile. Le Distribuzioni Kubernetes semplificano questo processo offrendo aggiornamenti rolling automatizzati (Rolling Updates), una strategia progettata per sostituire gradualmente le vecchie versioni dei Pod con quelle nuove.
Ottenere un vero zero downtime, tuttavia, richiede più della semplice configurazione predefinita di Kubernetes. Richiede un'attenta coordinazione tra il manifest della distribuzione, gli endpoint di salute dell'applicazione e il processo di terminazione graziosa. Questa guida fornisce un approccio completo, passo dopo passo, per configurare le Distribuzioni Kubernetes al fine di garantire che gli aggiornamenti delle applicazioni siano fluidi e invisibili all'utente finale.
Copriremo il ruolo critico delle sonde di prontezza (readiness probes), come ottimizzare i parametri della strategia di distribuzione (maxSurge e maxUnavailable) e le migliori pratiche per la terminazione dell'applicazione al fine di eliminare le interruzioni del servizio durante le transizioni di distribuzione.
Prerequisiti per lo Zero Downtime
Prima di configurare il manifest di Kubernetes, l'applicazione sottostante deve aderire a determinati principi per supportare distribuzioni a zero downtime:
- Compatibilità Retroattiva dell'Applicazione: Per il breve periodo in cui entrambe le vecchie e le nuove versioni dell'applicazione sono in esecuzione contemporaneamente, devono essere compatibili con le risorse condivise (database, code, cache).
- Idempotenza: Le operazioni che potrebbero essere gestite da entrambe le versioni devono essere ripetibili senza effetti collaterali negativi.
- Terminazione Graziosa: L'applicazione deve essere programmata per riconoscere il segnale
SIGTERMinviato da Kubernetes e interrompere graziosamente l'accettazione di nuove connessioni mentre termina le richieste in corso prima di uscire.
Comprensione della Strategia di Rolling Update di Kubernetes
Le Distribuzioni Kubernetes utilizzano per impostazione predefinita la strategia RollingUpdate. Questo metodo garantisce che la vecchia versione dell'applicazione non venga completamente arrestata prima che la nuova versione sia operativa, gestendo la transizione utilizzando due parametri principali:
| Parametro | Descrizione | Impatto sullo Zero Downtime |
|---|---|---|
maxSurge |
Definisce il numero massimo di Pod che possono essere creati oltre il numero desiderato di repliche. Può essere un numero assoluto o una percentuale (predefinito: 25%). | Controlla la velocità del rollout e garantisce che la capacità aumenti temporaneamente. |
maxUnavailable |
Definisce il numero massimo di Pod che possono essere non disponibili durante l'aggiornamento. Può essere un numero assoluto o una percentuale (predefinito: 25%). | Cruciale per lo zero downtime. Impostarlo a 0% significa che nessun Pod in servizio viene terminato finché i nuovi Pod non sono completamente Ready. |
Strategia Consigliata per lo Zero Downtime
Per la massima disponibilità, la configurazione migliore è spesso quella di garantire zero downtime di perdita di capacità:
maxUnavailable: 0(Garantisce che la capacità non scenda mai al di sotto del desiderato).maxSurge: 1o25%(Permette alla capacità di superare brevemente il target, garantendo che un nuovo Pod sia pronto prima che uno vecchio venga terminato).
Passaggio 1: Implementazione delle Readiness Probes
La Readiness Probe è il meccanismo più importante per garantire aggiornamenti a zero downtime. Kubernetes si affida a questa sonda per determinare se un nuovo Pod è pronto a ricevere traffico utente e se un vecchio Pod sta ancora servendo attivamente traffico.
Liveness vs. Readiness
- Liveness Probe: Indica a Kubernetes se il container è sano e funzionante. Se fallisce, il container viene riavviato.
- Readiness Probe: Indica a Kubernetes se il container è pronto a servire richieste. Se fallisce, il Pod viene rimosso dagli endpoint del Service associato, deviando il traffico lontano da esso finché non diventa pronto.
Per gli aggiornamenti rolling, la Readiness Probe viene utilizzata per controllare la transizione. Kubernetes non procederà a terminare un vecchio Pod finché un Pod appena creato non supererà con successo il suo controllo di prontezza.
# Estratto di deployment.yaml
spec:
containers:
- name: my-app
image: myregistry/my-app:v2.0
ports:
- containerPort: 8080
# --- Configurazione Readiness Probe ---
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 15 # Tempo di attesa prima del primo tentativo di sonda
periodSeconds: 5 # Frequenza con cui eseguire il controllo
timeoutSeconds: 3
failureThreshold: 3 # Numero di fallimenti consecutivi per contrassegnare il Pod come non pronto
# --- Configurazione Liveness Probe (Controllo di Salute Standard) ---
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
Suggerimento: Assicurati che l'endpoint
/health/readydella tua applicazione restituisca un codice di successo (HTTP 200-299) solo quando l'inizializzazione, le connessioni al database e altre dipendenze esterne sono completamente operative.
Passaggio 2: Configurazione della Strategia di Distribuzione
Per imporre un vero zero downtime, configuriamo esplicitamente la strategia di rolling update per impedire qualsiasi calo nel numero di repliche disponibili.
In questa configurazione, Kubernetes creerà prima un nuovo Pod (maxSurge: 1). Solo dopo che il nuovo Pod avrà superato la sua readiness probe, Kubernetes terminerà un vecchio Pod. Poiché maxUnavailable è 0, la capacità di servizio non scende mai al di sotto del conteggio target delle repliche.
# Estratto di deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-web-deployment
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
# Garantisce che la capacità non scenda mai al di sotto del numero di repliche desiderato (4)
maxUnavailable: 0
# Consente la creazione di un Pod aggiuntivo durante il rollout
maxSurge: 1
template:
# ... specifica del container ...
Passaggio 3: Garanzia della Terminazione Graziosa
Anche con readiness probes robuste, se l'applicazione si arresta istantaneamente alla ricezione del segnale di terminazione, rischia di interrompere le richieste in corso.
Kubernetes segue una sequenza di terminazione specifica:
- Il Pod viene contrassegnato come Terminating.
- Il Pod viene rimosso dagli endpoint del Service (il traffico smette di essere instradato verso di esso).
- Viene eseguito l'hook pre-stop (se definito).
- Il container riceve il segnale
SIGTERM. - Kubernetes attende la durata definita da
terminationGracePeriodSeconds(predefinito: 30 secondi). - Se il container è ancora in esecuzione, riceve un
SIGKILLnon negoziabile.
Per garantire uno spegnimento grazioso, l'applicazione deve gestire SIGTERM e terminationGracePeriodSeconds deve essere sufficientemente lungo affinché l'applicazione possa completare le richieste esistenti.
# Estratto di deployment.yaml, all'interno della specifica del container
terminationGracePeriodSeconds: 45 # Tempo aumentato per lo spegnimento grazioso
containers:
- name: my-app
image: myregistry/my-app:v2.0
lifecycle:
preStop:
exec:
# Esempio: Esecuzione di uno script per scaricare immediatamente le connessioni
command: ["/bin/sh", "-c", "sleep 10"]
Migliore Pratica: Il tempo tra il fallimento della Readiness Probe del Pod (Passaggio 2) e la ricezione di
SIGTERM(Passaggio 4) è critico. Se la tua applicazione gestisce correttamenteSIGTERM, impostare unterminationGracePeriodSecondsleggermente più lungo (es. 45 o 60 secondi) impedisce arresti forzati.
Passaggio 4: Esecuzione e Monitoraggio dell'Aggiornamento
Una volta che il tuo manifest di distribuzione include la strategia ottimizzata e le probes robuste, l'esecuzione dell'aggiornamento è semplice.
-
Aggiorna il Tag dell'Immagine: Modifica il tuo manifest di distribuzione per riflettere la nuova versione dell'immagine (es. da
v2.0av2.1). -
Applica la Configurazione:
bash kubectl apply -f deployment.yamlIn alternativa, puoi applicare una patch direttamente all'immagine:
bash kubectl set image deployment/my-web-deployment my-app=myregistry/my-app:v2.1 -
Monitora lo Stato del Rollout: Osserva Kubernetes progredire attraverso le fasi, verificando che il numero di Pod pronti non scenda mai al di sotto del conteggio desiderato.
bash kubectl rollout status deployment/my-web-deployment -
Verifica la Disponibilità dei Pod: Osserva lo stato dei Pod per confermare che i vecchi Pod (v2.0) vengano terminati graziosamente solo dopo che i nuovi Pod (v2.1) sono completamente pronti.
bash kubectl get pods -l app=my-web-deployment -w
Considerazioni Avanzate
Utilizzo dei Pod Disruption Budgets (PDB)
Mentre una strategia di distribuzione gestisce gli aggiornamenti volontari, un Pod Disruption Budget (PDB) garantisce che un numero minimo di Pod sia disponibile anche durante interruzioni non pianificate (es. manutenzione dei nodi, aggiornamenti del cluster). Sebbene i PDB non controllino direttamente la velocità di aggiornamento rolling, fungono da rete di sicurezza.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-app-pdb
spec:
minAvailable: 75% # Garantisce che almeno il 75% delle repliche sia sempre disponibile
selector:
matchLabels:
app: my-web-deployment
L'Importanza del Ritardo Iniziale
Se la tua applicazione impiega tempo per avviarsi (es. caricamento di file di configurazione di grandi dimensioni o creazione di cache), assicurati che initialDelaySeconds nella tua Readiness Probe sia sufficientemente lungo. Se la sonda controlla troppo presto e fallisce, il Pod verrà contrassegnato come non integro e potenzialmente bloccato in un loop di crash, interrompendo l'intera distribuzione.
Conclusione
Ottenere aggiornamenti rolling a vero zero downtime in Kubernetes è una combinazione di configurazione robusta della piattaforma e sviluppo disciplinato dell'applicazione. Sfruttando correttamente le Readiness Probes per segnalare lo stato operativo, ottimizzando la strategia di Distribuzione (maxUnavailable: 0) per mantenere la capacità e implementando gestori di terminazione graziosa, puoi garantire che gli aggiornamenti delle applicazioni vengano eseguiti in modo affidabile senza interrompere il servizio ai tuoi utenti. Testa sempre attentamente il tuo processo di aggiornamento in un ambiente di staging per convalidare il periodo di grazia della terminazione e la logica delle sonde.