Quando un pod Kubernetes entra in CrashLoopBackOff subito dopo il riavvio di un nodo, il problema spesso non è nell’applicazione in sé ma nel contesto in cui viene rilanciata: volumi non pronti, dipendenze esterne non raggiungibili, limiti di risorse troppo stretti, probe troppo aggressive o configurazioni che cambiano ordine di avvio. Il punto critico è distinguere tra un crash reale del processo e un loop di riavvio causato da condizioni ambientali transitorie.
In questo articolo trovi un percorso pratico per fare diagnosi rapida, raccogliere evidenze utili e applicare una correzione minima e reversibile. L’obiettivo non è “spegnere l’allarme”, ma capire perché il pod fallisce dopo il reboot del nodo e come evitare che il problema torni alla prima manutenzione o al prossimo drain.
Diagnosi probabile
La causa più comune è una di queste:
- il container parte prima che un volume persistente sia disponibile o montato correttamente;
- il servizio esterno a cui l’app si connette non è ancora pronto quando parte il pod;
- le liveness probe o startup probe sono troppo strette e provocano riavvii prematuri;
- la memoria o la CPU assegnate non bastano dopo il restart, soprattutto se il nodo torna operativo con carico elevato;
- l’app legge segreti o configmap che, dopo il riavvio, non vengono trovati subito per un problema di sincronizzazione o permessi.
Se il problema appare solo dopo reboot, è utile pensare al timing: il nodo rientra, i controller riprogrammano i pod, ma alcune dipendenze impiegano più tempo a stabilizzarsi. Il risultato è un avvio fallito che sembra casuale ma è ripetibile.
Verifiche immediate
Prima di cambiare qualcosa, conviene raccogliere tre segnali concreti.
- Controlla lo stato del pod e la sequenza dei restart con
kubectl get pod -n NAMESPACE -o wideekubectl describe pod NOME_POD -n NAMESPACE. L’esito atteso è vedere eventi utili come errori di mount, probe fallite o exit code del container. - Leggi i log dell’ultimo tentativo con
kubectl logs NOME_POD -n NAMESPACE --previous. Se l’app si chiude subito, qui trovi spesso il messaggio decisivo: connessione rifiutata, file mancanti, timeout, permesso negato. - Verifica se il problema colpisce solo quel nodo con
kubectl get pod -n NAMESPACE -o widee confronta il nodo con altri pod simili. Se i pod sullo stesso nodo falliscono insieme, il nodo o il suo storage sono una pista forte.
Se usi storage persistente, controlla anche se il PersistentVolumeClaim è Bound e se il volume risulta montato. Un PVC in stato corretto ma con mount lento può comunque generare crash iniziali, soprattutto se l’app non aspetta il filesystem prima di partire.
Soluzione consigliata passo-passo
La correzione più sicura è procedere per esclusione, partendo dal punto meno invasivo.
1. Allarga il tempo di avvio
Se il container richiede qualche secondo in più dopo il reboot del nodo, aumenta il margine delle probe. In pratica, fai in modo che Kubernetes non interpreti come fallimento ciò che è solo un avvio lento.
Nel manifest, valuta di usare una startup probe per dare all’app una finestra di avvio più ampia. Questo è utile soprattutto se oggi hai solo liveness e readiness probe molto aggressive.
Effetto atteso: il container può impiegare più tempo a diventare sano senza essere riavviato in anticipo.
2. Verifica le dipendenze esterne
Se l’app si collega a database, code, storage o API interne, prova a introdurre un controllo di disponibilità esplicito prima dell’avvio vero e proprio. Puoi farlo con uno script di entrypoint semplice, oppure con una logica di retry lato applicazione.
Per esempio, se il database è in un altro nodo o in un servizio che torna operativo dopo il cluster, il pod potrebbe fallire al primo tentativo ma non al secondo. In questo caso il fix corretto non è “riavviare più spesso”, ma aspettare il servizio giusto al momento giusto.
Verifica dopo la modifica: il pod deve passare da CrashLoopBackOff a Running senza necessità di restart manuali.
3. Controlla richieste e limiti
Un nodo appena riavviato può avere risorse più contese del normale. Se il pod è dimensionato troppo stretto, il processo può essere ucciso dal kernel o dal runtime prima di stabilizzarsi. Controlla resources.requests e resources.limits nel deployment e confrontali con il consumo reale osservato nei periodi di carico.
Se vedi OOM kill o riavvii senza log applicativi, aumenta prima la memoria di un margine moderato, non raddoppiare alla cieca. L’obiettivo è capire se il problema è un picco transitorio o un sottodimensionamento strutturale.
4. Rivedi mount e permessi
Se il pod usa volumi, monta e permessi vanno verificati con attenzione. Dopo il reboot, un volume può essere presente ma non ancora pronto al momento in cui il container parte. In altri casi il filesystem si monta ma i permessi non consentono all’utente del container di scrivere la directory di lavoro.
Controlla se il container gira con un runAsUser specifico e se la directory montata è compatibile. In ambienti con storage condiviso, spesso la soluzione è allineare fsGroup o correggere ownership e mode sul volume, sempre con una modifica minima e verificabile.
5. Aggiorna le probe con criterio
Le probe non devono essere “più permissive” in modo generico, ma coerenti con il vero tempo di avvio. Se l’app ha bisogno di 40 secondi per inizializzarsi e la liveness probe parte dopo 10, il crash loop è quasi garantito al primo riavvio lento.
Imposta soglie realistiche, misurate in base al comportamento reale: initialDelaySeconds, timeoutSeconds, periodSeconds e failureThreshold vanno letti insieme. La startup probe è spesso il modo più pulito per separare fase di bootstrap e controllo di salute.
Controlli finali / rollback
Dopo il fix, fai questi controlli:
- verifica che il pod resti stabile per alcuni minuti e non aumenti il contatore dei restart;
- controlla i log per confermare che l’app completa l’inizializzazione e non resta bloccata su retry infiniti;
- apri il servizio dall’esterno o con un
kubectl port-forwarde conferma che la risposta sia coerente con lo stato Ready.
Se la modifica riguarda probe, richieste o limiti, il rollback è semplice: ripristina il manifest precedente e riapplica la versione salvata prima del cambio. Se il problema peggiora dopo l’intervento, torna subito alla configurazione originale e confronta i log prima e dopo la modifica.
In caso di dubbio, la strategia più sicura è correggere una sola variabile alla volta. Cambiare insieme probe, risorse e volumi rende difficile capire quale azione abbia davvero risolto il problema.
Regola pratica: se un pod fallisce solo dopo il reboot del nodo, pensa prima a timing, dipendenze e mount, poi al codice applicativo.
Per evitare recidive, conviene anche tenere una piccola checklist operativa per i reboot programmati:
- salva il manifest del workload prima dell’intervento;
- controlla lo stato dei volumi e delle dipendenze esterne;
- monitora restart, eventi e log nei primi minuti dopo il ritorno del nodo;
- conferma che la readiness sia reale, non solo nominale.
Se il cluster è critico, valuta una finestra di manutenzione con osservazione attiva: il problema spesso emerge solo quando il nodo rientra in servizio sotto carico normale. In quel momento, avere già pronti eventi, log e una copia del manifest precedente permette di intervenire in modo rapido e reversibile, senza trasformare un semplice riavvio in un incidente prolungato.
In sintesi, il modo migliore per uscire da un CrashLoopBackOff post-reboot non è “riavviare finché funziona”, ma rendere il pod tollerante ai tempi reali del nodo, delle dipendenze e dello storage. Una diagnosi ordinata, una sola modifica per volta e un controllo finale chiaro sono la combinazione più affidabile per riportare il servizio stabile.
Commenti (0)
Nessun commento ancora.
Segnala contenuto
Elimina commento
Eliminare definitivamente questo commento?
L'azione non si può annullare.