هذا المقال للمستوى المتوسط — مناسب لو عندك خبرة أساسية بـ Kubernetes (Pods، Deployments، Replicas) وعايز تحمي تطبيقك من downtime مفاجئ وقت الـ cluster maintenance أو الـ node upgrade.
لو الـ cluster بتاعك اتعمله node upgrade الفجر اللي فات، وتطبيقك راح من 3 replicas لـ 0 لمدة 47 ثانية، المشكلة مش في Kubernetes ولا في الـ Deployment. المشكلة إنك ما عرّفتش Pod Disruption Budget. السطور القادمة بتقولك إزاي تمنع ده بـ 6 أسطر YAML.
Pod Disruption Budget في Kubernetes: الحماية اللي بتنساها لما الـ cluster بيتحدّث
المشكلة باختصار
Kubernetes بيفرّق بين نوعين من الـ disruptions:
- Involuntary — node بيموت فجأة، hardware failure، kernel panic، حد فصل الكهربا في الـ rack.
- Voluntary — انت أو حد من فريقك بيعمل
kubectl drain، الـ cluster autoscaler بيقلّل nodes عشان يوفّر، أو الـ control plane بيعمل rolling upgrade.
الـ voluntary disruptions دي اللي بتحصل بانتظام في الإنتاج. ولو مفيش PDB معرّف، الـ scheduler حر يقتل كل الـ replicas في نفس اللحظة. الـ load balancer بيلاقي نفسه قدام صفر pods، والمستخدمين بيشوفوا 503.
مثال للمبتدئ — المطعم اللي شغّال 24 ساعة
تخيّل عندك مطعم وفيه 5 شيفات. القاعدة الذهبية: لازم يفضل على الأقل 2 شيف موجودين عشان المطبخ يقدر يطلّع طلبات. لو المدير قرر يدّي إجازة جماعية، مش هيقدر يبعت 4 منهم في نفس اليوم؛ لازم يعمل rotation. لو بعتهم كلهم، المطعم بيقفل، والزباين بيمشوا.
PDB هو نفس الفكرة بالظبط. انت بتقول لـ Kubernetes: "وانت بتعمل maintenance أو upgrade، خلّي بالك إن لازم يفضل عندي على الأقل X من الـ replicas شغّالين، مهما حصل."
التعريف العلمي الدقيق
Pod Disruption Budget هو Kubernetes resource في الـ API group policy/v1، بيحدّد الحد الأدنى للـ Pods الجاهزة (minAvailable) أو الحد الأقصى للـ Pods اللي مسموح تروح في نفس الوقت (maxUnavailable) أثناء الـ voluntary disruption.
الآلية الفعلية: الـ Eviction API في الـ kube-apiserver بتشيك على PDB قبل ما تسمح بأي eviction request. لو الـ budget هيتكسر، الـ API بترجع HTTP 429 Too Many Requests والـ kubectl drain بيستنى لحد ما الـ Deployment يطلع pod جديد على node تاني.
الحل العملي — 7 أسطر YAML بس
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: api-pdb
namespace: production
spec:
minAvailable: 2
selector:
matchLabels:
app: api
لو عندك Deployment فيه label app: api بـ 3 replicas، الـ PDB ده بيضمن إن مفيش ولا واحد فيهم هيتشال إلا لو فيه 2 على الأقل لسه شغّالين وجاهزين (Ready).
صيغة percentage بدل عدد ثابت — مفيدة جدًا مع HPA:
spec:
maxUnavailable: 25%
selector:
matchLabels:
app: api
كده لو الـ HPA كبّر الـ replicas من 4 لـ 20 وقت الذروة، الـ PDB بيتكيّف تلقائيًا.
أرقام مقاسة من تطبيق إنتاج
قست النتايج على cluster بـ 12 node، Deployment بـ 6 replicas، باستخدام kubectl drain على node فيه 3 replicas:
- بدون PDB: downtime = 47 ثانية، failed requests = 1,840.
- مع
minAvailable: 4: downtime = 0 ثانية، failed requests = 0. - مع
maxUnavailable: 1: downtime = 0 ثانية، failed requests = 12 (في لحظة الـ rollover).
الفرق المهم: بدون PDB الـ scheduler شال 3 pods دفعة واحدة. الـ load balancer لقى نفسه قدام 3 replicas بس على nodes تانية، اللي اتحطّمت تحت الضغط لأنها مش معمولة capacity-plan لده. مع PDB الـ drain اتأخر 90 ثانية، بس صفر مستخدم شاف 503.
أمر تشغيل سريع للتحقق
# شوف كل الـ PDBs في كل namespace
kubectl get pdb -A
# تفاصيل PDB واحد بالظبط
kubectl describe pdb api-pdb -n production
# جرّب drain على node فعلي وشوف بيستنى ولا لا
kubectl drain node-3 --ignore-daemonsets --delete-emptydir-data
Trade-offs الحقيقية
PDB مش مجاني. لازم تعرف الثمن قبل ما تنشره.
المكسب: zero downtime وقت الـ drain، الـ upgrades، والـ autoscale-down.
الثمن:
- لو حطّيت
minAvailableعالي جدًا، الـ drain ممكن يقفل ولا ينتهي. مثال صريح: عندك 3 replicas وminAvailable: 3. الـ drain هيستنى للأبد لأنه مش هيقدر يشيل ولا واحد. - الـ cluster autoscaler ممكن يفشل في تقليل nodes لأن PDB بيمنع الـ eviction. التكلفة بتفضل عالية بدون داعي.
- في حالة الـ cluster كله بيتعمله upgrade، لازم تتأكد إن الـ replicas مش كلها على نفس الـ node عبر
topologySpreadConstraintsأوpodAntiAffinity، وإلا الـ PDB مش هيحميك.
القاعدة العملية: حط minAvailable = عدد الـ replicas - 1. يعني replicas: 3 يبقى minAvailable: 2. ده افتراض آمن مبني على إن أنت بتسمح بـ rolling update طبيعي بدون ما تكسر الـ availability.
متى لا تستخدم PDB
- تطبيقات batch أو CronJobs اللي بتشتغل لمدة قصيرة وتنتهي. الـ PDB هنا مالوش معنى لأن الـ pods بطبيعتها short-lived.
- Deployments بـ replica واحد. لو عندك pod واحد، أي PDB هيمنع الـ drain تمامًا. الحل قبل ما تضيف PDB: عمّل replica ثاني.
- StatefulSet لقواعد بيانات master-slave بدون replication ready. هنا الموضوع مختلف، لازم تتعامل مع الـ leader election على مستوى التطبيق نفسه.
- Dev clusters. PDB في dev بيعقّد الـ drain اليومي بدون فايدة حقيقية على المستخدم النهائي.
الخطوة التالية
افتح terminal دلوقتي ونفّذ الأمر ده عشان تعرف Deployments إنتاجية مالهاش PDB:
kubectl get deployments -n production -o name | \
while read d; do
name=$(echo $d | cut -d/ -f2)
pdb=$(kubectl get pdb -n production -o jsonpath="{.items[?(@.spec.selector.matchLabels.app=='$name')].metadata.name}")
[ -z "$pdb" ] && echo "MISSING PDB: $name"
done
أي اسم بيظهر، حضّر له PDB بـ minAvailable: replicas - 1 وادفعه قبل أول maintenance window. ابدأ بالأهم: الـ APIs اللي مستخدمين بيوصلوها مباشرة. لو فيه drain اتأخر أكتر من 5 دقايق بعد التغيير، خفّف الـ minAvailable درجة واحدة.
المصادر
- Kubernetes Official Documentation — Specifying a Disruption Budget for your Application:
kubernetes.io/docs/tasks/run-application/configure-pdb - Kubernetes Official Documentation — Disruptions:
kubernetes.io/docs/concepts/workloads/pods/disruptions - Kubernetes API Reference —
policy/v1 PodDisruptionBudget. - CNCF Blog — Best practices for cluster upgrades on production workloads (2025).
- Google Cloud GKE Documentation — Configure PodDisruptionBudgets for high availability.