Come eseguire Rolling Updates a zero downtime nei Deployment di Kubernetes

Padroneggia l'arte di eseguire rolling updates a zero downtime nei Deployment di Kubernetes. Questa guida esperta illustra le configurazioni essenziali necessarie per mantenere la disponibilità continua dell'applicazione durante le transizioni. Impara come implementare robusti Readiness Probes, come ottimizzare le strategie di deployment `maxSurge` e `maxUnavailable` per la massima operatività (uptime) e come garantire la terminazione elegante dell'applicazione. Segui questi passaggi pratici per eliminare le interruzioni del servizio e fornire aggiornamenti fluidi agli utenti finali.

32 visualizzazioni

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:

  1. 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).
  2. Idempotenza: Le operazioni che potrebbero essere gestite da entrambe le versioni devono essere ripetibili senza effetti collaterali negativi.
  3. Terminazione Graziosa: L'applicazione deve essere programmata per riconoscere il segnale SIGTERM inviato 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: 1 o 25% (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/ready della 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:

  1. Il Pod viene contrassegnato come Terminating.
  2. Il Pod viene rimosso dagli endpoint del Service (il traffico smette di essere instradato verso di esso).
  3. Viene eseguito l'hook pre-stop (se definito).
  4. Il container riceve il segnale SIGTERM.
  5. Kubernetes attende la durata definita da terminationGracePeriodSeconds (predefinito: 30 secondi).
  6. Se il container è ancora in esecuzione, riceve un SIGKILL non 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 correttamente SIGTERM, impostare un terminationGracePeriodSeconds leggermente 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.

  1. Aggiorna il Tag dell'Immagine: Modifica il tuo manifest di distribuzione per riflettere la nuova versione dell'immagine (es. da v2.0 a v2.1).

  2. Applica la Configurazione:

    bash kubectl apply -f deployment.yaml

    In alternativa, puoi applicare una patch direttamente all'immagine:

    bash kubectl set image deployment/my-web-deployment my-app=myregistry/my-app:v2.1

  3. 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

  4. 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.