Se le tue app Google Kubernetes Engine (GKE) riscontrano interruzioni impreviste dei container, instabilità o errori CrashLoopBackOff
, il problema potrebbe essere dovuto a eventi Out of Memory (OOM). Gli eventi OOM si verificano quando un container o un nodo esaurisce la
memoria, causando la terminazione dei processi da parte di Linux OOM Killer per recuperare
le risorse.
Utilizza questa pagina per identificare se si è verificato un evento OOM a livello di container o di nodo e applica strategie di mitigazione efficaci per evitare una ricorrenza.
Queste informazioni sono importanti per gli sviluppatori di applicazioni che devono assicurarsi che le loro applicazioni siano configurate con richieste e limiti di memoria appropriati e che non presentino perdite di memoria. È importante anche per gli amministratori e gli operatori della piattaforma che monitorano l'utilizzo delle risorse dei nodi e si assicurano che il cluster disponga di una capacità di memoria adeguata per supportare i carichi di lavoro di cui è stato eseguito il deployment. Per maggiori informazioni sui ruoli comuni e sulle attività di esempio a cui facciamo riferimento nei Google Cloud contenuti, consulta Ruoli utente e attività comuni di GKE.
Cause comuni degli eventi OOM
Gli eventi OOM si verificano in genere durante i picchi di carico o di traffico, quando l'utilizzo della memoria dell'app aumenta e raggiunge il limite di memoria configurato per il container.
I seguenti scenari possono causare un evento OOM:
- Limite di memoria insufficiente: l'impostazione
resources.limits.memory
nel manifest del pod è troppo bassa per le richieste di memoria tipiche o di picco dell'app. - Richieste o limiti di memoria non definiti: se
resources.limits.memory
eresources.requests.memory
non sono definiti, l'utilizzo della memoria del container è illimitato. - Carico elevato o a picchi: picchi improvvisi ed estremi di carico possono sovraccaricare le risorse di un sistema, inclusa la memoria, anche se i limiti sono generalmente adeguati.
- Perdita di memoria: l'app potrebbe avere un difetto di codice che le impedisce di rilasciare correttamente la memoria.
Gli eventi OOM possono avviare un errore a cascata, perché rimangono meno container per gestire il traffico, aumentando il carico sui container rimanenti. Questi contenitori potrebbero quindi essere terminati.
Come Kubernetes gestisce gli eventi OOM
Linux OOM Killer gestisce ogni evento OOM. OOM Killer è un processo del kernel che si attiva quando la memoria del sistema è molto ridotta. Il suo scopo è prevenire un arresto anomalo totale del sistema terminando strategicamente i processi per liberare risorse. Il kernel utilizza un sistema di punteggio per selezionare il processo da arrestare, con l'obiettivo di preservare la stabilità del sistema e ridurre al minimo la perdita di dati.
In un ambiente Kubernetes, OOM Killer opera in due ambiti diversi: il gruppo di controllo (cgroup), che interessa un container, e il sistema, che interessa l'intero nodo.
Terminazione OOM a livello di container
Un arresto anomalo OOM a livello di contenitore si verifica quando un contenitore tenta di superare il limite di memoria predefinito. Kubernetes assegna ogni container a un cgroup specifico con un limite di memoria rigido. Quando l'utilizzo della memoria di un container raggiunge questo limite, il kernel tenta innanzitutto di recuperare la memoria all'interno di questo cgroup. Se il kernel non riesce a recuperare memoria sufficiente utilizzando questo processo, viene richiamato il cgroup OOM Killer. Termina i processi all'interno di quel cgroup specifico per applicare il limite delle risorse.
Quando il processo principale in un container viene terminato in questo modo, Kubernetes osserva
l'evento e contrassegna lo stato del container come OOMKilled
. Il restartPolicy
configurato del pod determina il risultato:
Always
oOnFailure
: il container viene riavviato.Never
: il container non viene riavviato e rimane in stato Terminato.
Isolando l'errore nel container problematico, OOM Killer impedisce che un singolo pod difettoso blocchi l'intero nodo.
In che modo la versione di cgroup influisce sul comportamento di OOM Killer
Il comportamento di OOM kill può variare in modo significativo tra le versioni di cgroup. Se non sai quale versione di cgroup utilizzi, controlla la modalità cgroup dei nodi del cluster.
In
cgroup v1
, un evento OOM all'interno del cgroup di memoria di un container può portare a un comportamento imprevedibile. OOM Killer potrebbe terminare qualsiasi processo all'interno di questo cgroup, inclusi i processi secondari che non sono il processo principale del container (PID 1).Questo comportamento rappresenta una sfida significativa per Kubernetes. Poiché Kubernetes monitora principalmente l'integrità del processo del container principale, non è a conoscenza di questi errori OOM "parziali". Il processo contenitore principale potrebbe continuare a essere eseguito, anche se i processi secondari critici sono stati terminati. Questo comportamento può causare errori sottili dell'app che non sono immediatamente visibili a Kubernetes o agli operatori, ma sono comunque visibili nel journal di sistema del nodo (
journalctl
).cgroup v2
offre un comportamento più prevedibile di OOM Killer.Per garantire l'integrità del workload in un ambiente cgroup v2, OOM killer impedisce le interruzioni parziali e garantisce uno dei due risultati: o tutte le attività appartenenti a quel cgroup e ai suoi discendenti vengono terminate (rendendo l'errore visibile a Kubernetes) oppure, quando il workload non ha attività che utilizzano troppa memoria, il workload viene lasciato intatto e continua a essere eseguito senza interruzioni impreviste dei processi interni.
Per gli scenari in cui vuoi che
cgroup v1
termini un singolo processo, kubelet fornisce il flagsingleProcessOOMKill
percgroup v2
. Questo flag ti offre un controllo più granulare, consentendo la terminazione di singoli processi durante un evento OOM, anziché dell'intero cgroup.
Terminazione OOM a livello di sistema
Un arresto anomalo OOM a livello di sistema è un evento più grave che si verifica quando l'intero nodo, non solo un singolo container, esaurisce la memoria disponibile. Questo evento può verificarsi se l'utilizzo combinato della memoria di tutti i processi (inclusi tutti i pod e i daemon di sistema) supera la capacità del nodo.
Quando questo nodo esaurisce la memoria, OOM Killer globale valuta tutti i processi sul nodo e termina un processo per recuperare memoria per l'intero sistema. Il processo selezionato è in genere di breve durata e utilizza una grande quantità di memoria.
Per evitare gravi situazioni di esaurimento della memoria, Kubernetes utilizza l'espulsione node-pressure per gestire le risorse dei nodi. Questo processo prevede l'espulsione dei pod meno critici da un nodo quando le risorse, come memoria o spazio su disco, stanno per esaurirsi. Un'interruzione OOM a livello di sistema indica che questo processo di eliminazione non è riuscito a liberare memoria abbastanza rapidamente da evitare il problema.
Se OOM Killer termina il processo di un container, l'effetto è in genere
identico a un arresto attivato da cgroup: il container viene contrassegnato come OOMKilled
e
riavviato in base al criterio. Tuttavia, se un processo di sistema critico viene interrotto
(cosa rara), il nodo stesso potrebbe diventare instabile.
Esamina gli eventi OOM
Le sezioni seguenti ti aiutano a rilevare e confermare un evento OOM, a partire dagli strumenti Kubernetes più semplici e passando all'analisi dei log più dettagliata.
Controlla lo stato del pod per gli eventi OOM visibili
Il primo passo per confermare un evento OOM è verificare se Kubernetes ha osservato
l'evento OOM. Kubernetes osserva l'evento quando il processo principale del container viene interrotto, il che è un comportamento standard negli ambienti cgroup v2
.
Controlla lo stato del pod:
kubectl describe pod POD_NAME
Sostituisci
POD_NAME
con il nome del pod che vuoi esaminare.Se si è verificato un evento OOM visibile, l'output è simile al seguente:
... Last State: Terminated Reason: OOMKilled Exit Code: 137 Started: Tue, 13 May 2025 19:05:28 +0000 Finished: Tue, 13 May 2025 19:05:30 +0000 ...
Se vedi OOMKilled
nel campo Reason
, hai confermato l'evento. Un
Exit Code
di 137
indica anche un OOM kill. Se il campo Reason
ha un
valore diverso o il pod è ancora in esecuzione nonostante gli errori dell'app, vai alla
sezione successiva per ulteriori indagini.
Cercare nei log eventi OOM invisibili
Un'interruzione OOM è "invisibile" a Kubernetes se un processo secondario viene interrotto, ma il
processo del container principale continua a essere eseguito (uno scenario comune negli ambienti cgroup v1
). Devi cercare nei log del nodo per trovare prove di questi eventi.
Per trovare gli errori OOM invisibili, utilizza Esplora log:
Nella console Google Cloud , vai a Esplora log.
Nel riquadro della query, inserisci una delle seguenti query:
Se hai già un pod che ritieni abbia riscontrato un evento OOM, esegui una query su quel pod specifico:
resource.type="k8s_node" jsonPayload.MESSAGE:(("POD_NAME" AND "ContainerDied") OR "TaskOOM event") resource.labels.cluster_name="CLUSTER_NAME"
Sostituisci quanto segue:
POD_NAME
: il nome del pod che vuoi interrogare.CLUSTER_NAME
: il nome del cluster a cui appartiene il pod.
Per scoprire quali pod o nodi hanno riscontrato un evento OOM, esegui una query su tutti i workload GKE:
resource.type="k8s_node" jsonPayload.MESSAGE:("ContainerDied" OR "TaskOOM event") resource.labels.cluster_name="CLUSTER_NAME"
Fai clic su Esegui query.
Nell'output, individua gli eventi OOM cercando le voci di log contenenti la stringa
TaskOOM
.(Facoltativo) Se hai cercato eventi OOM per tutti i carichi di lavoro GKE e vuoi identificare il pod specifico che ha riscontrato gli eventi OOM, completa i seguenti passaggi:
- Per ogni evento, prendi nota dell'ID contenitore associato.
Identifica gli arresti dei container cercando voci di log contenenti la stringa
ContainerDied
e che si sono verificate poco dopo gli eventi OOM. Abbina l'ID container dell'evento OOM alla rigaContainerDied
corrispondente.Dopo aver trovato la corrispondenza con
container IDs
, la rigaContainerDied
in genere include il nome del pod associato al container non riuscito. Questo pod è stato interessato dall'evento OOM.
Utilizzare journalctl per informazioni in tempo reale
Se devi eseguire l'analisi in tempo reale del tuo sistema, utilizza i comandi journalctl
.
Connettiti al nodo utilizzando SSH:
gcloud compute ssh NODE_NAME --location ZONE
Sostituisci quanto segue:
NODE_NAME
: il nome del nodo che vuoi esaminare.ZONE
: la zona Compute Engine a cui appartiene il nodo.
Nella shell, esplora i messaggi del kernel dal journal di sistema del nodo:
journalctl -k
Analizza l'output per distinguere il tipo di evento:
- Interruzione a livello di contenitore: la voce di log contiene termini come
memory cgroup
,mem_cgroup
omemcg
, che indicano che è stato applicato un limite cgroup. - Interruzione a livello di sistema: la voce di log è un messaggio generico
come
Out of memory: Killed process...
senza menzionare un cgroup.
- Interruzione a livello di contenitore: la voce di log contiene termini come
Risolvere gli eventi OOM
Per risolvere un evento OOM, prova le seguenti soluzioni:
- Aumenta i limiti di memoria: questa è la soluzione più diretta. Modifica il manifest del pod per fornire un valore
resources.limits.memory
più elevato che si adatti al picco di utilizzo dell'app. Per ulteriori informazioni sull'impostazione dei limiti, consulta Gestione delle risorse per pod e container nella documentazione di Kubernetes. - Aggiungi o modifica le richieste di memoria: nel manifest del pod, verifica che il campo
resources.requests.memory
sia impostato su un valore realistico per l'utilizzo tipico. Questa impostazione aiuta Kubernetes a pianificare il pod su un nodo con memoria sufficiente. - Scalare orizzontalmente il workload: per distribuire il carico di traffico e ridurre la pressione sulla memoria di un singolo pod, aumenta il numero di repliche. Per fare in modo che Kubernetes esegua lo scale up del carico di lavoro in modo proattivo, valuta la possibilità di abilitare la scalabilità automatica orizzontale dei pod.
- Scalare verticalmente i nodi: se molti pod su un nodo sono vicini ai limiti, il nodo stesso potrebbe essere troppo piccolo. Per aumentare le dimensioni dei nodi, esegui la migrazione dei workload a un pool di nodi con più memoria. Per consentire a Kubernetes di scalare in modo proattivo i nodi, valuta la possibilità di abilitare la scalabilità automatica pod verticale.
- Ottimizza la tua app: esamina la tua app per identificare e risolvere le perdite di memoria e ottimizza il codice che consuma grandi quantità di memoria durante i picchi di traffico.
- Elimina i carichi di lavoro problematici: come ultima risorsa per i carichi di lavoro non critici, elimina il pod per ridurre immediatamente la pressione sul cluster.
Passaggi successivi
Se non riesci a trovare una soluzione al tuo problema nella documentazione, consulta la sezione Richiedi assistenza per ulteriore aiuto, inclusi consigli sui seguenti argomenti:
- Aprire una richiesta di assistenza contattando l'assistenza clienti cloud.
- Ricevere assistenza dalla community
ponendo domande su Stack Overflow e utilizzando il tag
google-kubernetes-engine
per cercare problemi simili. Puoi anche unirti al canale Slack#kubernetes-engine
per ulteriore assistenza della community. - Apertura di bug o richieste di funzionalità utilizzando lo strumento di monitoraggio dei problemi pubblico.