PerfectScalePerfectScale

PerfectScale

kubectl rollout: come gestire, annullare e riavviare i Deployment

Questa pagina è disponibile anche in English, Deutsch, Español, Français, 日本語 e Português.

Tania Duggal
By Tania Duggal
Sep 7, 202611 min read

kubectl rollout è il comando che usi per controllare e ispezionare il modo in cui Kubernetes distribuisce le modifiche a un workload. Quando modifichi un Deployment, Kubernetes sostituisce i vecchi pod con quelli nuovi, e kubectl rollout è lo strumento con cui osservi quel processo, lo metti in pausa, esegui un rollback, lo riavvii e ne consulti la cronologia.

In questa guida scoprirai come Kubernetes esegue davvero un rollout dietro le quinte, ogni sottocomando di kubectl rollout con esempi pratici, perché i rollout si bloccano e come diagnosticarli, oltre alle pratiche che rendono i rollout sicuri in produzione.

Che cos'è kubectl rollout?

kubectl rollout è un insieme di comandi per gestire il rollout di un workload dopo che lo hai modificato. Un rollout è il processo di sostituzione dei pod che eseguono la vecchia versione con pod che eseguono quella nuova. Il comando non modifica il workload in sé. Ti permette invece di osservare e controllare il rollout innescato da una modifica: verificare se è terminato, esaminare cosa è cambiato, annullarlo, metterlo in pausa e riprenderlo, oppure riavviare i pod.

Funziona con i workloads che gestiscono i rollout per te, ovvero Deployment, StatefulSet e DaemonSet. Gran parte di questa guida utilizza un Deployment, perché è il caso in cui i rollout sono più comuni.

Come esegue davvero un rollout Kubernetes?

Quando modifichi il pod template di un Deployment, Kubernetes non interviene sui pod in esecuzione. Crea un nuovo ReplicaSet per la nuova versione e sposta gradualmente i pod dal vecchio ReplicaSet a quello nuovo. Ogni ReplicaSet, e ogni pod che gli appartiene, porta con sé un'etichetta pod-template-hash, cioè un hash del pod template. È grazie a questa etichetta che Kubernetes distingue le versioni e mantiene ogni pod collegato al ReplicaSet corretto. Quando in seguito esegui un rollback, in realtà Kubernetes non fa altro che scalare di nuovo verso l'alto un vecchio ReplicaSet.

La parte importante è sapere quali modifiche avviano effettivamente un rollout. Solo le modifiche al pod template, il campo .spec.template, creano un nuovo ReplicaSet e una nuova revisione. Ciò significa che una nuova immagine, una variabile d'ambiente modificata o una resource request aggiornata attivano tutte un rollout. Una modifica al numero di repliche invece no, perché scalare verso l'alto o verso il basso ridimensiona soltanto il ReplicaSet corrente senza crearne uno nuovo. Ecco perché lo scaling di un Deployment non compare mai nella sua cronologia dei rollout.

La velocità del rollout è controllata da due campi della strategia di rolling update. Il maxSurge stabilisce quanti pod extra possono esistere oltre il numero desiderato durante il rollout, e il suo valore predefinito è il 25%, arrotondato per eccesso. Il maxUnavailable stabilisce quanti pod possono mancare rispetto al numero desiderato durante il rollout, e il suo valore predefinito è il 25%, arrotondato per difetto. Insieme, controllano la rapidità con cui Kubernetes sostituisce i vecchi pod con i nuovi. Impostare maxSurge: 1 e maxUnavailable: 0 è una scelta prudente e diffusa, perché aggiunge un nuovo pod prima di rimuoverne uno vecchio e non scende mai sotto la piena capacità.

Ci sono altre tre impostazioni che controllano l'avanzamento del rollout. Un nuovo pod conta come disponibile solo quando la sua readiness probe ha esito positivo, quindi senza una buona readiness probe Kubernetes considererà un pod pronto prima che possa servire traffico e andrà avanti troppo presto. Il minReadySeconds impone a un pod, una volta pronto, un tempo di attesa prima di essere conteggiato come disponibile, così da intercettare i pod che superano la probe ma vanno in crash pochi secondi dopo. E il progressDeadlineSeconds, il cui valore predefinito è 600 (10 minuti), indica quanto a lungo Kubernetes attende che il rollout faccia progressi prima di contrassegnare il Deployment come fallito con ProgressDeadlineExceeded.

media

I sottocomandi di kubectl rollout e le risorse che li supportano

kubectl rollout ha sei sottocomandi: status, history, undo, pause, resume e restart. Non tutti si applicano a ogni workload. status, history, undo e restart funzionano su Deployment, StatefulSet e DaemonSet. pause e resume funzionano solo sui Deployment, perché solo un Deployment ha un rollout che può essere messo in pausa. Le sezioni che seguono trattano ciascun sottocomando, usando un Deployment chiamato api.

kubectl rollout status

kubectl rollout status segue un rollout e ti dice quando è terminato:

kubectl rollout status deployment/api

Mentre è in esecuzione, stampa i progressi e termina quando il rollout è completato. Vedrai righe come Waiting for deployment "api" rollout to finish: 2 out of 4 new replicas have been updated... e infine deployment "api" successfully rolled out. Ogni riga riflette lo scale-up del nuovo ReplicaSet e i pod che diventano disponibili.

Per impostazione predefinita, il comando trasmette l'output in tempo reale e attende. Ci sono due flag che ne cambiano il comportamento: --timeout gli impedisce di attendere all'infinito, cosa importante in uno script, mentre --watch=false fa sì che stampi lo stato corrente una sola volta ed esca, invece di rimanere in ascolto:

kubectl rollout status deployment/api --timeout=5m
kubectl rollout status deployment/api --watch=false

La parte più utile di rollout status è il suo exit code. Restituisce 0 quando il rollout ha successo e un codice diverso da zero quando fallisce o va in timeout. Questo lo rende prezioso nelle pipeline CI/CD: la pipeline può attendere il completamento del rollout e fallire se il Deployment non diventa pronto, invece di considerare un kubectl apply riuscito come un deployment riuscito.

kubectl rollout history

kubectl rollout history elenca le revisioni passate di un workload, così puoi vedere cosa è cambiato e scegliere a quale tornare:

kubectl rollout history deployment/api

L'output è una tabella con i numeri di revisione e una colonna CHANGE-CAUSE. Per vedere il pod template completo di una revisione, passa --revision:

kubectl rollout history deployment/api --revision=2

La colonna CHANGE-CAUSE viene compilata solo se imposti l'annotazione kubernetes.io/change-cause. Il vecchio flag --record che la popolava è deprecato, quindi il modo attuale è impostare tu stesso l'annotazione dopo una modifica:

kubectl annotate deployment/api kubernetes.io/change-cause="update image to api:1.4.0"

Senza l'annotazione, la colonna mostra <none>, rendendo più difficile capire cosa è cambiato in ogni revisione.

Quanto indietro puoi tornare dipende da revisionHistoryLimit, il cui valore predefinito è 10. Kubernetes conserva quel numero di vecchi ReplicaSet e rimuove i più datati. Se il limite è troppo basso, la revisione a cui vorresti tornare potrebbe non esistere più.

kubectl rollout undo

kubectl rollout undo esegue il rollback di un workload. Senza argomenti, torna alla revisione precedente; con --to-revision torna a una revisione specifica della cronologia:

kubectl rollout undo deployment/api
kubectl rollout undo deployment/api --to-revision=2

Funziona perché Kubernetes conserva ancora il vecchio ReplicaSet e si limita a scalarlo di nuovo verso l'alto. Un rollback è a sua volta un rollout, quindi fallo seguire da rollout status per confermare che sia terminato.

Un limite importante è che undo ripristina solo il pod template. Questo include l'immagine del container, le variabili d'ambiente e le impostazioni delle risorse. Non annulla le modifiche fatte al di fuori del pod template. Ad esempio, se la release ha modificato anche una ConfigMap, un Secret, uno schema di database o un sistema esterno, il rollback del Deployment non annulla quelle modifiche.

Per questo motivo, considera rollout undo uno strumento di ripristino rapido, non la tua strategia di deployment abituale. Può ripristinare velocemente una versione precedente dei pod, ma non può annullare tutto ciò che potrebbe essere cambiato durante una release.

kubectl rollout restart

kubectl rollout restart riavvia tutti i pod di un workload senza cambiare l'immagine:

kubectl rollout restart deployment/api

Il comando aggiunge al pod template un'annotazione kubectl.kubernetes.io/restartedAt con il timestamp corrente; poiché questo modifica il pod template, Kubernetes lo tratta come un normale rollout. Crea un nuovo ReplicaSet e sostituisce gradualmente i vecchi pod, rispettando maxSurge, maxUnavailable e le readiness probe. Con probe configurate correttamente, questo permette all'applicazione di riavviarsi senza downtime.

Un caso d'uso comune è recepire modifiche che non riavviano automaticamente i pod. Ad esempio, quando aggiorni una ConfigMap o un Secret che l'applicazione legge solo all'avvio, i pod esistenti continuano a usare i vecchi valori. Un rollout restart sostituisce quei pod in modo che partano con i nuovi valori.

Un rollout restart è più controllato rispetto all'eliminazione manuale dei pod o allo scaling a zero di un Deployment. Eliminare i pod manualmente li sostituisce, ma non offre lo stesso processo di rollout controllato, mentre scalare a zero ferma tutti i pod prima di avviarne di nuovi, causando downtime. Un rollout restart sostituisce i pod gradualmente rispettando le impostazioni di rollout del Deployment.

kubectl rollout pause e resume

kubectl rollout pause impedisce a un Deployment di reagire alle modifiche, e kubectl rollout resume gli permette di proseguire:

kubectl rollout pause deployment/api
kubectl rollout resume deployment/api

Ci sono due situazioni in cui è utile. La prima è raggruppare più modifiche in un unico rollout. Se prima metti in pausa, poi modifichi immagine, risorse e variabili d'ambiente, e infine riprendi, Kubernetes esegue un solo rollout con tutte le modifiche invece di un rollout separato per ogni intervento:

kubectl rollout pause deployment/api
kubectl set image deployment/api api=api:1.5.0
kubectl set resources deployment/api -c=api --limits=cpu=500m,memory=512Mi
kubectl rollout resume deployment/api

La seconda è mettere in pausa a metà di un rollout per validare un canary parziale. Avvii un rollout cambiando l'immagine, lasci che qualche nuovo pod venga avviato, poi metti in pausa. A quel punto una piccola quota di traffico è sulla nuova versione mentre il resto rimane su quella vecchia, e puoi osservarne metriche e log. Se tutto sembra funzionare correttamente, riprendi per completare il rollout; in caso contrario, esegui undo per tornare indietro. Ricorda che non puoi fare il rollback di un Deployment in pausa, quindi riprendilo prima di eseguire undo.

Perché i rollout si bloccano e come diagnosticarli?

Un rollout si blocca quando i nuovi pod non riescono a diventare disponibili, e il Deployment finisce per segnalare ProgressDeadlineExceeded. Ecco le cause più comuni:

a. Capacità del cluster insufficiente per i pod di surge: un rolling update crea pod extra (maxSurge) prima di rimuovere quelli vecchi, quindi il rollout ha bisogno di CPU e memoria libere per schedularli. Se il cluster non ha spazio, i pod di surge restano Pending e il rollout non può avanzare. Devi verificare con kubectl get pods e kubectl describe pod sul pod in pending, e controllare se il Cluster Autoscaler può aggiungere un nodo.

b. Readiness probe fallite e CrashLoopBackOff: se i nuovi pod partono ma non superano mai la readiness probe, oppure vanno in crash e si riavviano a ciclo continuo, non vengono mai conteggiati come disponibili e il rollout si arena. Leggi i log del nuovo pod con kubectl logs e i suoi eventi con kubectl describe pod. È qui che emergono una probe mal configurata o una nuova immagine difettosa.

c. OOMKill causati da request e limit di memoria sottodimensionati: se la nuova versione ha bisogno di più memoria di quanta ne consenta il suo limit, il kernel termina ogni nuovo pod all'avvio, quindi il pod mostra OOMKilled con exit code 137 e il rollout non si completa mai. I log del pod sono di solito vuoti, perché il container è stato terminato anziché andare in crash, quindi il segnale si trova in kubectl describe pod, sotto la voce last state.

d. I PodDisruptionBudget non bloccano il rollout in sé: un PodDisruptionBudget non vincola il rolling update di un Deployment. I PDB non limitano i rolling update dei workloads perché il rollout sostituisce i pod direttamente e non tramite l'API di eviction. Ciò che un PDB vincola sono le eviction volontarie: i drain dei nodi, lo scale-down del Cluster Autoscaler e simili. Quindi un PDB può bloccare il drain di un nodo in corso nello stesso momento del rollout, e un PDB configurato male (ad esempio minAvailable uguale al numero di repliche) può bloccare del tutto i drain, ma non è ciò che sta trattenendo il rollout in sé.

e. Conflitti tra Horizontal Pod Autoscaler e repliche: se un HPA gestisce le repliche di un Deployment e tu imposti anche replicas in modo fisso nel manifest, ogni kubectl apply riporta il conteggio al valore del manifest finché l'HPA non lo corregge di nuovo. Questo può causare comportamenti di scaling confusi durante un rollout. La soluzione è omettere replicas dal manifest per qualunque Deployment gestito da un HPA.

La maggior parte di questi problemi si riconduce al dimensionamento delle risorse. Sia i pod di surge che non trovano posto sul cluster sia i nuovi pod terminati con OOMKilled indicano impostazioni di risorse errate. È qui che PerfectScale fa la differenza. La sua piattaforma di governance per Kubernetes osserva come i tuoi workloads utilizzano realmente CPU e memoria e trasforma questi dati in raccomandazioni di right-sizing concrete e automatizzate, applicabili manualmente o in modo autonomo. Con request e limit allineati alla realtà, i pod di surge trovano posto e i nuovi pod hanno la memoria di cui hanno bisogno, così i rollout si concludono senza intoppi invece di bloccarsi. Team come Paramount Pictures e Creditas usano PerfectScale per mantenere efficienti i loro cluster: puoi registrarti o prenotare una sessione tecnica.

media

Best practice per usare kubectl rollout in produzione

Ecco alcune pratiche semplici per mantenere i rollout in produzione sicuri e fluidi:

a. Fai il right-sizing di request e limit prima del rollout: devi impostare resource request e limit accurati prima di avviare un rollout. Questo dà ai pod di surge lo spazio sufficiente per essere schedulati e riduce il rischio che i nuovi pod vengano terminati per OOMKill.

b. Controlla metriche e log, non solo il rollout status: un rollout status riuscito significa solo che i nuovi pod sono diventati pronti. Non significa che l'applicazione funzioni correttamente. Dopo un rollout dovresti controllare tassi di errore, latenza e log, soprattutto quando usi un canary in pausa.

c. Imposta esplicitamente progressDeadlineSeconds e --timeout: devi impostare un progressDeadlineSeconds ragionevole affinché Kubernetes contrassegni come fallito un Deployment bloccato. Usa --timeout con rollout status così la tua pipeline smette di attendere dopo un periodo definito.

d. Aggiungi un'annotazione change-cause a ogni modifica: dovresti impostare kubernetes.io/change-cause quando apporti modifiche, così rollout history mostra chiaramente cosa è cambiato in ogni revisione. Questo rende più facile scegliere la revisione giusta durante un rollback.

e. Mantieni revisionHistoryLimit abbastanza alto per fare rollback in sicurezza: il valore predefinito di 10 va bene per la maggior parte dei workloads, ma se rilasci con grande frequenza, assicurati che copra comunque le revisioni a cui potresti realisticamente dover tornare.

f. Limita il raggio d'impatto con rollout graduali: evita di inviare una modifica rischiosa a ogni namespace o cluster in una volta sola. Distribuiscila in più fasi, così puoi individuare i problemi in anticipo e fermarti prima che colpiscano tutto.

g. Passa dai comandi manuali a GitOps e progressive delivery: kubectl rollout è utile per imparare e gestire i rollout manualmente. Per ambienti di produzione più grandi, strumenti come Argo CD o Flux possono gestire i deployment tramite GitOps, mentre Argo Rollouts o Flagger possono automatizzare deployment canary e blue-green.