حدود الموارد ومجموعات التحكم
حدود الموارد ومجموعات التحكم
الحاوية في جوهرها عبارة عن عملية — أو شجرة من العمليات — تعمل على نواة المضيف. وبدون حدود صريحة، يمكن لحاوية واحدة مفلتة من السيطرة أن تستهلك كل دورات المعالج وكل بايت من ذاكرة الوصول العشوائي على المضيف، مما يتسبب في تعطل كل الحاويات الأخرى والعقدة بأكملها. مجموعات التحكم في لينكس (cgroups) هي آلية النواة التي تمنع ذلك: إذ تفرض حدوداً صارمة على المعالج والذاكرة والإدخال/الإخراج وعدد العمليات لكل مجموعة عمليات. كلٌّ من Docker وKubernetes يبنيان نموذجَي تحديد الموارد الخاصَّيْن بهما فوق cgroups.
كيف تعمل مجموعات التحكم داخلياً
عند بدء Docker تشغيل حاوية، ينشئ الخادم الخفي تسلسلاً هرمياً لـ cgroup تحت /sys/fs/cgroup/ ويضع كل عملية حاوية بداخله. تفرض النواة بعد ذلك الحدود التي حددتها على مستوى هذا التسلسل الهرمي — بصرف النظر عن مدى عدوانية الحاوية في محاولة الإفلات. مع الإصدار الثاني من cgroups (الافتراضي على Linux 5.2+ وجميع التوزيعات الحديثة)، يتوحد التسلسل الهرمي في شجرة واحدة ويكون المحاسبة أكثر دقة، لا سيما للذاكرة.
memory.max محل memory.limit_in_bytes من v1، ويُتحكم في المعالج عبر cpu.max بدلاً من cpu.cfs_quota_us. تظل علامات واجهة سطر الأوامر لـ Docker وkubectl كما هي بصرف النظر عن الإصدار — إذ تترجم المحرك تلقائياً.
حدود الذاكرة وسلوك OOM
الذاكرة هي أكثر الموارد خطورة عند إهمالها. عندما تتجاوز حاوية حد ذاكرتها، يُنهي قاتل OOM (نفاد الذاكرة) في النواة عملية داخل cgroup. في Docker، يتجلى ذلك بخروج الحاوية بحالة 137 (SIGKILL من النواة). بدون حد، قد يختار قاتل OOM أي عملية على المضيف — بما في ذلك خادم Docker الخفي أو عملية في حاوية غير ذات صلة تماماً.
--memory-swap مساوياً لـ --memory. هذا يعطل المبادلة تماماً، وهو ما يبدو آمناً لكنه يتسبب في قتل OOM عند حد الذاكرة دون أي هبوط ناعم. في الإنتاج، إما أن تسمح بقدر صغير من المبادلة (1.5 إلى 2 ضعف حد الذاكرة)، أو تعطل المبادلة على مستوى المضيف بالكامل لأعباء العمل الحساسة لزمن الاستجابة، والاعتماد على قتل OOM السريع كقاطع دائرة.
يمكنك أيضاً تهيئة ما يحدث قبل قتل OOM باستخدام --oom-score-adj. يصنّف قاتل OOM في النواة كل عملية بين -1000 (لا تقتل أبداً) و+1000 (اقتل أولاً). يجعل الضبط على درجة عالية لحاويتك منها الضحية المفضلة، مما يحمي العمليات على مستوى المضيف.
حدود المعالج: الحصص والأوزان والفترات
يعمل تحديد المعالج بشكل مختلف عن الذاكرة لأن وقت المعالج قابل للضغط — يتم تبطيء الحاوية التي تطلب أكثر من حصتها، لا قتلها. يكشف Docker عن مفترقَين مستقلَّين:
--cpus(أو--cpu-quota+--cpu-period) — يضع سقفاً صارماً.--cpus=1.5تعني أن الحاوية قد تستخدم ما يصل إلى 1.5 ثانية-معالج في الثانية، بصرف النظر عن الطاقة المتاحة. يُنفَّذ كحصة جدول CFS (المُجدوِّل العادل تماماً).--cpu-shares— يضع وزناً نسبياً (الافتراضي 1024). يسري فقط عند التنافس على المعالج. تحصل الحاوية ذات 2048 حصة على ضعف وقت المعالج مقارنة بحاوية ذات 1024 حصة عندما تكون كلتاهما مشغولتين. عندما يكون المضيف خاملاً، لا تهم الحصص — يمكن للحاوية ذات الحصص المنخفضة الانطلاق بحرية.
ulimits: واصفات الملفات وعداد العمليات
بعيداً عن المعالج والذاكرة، ثمة موردان آخران يتسببان في أعطال إنتاج خفية: واصفات الملفات المفتوحة وعداد العمليات/الخيوط. كلاهما يُتحكم بهما عبر إعدادات ulimit التي يرثها Docker من الإعدادات الافتراضية للخادم الخفي، ويمكن تجاوزها لكل حاوية على حدة.
يمكن لخدمة عالية التزامن (قاعدة بيانات، خادم ويب، وسيط رسائل) استنفاد حدود واصفات الملفات تحت الحمل، مما يتسبب في أخطاء "عدد كبير جداً من الملفات المفتوحة" الغامضة قبل نفاد المعالج أو الذاكرة بوقت طويل. وبالمثل، يمكن للعمليات الفروعية الشرهة أو JVM يسرب الخيوط أن تستنفد جميع معرفات العمليات على المضيف، مما يجعل العقدة غير قادرة على بدء أي عملية جديدة — بما في ذلك نصوص الاسترداد.
طلبات الموارد وحدودها في Kubernetes
في Kubernetes، يُهيَّأ المعالج والذاكرة على مستوى الحاوية داخل مواصفة Pod. ثمة مفهومان متميزان: الطلبات (ضمان المُجدوِّل — يجب أن تمتلك العقدة هذا القدر من الطاقة الحرة) والحدود (سقف cgroup — لا يمكن للحاوية تجاوزه). ضبط الحدود فقط دون الطلبات خطأ شائع يؤدي إلى قيام المُجدوِّل بوضع عدد كبير جداً من الحجيرات على عقدة واحدة.
container_cpu_cfs_throttled_seconds_total) — التبطيء الشديد مضر بالقدر ذاته للخدمات الحساسة لزمن الاستجابة.
التحقق من الحدود ومراقبتها في الإنتاج
ضبط الحدود هو نصف العمل فقط. يجب أيضاً التحقق من تطبيقها والتنبيه عندما تقترب الحاويات منها. الإشارات الرئيسية للمراقبة:
- نسبة استخدام الذاكرة — أنشئ تنبيهاً عند 80% من الحد. عند 100% يتم القتل دون أي تحذير.
- عداد قتل OOM —
container_oom_events_totalفي Prometheus؛ أي قيمة فوق الصفر تعني حادثة إنتاج. - نسبة تبطيء المعالج —
container_cpu_cfs_throttled_periods_total / container_cpu_cfs_periods_total؛ فوق 25% يشير إلى أن حد المعالج منخفض جداً. - استخدام واصفات الملفات — قارن عدد
/proc/<pid>/fdبالـ ulimit للخدمات طويلة الأمد.
LimitRange في كل مساحة اسم — فهو يحقن تلقائياً الطلبات والحدود الافتراضية لأي حجيرة تحذفها، حتى لا يتمكن نشر مهيأ بشكل خاطئ من تجاوز السياسة.