🧟‍♂️ The Kubernetes "Eviction Graveyard": How to Fix and Prevent Ephemeral-Storage Crashes

A hands-on guide to maintaining cluster stability under heavy AI and data-processing workloads.

If you have been managing Kubernetes clusters for a while, especially clusters running heavy AI, OCR, or data-processing workloads, you've probably run into the dreaded "Eviction Graveyard."

You run kubectl get pods, expecting to see a clean list of running microservices, and instead, you are greeted by this nightmare:

List of Evicted Kubernetes Pods

Dozens, sometimes hundreds, of dead pods cluttering your namespace.

In this post, I will break down exactly what this error means, how to clean it up instantly, and most importantly, the Enterprise Best Practices to ensure it never happens to your production cluster again.

🔍 What is the "Eviction Graveyard"?

When a pod shows as Evicted, it means the Kubernetes Worker Node completely ran out of a critical resource—usually RAM or Hard Drive space (ephemeral-storage).

To prevent the entire Linux server from crashing, the Kubelet goes into "survival mode" and aggressively assassinates the pods consuming the most resources.

However, because your pods are managed by a Deployment, Kubernetes immediately says, "Oh no, the pod died! Let me spin up a replacement." The new pod starts, fills up the hard drive again, and gets killed again. This endless loop creates the graveyard of dead pods.

If you see ContainerStatusUnknown, it means the Worker Node was struggling so badly (likely at 100% CPU or 100% Disk IO) that it temporarily lost communication with the Kubernetes Control Plane.

🧯 The Immediate Fix (Putting out the fire)

Before we fix the root cause, let's clean up your terminal and free up the node.

1. Clean up the Graveyard

Those Evicted pods are completely dead, but they are cluttering your view. You can instantly wipe all failed pods in your namespace with this command:

kubectl delete pods --field-selector status.phase=Failed -n <your-namespace>

2. Free up the Node's Disk Space

Usually, this happens because local Docker/Containerd images and temporary files have filled up the node's disk. SSH into your struggling worker node and prune the unused images:

# If using RKE2/Containerd:
sudo /var/lib/rancher/rke2/bin/crictl rmi --prune

# If using standard Docker:
docker image prune -a

🏗️ The Root Cause: Ephemeral-Storage

In my case, the issue was tied to AI Document Processing microservices.

When your application downloads large PDFs or images, processes them, and saves temp files to the local Linux container (/tmp), it consumes ephemeral-storage. If the app doesn't delete those files after processing, the pod bloats until it consumes the node's entire hard drive.

🌟 Enterprise Best Practices (The Permanent Fix)

In a professional DevOps environment, you never want a single rogue microservice to fill up a server's hard drive and take down neighboring applications. Here is the two-step best practice to secure your cluster.

1. The DevOps Fix: Enforce Resource Limits

You must tell Kubernetes to isolate the damage. By setting ephemeral-storage limits in your Helm Chart or Deployment YAML, you instruct Kubernetes: "If this specific pod writes more than 3GB of temporary files, kill ONLY this pod, before it threatens the rest of the node."

Add this to your deployment.yaml under the resources block:

resources:
  requests:
    cpu: "500m"
    memory: "1Gi"
    ephemeral-storage: "1Gi"  # Asks the node to guarantee 1GB of disk space
  limits:
    cpu: "2"
    memory: "4Gi"
    ephemeral-storage: "3Gi"  # Kills the pod if it exceeds 3GB of temp files!

2. The Developer Fix: Code-Level Cleanup

Infrastructure limits are the safety net, but the actual cure requires good software engineering. If your application processes files (like an AI model running inference on documents), the code must include a cleanup phase.

Ensure your developers are using standard cleanup methods in their code (e.g., Python's os.remove(temp_file_path) or tempfile.TemporaryDirectory()) as soon as the API response is sent to the user.

Conclusion

Kubernetes is incredibly resilient, but it relies on us to give it the right boundaries. By combining automated cleanup commands, strict YAML resource limits, and good developer practices, you can permanently banish the Eviction Graveyard from your cluster.

Have you run into the Eviction Graveyard before? Let me know how you solved it on LinkedIn!

🧟‍♂️ Le « Cimetière d'Évictions » Kubernetes : Comment Réparer et Prévenir les Plantages

Un guide pratique pour maintenir la stabilité du cluster sous de lourdes charges d'IA et de traitement de données.

Si vous gérez des clusters Kubernetes depuis un certain temps, en particulier des clusters exécutant de lourdes charges de travail d'IA, d'OCR ou de traitement de données, vous avez probablement déjà rencontré le redouté « Cimetière d'Évictions ».

Vous lancez kubectl get pods en vous attendant à voir une liste propre de microservices en cours d'exécution, et au lieu de cela, vous êtes accueilli par ce cauchemar :

Liste des Pods Kubernetes Évincés

Des dizaines, parfois des centaines, de pods morts encombrent votre namespace.

Dans cet article, je vais vous expliquer exactement ce que signifie cette erreur, comment la nettoyer instantanément, et surtout, les Meilleures Pratiques d'Entreprise pour s'assurer que cela ne se produise plus jamais sur votre cluster de production.

🔍 Qu'est-ce que le « Cimetière d'Évictions » ?

Lorsqu'un pod affiche le statut Evicted (Évincé), cela signifie que le nœud de travail Kubernetes est complètement à court d'une ressource critique, généralement de la RAM ou de l'espace disque (ephemeral-storage).

Pour éviter que le serveur Linux entier ne plante, le Kubelet passe en « mode survie » et assassine agressivement les pods qui consomment le plus de ressources.

Cependant, parce que vos pods sont gérés par un Deployment, Kubernetes se dit immédiatement : « Oh non, le pod est mort ! Laissez-moi en démarrer un de remplacement. » Le nouveau pod démarre, remplit à nouveau le disque dur, et est tué à nouveau. Cette boucle sans fin crée le cimetière de pods morts.

Si vous voyez ContainerStatusUnknown, cela signifie que le nœud de travail était tellement en difficulté (probablement à 100 % de CPU ou 100 % d'E/S disque) qu'il a temporairement perdu la communication avec le Control Plane de Kubernetes.

🧯 La Correction Immédiate (Éteindre l'incendie)

Avant de corriger la cause fondamentale, nettoyons votre terminal et soulageons le nœud.

1. Nettoyer le Cimetière

Ces pods évincés sont complètement morts, mais ils encombrent votre vue. Vous pouvez supprimer instantanément tous les pods en échec dans votre namespace avec cette commande :

kubectl delete pods --field-selector status.phase=Failed -n <votre-namespace>

2. Libérer l'Espace Disque du Nœud

Généralement, cela se produit parce que les images Docker/Containerd locales et les fichiers temporaires ont rempli le disque du nœud. Connectez-vous en SSH à votre nœud en difficulté et purgez les images inutilisées :

# Si vous utilisez RKE2/Containerd :
sudo /var/lib/rancher/rke2/bin/crictl rmi --prune

# Si vous utilisez Docker standard :
docker image prune -a

🏗️ La Cause Profonde : Stockage Éphémère (ephemeral-storage)

Dans mon cas, le problème était lié aux microservices de traitement de documents par IA.

Lorsque votre application télécharge de gros PDF ou images, les traite et enregistre des fichiers temporaires dans le conteneur Linux local (/tmp), elle consomme du ephemeral-storage. Si l'application ne supprime pas ces fichiers après traitement, le pod gonfle jusqu'à consommer tout le disque dur du nœud.

🌟 Meilleures Pratiques d'Entreprise (La Solution Permanente)

Dans un environnement DevOps professionnel, vous ne voulez jamais qu'un seul microservice malveillant remplisse le disque dur d'un serveur et fasse tomber les applications voisines. Voici la meilleure pratique en deux étapes pour sécuriser votre cluster.

1. La Solution DevOps : Appliquer les Limites de Ressources

Vous devez dire à Kubernetes de contenir les dégâts. En définissant des limites de stockage éphémère dans votre Chart Helm ou votre fichier YAML de déploiement, vous donnez la consigne à Kubernetes : « Si ce pod spécifique écrit plus de 3 Go de fichiers temporaires, tue UNIQUEMENT ce pod, avant qu'il ne menace le reste du nœud. »

Ajoutez ceci à votre deployment.yaml sous le bloc resources :

resources:
  requests:
    cpu: "500m"
    memory: "1Gi"
    ephemeral-storage: "1Gi"  # Demande au nœud de garantir 1 Go d'espace disque
  limits:
    cpu: "2"
    memory: "4Gi"
    ephemeral-storage: "3Gi"  # Tue le pod s'il dépasse 3 Go de fichiers temporaires !

2. La Solution Développeur : Nettoyage au Niveau du Code

Les limites d'infrastructure sont un filet de sécurité, mais le véritable remède nécessite une bonne ingénierie logicielle. Si votre application traite des fichiers (comme un modèle d'IA effectuant des inférences sur des documents), le code doit inclure une phase de nettoyage.

Assurez-vous que vos développeurs utilisent des méthodes de nettoyage standard dans leur code (par ex. os.remove(chemin_fichier_temp) en Python ou tempfile.TemporaryDirectory()) dès que la réponse API est envoyée à l'utilisateur.

Conclusion

Kubernetes est incroyablement résilient, mais il compte sur nous pour lui donner les bonnes limites. En combinant des commandes de nettoyage automatisées, des limites de ressources YAML strictes et de bonnes pratiques de développement, vous pouvez bannir définitivement le Cimetière d'Évictions de votre cluster.

Avez-vous déjà rencontré le Cimetière d'Évictions ? Dites-moi comment vous l'avez résolu sur LinkedIn !