المستوى: مبتدئ — مناسب لأي مهندس Kubernetes معاه أقل من سنة خبرة وشاف رسالة OOMKilled في الـ logs مرة واحدة على الأقل.
OOMKilled في Kubernetes: ليه الـ pod بيموت رغم إن السيرفر فاضي
لو فتحت kubectl get pods ولقيت STATUS: OOMKilled قدامك، Kubernetes مش غلطان. هو نفّذ بالظبط الأرقام اللي انت كتبتها في الـ YAML. غالبًا انت كتبت memory: 256Mi وبرنامجك بياكل 280Mi في الذروة، فالـ Linux kernel قتله في 200 مللي ثانية بدون إنذار. مفيش graceful shutdown، مفيش سطر في الـ logs، مفيش chance ينضّف الـ DB connections.
المشكلة باختصار
Kubernetes بيدّي لكل container "حصة" من الـ RAM. لو الـ container تخطّى الحصة دي بـ 1 بايت واحد، الـ kernel بيبعتله إشارة SIGKILL مباشرة. الموت لحظي، والـ kubelet بيسجّله في حقل lastState.terminated.reason باسم OOMKilled. اللي بيحصل بعدها إن الـ Deployment بيعيد إنشاء الـ pod، وبعد دقيقتين بيموت تاني، ومقدّمو الخدمة بيشوفوا 5xx متقطّعة.
قبل ما ندخل في التفاصيل — تخيّل المطعم
افتراض إنك صاحب مطعم وفيه 10 طباخين. كل طلب جديد بيدخل بيقولك "هحتاج 2 طباخين على الأقل عشان أبدأ". ده اسمه request. وانت بترد "ماشي، بس لو احتاجت أكتر من 4، هقفّل الطلب فورًا". ده اسمه limit.
لو الطلب طلب 5 طباخين فجأة، انت بتلغي الطلب على طول. هو ده اللي Kubernetes بيعمله مع الـ pod اللي عدّى الـ memory limit بالظبط. الفرق بس إن الـ pod بيتقتل بدون إنذار، مش بيتقاله "خفف شوية".
الفرق بين requests و limits بدقّة
Kubernetes بيستخدم cgroups v2 (في الـ kernel ≥ 5.8) عشان يعزل الـ resources بين الـ containers. الـ requests هو الحد اللي الـ scheduler بيضمنه للـ pod وقت ما بيقرر يحطّه على أنهي node. الـ limits هو الحد الأعلى اللي لو اتعدّى، الـ kernel بيتدخّل بنفسه.
- CPU limit: لو اتعدّى، Linux بيعمل throttle للعملية (تبطئ، ما تموتش).
- Memory limit: لو اتعدّى، الـ kernel بيقتل العملية فورًا (OOMKilled).
الفرق بين الاتنين مش تفصيلة. CPU throttling بيخلّي تطبيقك بطيء؛ memory kill بيخلّيه ميت. الـ scheduling قرارات بتتاخد بناءً على requests فقط، مش limits. ده معناه إن لو حطيت request: 2Gi على cluster كل node فيه 4Gi، أنت ضيّعت نص قدرة الـ cluster من غير ما تشغّل حاجة.