Se le tue applicazioni Google Kubernetes Engine (GKE) presentano terminazioni impreviste dei container, instabilità o errori CrashLoopBackOff, il problema potrebbe essere dovuto a eventi di memoria esaurita (OOM). Gli eventi OOM si verificano quando un container o un nodo esaurisce la memoria, il che fa sì che Linux OOM Killer termini i processi per recuperare 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 che si ripeta.
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 abbia una capacità di memoria adeguata per supportare i workload di cui è stato eseguito il deployment. Per saperne di più sui ruoli comuni e sulle attività di esempio a cui facciamo riferimento nei contenuti di Google Cloud , consulta Ruoli e attività comuni degli utenti 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.memorynel manifest del pod è troppo bassa per le esigenze di memoria tipiche o di picco dell'app. - Richieste o limiti di memoria non definiti: se non sono definiti né
resources.limits.memorynéresources.requests.memory, la memoria utilizzata dal container non ha limiti. - Carico elevato o con picchi: picchi di carico improvvisi ed estremi possono sovraccaricare le risorse di un sistema, inclusa la memoria, anche se i limiti sono generalmente adeguati.
- Perdita di memoria: l'app potrebbe presentare un difetto del codice che impedisce il rilascio corretto della 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 container potrebbero quindi essere terminati.
In che modo Kubernetes gestisce gli eventi OOM
Il killer OOM di Linux gestisce ogni evento OOM. OOM Killer è un processo del kernel che si attiva quando la memoria del sistema è quasi esaurita. Il suo scopo è impedire 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, l'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 per OOM a livello di container si verifica quando un container tenta di superare il limite di memoria predefinito. Kubernetes assegna ogni container a un cgroup specifico con un limite di memoria rigido. Quando la memoria utilizzata di un container raggiunge questo limite, il kernel tenta innanzitutto di recuperare memoria all'interno di quel cgroup. Se il kernel non riesce a recuperare memoria sufficiente utilizzando questo processo, viene richiamato il killer OOM del cgroup. 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. restartPolicy configurato del pod determina quindi il risultato:
AlwaysoOnFailure: il container viene riavviato.Never: il container non viene riavviato e rimane in uno stato terminato.
Isolando l'errore nel container incriminato, OOM Killer impedisce che un singolo pod difettoso provochi l'arresto anomalo dell'intero nodo.
In che modo la versione di cgroup influisce sul comportamento di OOM Killer
Il comportamento di interruzione OOM può variare in modo significativo tra le versioni di cgroup. Se non sai con certezza 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ò causare un comportamento imprevedibile. Il killer OOM potrebbe terminare qualsiasi processo all'interno di quel 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 arresti OOM "parziali". Il processo del container principale potrebbe continuare a essere eseguito, anche se i processi figlio critici sono stati terminati. Questo comportamento può causare errori impercettibili dell'app che non sono immediatamente visibili a Kubernetes o agli operatori, ma sono comunque visibili nel journal di sistema del nodo (
journalctl).cgroup v2offre un comportamento del killer OOM più prevedibile.Per garantire l'integrità del workload in un ambiente cgroup v2, l'OOM killer impedisce le terminazioni parziali e garantisce uno dei due risultati: o tutte le attività appartenenti a quel cgroup e ai relativi discendenti vengono terminate (rendendo l'errore visibile a Kubernetes) o, se il workload non ha attività che utilizzano troppa memoria, il workload rimane invariato e continua a essere eseguito senza terminazioni impreviste dei processi interni.
Per gli scenari in cui vuoi il comportamento
cgroup v1di terminazione di un singolo processo, kubelet fornisce il flagsingleProcessOOMKillpercgroup 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 per 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 la memoria utilizzata combinata di tutti i processi (inclusi tutti i pod e i daemon di sistema) supera la capacità del nodo.
Quando questo nodo esaurisce la memoria, il killer OOM globale valuta tutti i processi sul nodo e ne termina uno per recuperare memoria per l'intero sistema. Il processo selezionato è in genere uno di breve durata e che utilizza una grande quantità di memoria.
Per evitare situazioni di OOM gravi, Kubernetes utilizza l'eliminazione per pressione sul nodo per gestire le risorse dei nodi. Questo processo prevede l'espulsione dei pod meno critici da un nodo quando le risorse, come la memoria o lo spazio su disco, diventano estremamente scarse. Un arresto per memoria esaurita a livello di sistema indica che questo processo di espulsione non è riuscito a liberare memoria abbastanza rapidamente da evitare il problema.
Se il killer OOM termina il processo di un container, l'effetto è in genere identico a un'interruzione attivata da cgroup: il container viene contrassegnato come OOMKilled e riavviato in base alla sua policy. Tuttavia, se viene terminato un processo di sistema critico (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 fino ad arrivare a un'analisi dei log più dettagliata.
Controlla lo stato del pod per verificare la presenza di eventi OOM visibili
Il primo passaggio per confermare un evento OOM consiste nel verificare se Kubernetes ha osservato l'evento OOM. Kubernetes osserva l'evento quando il processo principale del container viene terminato, il che è un comportamento standard negli ambienti cgroup v2.
Controlla lo stato del pod:
kubectl describe pod POD_NAMESostituisci
POD_NAMEcon 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 valore Exit Code di 137 indica anche un arresto per memoria esaurita. Se il campo Reason ha un valore diverso o se il pod è ancora in esecuzione nonostante gli errori dell'app, vai alla sezione successiva per ulteriori indagini.
Cerca nei log gli eventi OOM invisibili
Un arresto per OOM è "invisibile" a Kubernetes se un processo figlio viene arrestato, 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 arresti per OOM invisibili, utilizza Esplora log:
Nella console Google Cloud , vai a Esplora log.
Nel riquadro delle query, inserisci una delle seguenti query:
Se hai già un pod che ritieni abbia subito 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 su cui vuoi eseguire la query.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 workload 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 le voci di log contenenti la stringa
ContainerDiede che si sono verificate poco dopo gli eventi OOM. Abbina l'ID container dell'evento OOM alla rigaContainerDiedcorrispondente.Dopo aver trovato la corrispondenza con
container IDs, la rigaContainerDiedin genere include il nome del pod associato al container che ha generato l'errore. Questo pod è stato interessato dall'evento OOM.
Correla gli eventi OOM con i riavvii dei container
Quando un arresto per OOM termina il processo principale di un container, Kubernetes riavvia il container in base al restartPolicy del pod, come descritto in Arresto per OOM a livello di container e Arresto per OOM a livello di sistema. Per visualizzare gli eventi OOMKilling e gli avvii dei container che li seguono in un unico elenco cronologico, utilizza Esplora log:
Nella console Google Cloud , vai a Esplora log.
Nel riquadro delle query, inserisci la seguente query:
log_id("events") resource.labels.cluster_name="CLUSTER_NAME" ( ( resource.type="k8s_pod" resource.labels.namespace_name="NAMESPACE_NAME" jsonPayload.message:"Started container" ) OR ( resource.type="k8s_node" jsonPayload.reason="OOMKilling" ) )Sostituisci quanto segue:
CLUSTER_NAME: il nome del cluster su cui vuoi eseguire la query.NAMESPACE_NAME: lo spazio dei nomi dei pod che vuoi esaminare.
Gli eventi
OOMKillingvengono segnalati per il nodo (tipo di risorsak8s_node), quindi non hanno un'etichetta dello spazio dei nomi. Il filtro dello spazio dei nomi si applica solo agli eventiStarted container, che vengono segnalati per il pod (tipo di risorsak8s_pod).Fai clic su Esegui query.
Nell'output, cerca gli eventi
Started containerche si verificano poco dopo un eventoOOMKillingsullo stesso nodo. Il messaggio dell'eventoOOMKillingidentifica il processo che è stato terminato, mentre l'eventoStarted containeridentifica il pod e il container che sono stati avviati.Non tutti gli eventi
Started containersono causati da un arresto per OOM. Per confermare che un container è stato riavviato a causa di un evento OOM, controlla lo stato del pod come descritto in Controlla lo stato del pod per verificare la presenza di eventi OOM visibili.
Utilizza journalctl per informazioni in tempo reale
Se devi eseguire un'analisi in tempo reale del sistema, utilizza i comandi journalctl.
Connettiti al nodo utilizzando SSH:
gcloud compute ssh NODE_NAME --location ZONESostituisci quanto segue:
NODE_NAME: il nome del nodo che vuoi esaminare.ZONE: la zona di Compute Engine a cui appartiene il nodo.
Nella shell, esplora i messaggi del kernel dal journal di sistema del nodo:
journalctl -kAnalizza l'output per distinguere il tipo di evento:
- Interruzione a livello di container: la voce di log contiene termini come
memory cgroup,mem_cgroupomemcg, che indicano che è stato applicato un limite cgroup. - Interruzione a livello di sistema: la voce di log è un messaggio generale come
Out of memory: Killed process...senza menzionare un cgroup.
- Interruzione a livello di container: la voce di log contiene termini come
Risolvi 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.memorypiù elevato che soddisfi l'utilizzo di picco dell'app. Per saperne di più 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.memorysia impostato su un valore realistico per l'utilizzo tipico. Questa impostazione aiuta Kubernetes a pianificare il pod su un nodo con memoria sufficiente. - Scala il workload in orizzontale: per distribuire il carico di traffico e ridurre la pressione sulla memoria su un singolo pod, aumenta il numero di repliche. Per fare in modo che Kubernetes scali il workload in modo proattivo, valuta la possibilità di abilitare la scalabilità automatica orizzontale dei pod.
- Scala i nodi verticalmente: se molti pod su un nodo sono vicini ai loro 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 fare in modo che Kubernetes scali i nodi in modo proattivo, valuta la possibilità di attivare la scalabilità automatica verticale dei pod.
- Ottimizza l'app: esamina l'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 workload problematici: come ultima risorsa per i workload 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 Richiedi assistenza per ulteriore aiuto, inclusi consigli sui seguenti argomenti:
- Aprire una richiesta di assistenza contattando l'assistenza clienti Google Cloud.
- Ricevere assistenza dalla community facendo domande su StackOverflow e utilizzando il tag
google-kubernetes-engineper cercare problemi simili. Puoi anche unirti al canale Slack#kubernetes-engineper ricevere ulteriore assistenza dalla community. - Apertura di problemi o richieste di funzionalità utilizzando l'Issue Tracker pubblico.