العوامل والبنيات الموزعة
العوامل والبنيات الموزعة
المتحكم في Jenkins (الذي كان يُعرف سابقاً بـ"master") هو العقل المدبّر لمنصة CI — يجدول المهام، ويدير الحالة، ويقدم واجهة المستخدم. يجب أن لا ينفّذ أعباء البناء أبداً. كل عملية بناء فعلية تجري على عامل (agent)، وهو عملية يتصل بها المتحكم عبر بروتوكول Remoting فوق TCP أو WebSocket، مما يوفر لك العزل الآمن، وقابلية التوسع الأفقي، والقدرة على مطابقة بيئات البناء مع متطلبات كل مهمة.
العوامل الثابتة
العامل الثابت هو آلة دائمة (جهاز VM أو خادم فعلي أو حاوية تعمل باستمرار) مسجّلة في Jenkins تحت Manage Jenkins → Nodes. يتصل بها المتحكم عبر SSH (أو تتصل العاملة بالمتحكم باستخدام agent.jar) وتحافظ على اتصال JNLP/TCP دائم.
يُضبط كل عقدة ثابتة بما يلي:
- التسميات (Labels) — وسوم مفصولة بمسافات مثل
linuxوdockerوgpu-builderوwindows. يختار تعبيرagent { label 'linux && docker' }في الـpipeline العقد المطابقة. - المنفّذون (Executors) — عدد البنيات المتزامنة التي تقبلها العقدة (عادةً 1–2× عدد المعالجات).
- المجلد الجذري — مجلد مساحة العمل؛ استخدم قرص SSD محلياً سريعاً وليس NFS.
- التوافر — دائم الاتصال أو عند الطلب (يُشغَّل عند الحاجة ويُقطع بعد الخمول).
الإطلاق عبر SSH (الطريقة الموصى بها): يفتح Jenkins اتصال SSH إلى مضيف العامل ويشغّل java -jar agent.jar. تأكد من تخزين المفتاح الخاص لـSSH الخاص بالمتحكم في Jenkins Credentials ومن إمكانية الوصول إلى مضيف العامل على المنفذ 22.
العوامل الديناميكية
تُجهَّز العوامل الديناميكية عند الطلب وتُدمَّر بعد اكتمال البناء. أبرز الخيارات المتاحة:
- إضافة Kubernetes — تُنشئ Pod لكل بناء، تُشغّل البناء داخل حاوية، ثم تُدمّره. هذا هو النموذج المعياري لـJenkins في البيئات الحديثة.
- إضافات EC2 / Azure VM / Google Compute — تُجهّز جهاز VM سحابياً، تُجري البناء، ثم تُنهي الجهاز. مفيد حين تحتاج عزلاً كاملاً على مستوى نظام التشغيل.
- إضافة Docker — تُشغّل حاوية لكل بناء على مضيف Docker. أبسط من Kubernetes لكنها مرتبطة بمضيف Docker واحد.
عوامل الحاويات: إضافة Kubernetes
على نطاق واسع، تُشغّل معظم المؤسسات الكبيرة عوامل Jenkins كـPods على Kubernetes. تُنشئ الإضافة PodTemplate — وهو جزء من مواصفات Pod — لكل نوع بيئة بناء. عندما يطلب الـpipeline تسمية مطابقة، تستدعي الإضافة Kubernetes API، يبدأ الـPod، يتصل حاوية jnlp بالمتحكم، وتُنفَّذ خطوات البناء داخل الحاويات المحددة.
يبدو الحد الأدنى من PodTemplate على Kubernetes في pipeline تصريحي كما يلي:
استراتيجية التسمية على نطاق واسع
التسميات هي الطريقة التي يُطابق بها المتحكم المهام مع الطاقة الاستيعابية. يمنع التصنيف المنهجي للتسميات فئة أعطال "يعمل على جهازي فقط":
- نظام التشغيل / المنصة —
linux،windows،macos-arm64 - بيئة التشغيل —
java17،node20،python311 - القدرة —
docker،gpu،large-mem(للبنيات الضخمة أو تعلم الآلة) - البيئة —
prod-deploy(عقد مقيّدة تحمل بيانات اعتماد السحابة)
في الـpipeline يمكن دمج التسميات بعوامل منطقية:
إعادة استخدام PodTemplate عبر واجهة إضافة Kubernetes أو المكتبات المشتركة
تعريف yaml: """...""" داخل كل Jenkinsfile يؤدي إلى انجراف الإعداد. النمط الإنتاجي هو تعريف كائنات PodTemplate الرسمية إما في إعداد إضافة Kubernetes العام (Manage Jenkins → Clouds → Kubernetes → Pod Templates) أو — والأفضل — في مكتبة مشتركة كدالة مساعدة. تستدعي الـpipelines الفردية حينئذٍ agent { label 'java-build' } وتحصل على المواصفة المُدارة مركزياً.
عزل المتحكم: استخدم دائماً agent none
agent none على المستوى الأعلى وعيّن عوامل محددة لكل مرحلة. إذا تعطلت خطوة بناء أو سرّبت ملفات على المتحكم، فقد تُفسد بيانات البناء وتستنزف مساحة القرص وتُعطّل منصة CI بالكامل.
أنماط الأعطال في الإنتاج
- انقطاع العامل أثناء البناء — يتوقف المهمة منتظرةً إعادة الاتصال؛ اضبط
JNLP_TIMEOUTوهيّئ حدود إعادة المحاولة في إضافة السحابة. - تراكم مساحات العمل على العوامل الثابتة — تملأ مساحات العمل القديمة القرص؛ استخدم إضافة Workspace Cleanup ومهمة
cleanWs()ليلية على كل عقدة. - طرد الـPod أثناء البناء — قد يطرد Kubernetes الـPod عند الضغط على الموارد؛ اضبط
priorityClassName: system-cluster-criticalللـpipelines الحرجة وهيّئ PodDisruptionBudgets على المجموعة. - بطء سحب الصور — الصور الكبيرة مثل
maven:3.9(500 ميغابايت+) تُسبب تأخيرات في الإطلاق البارد؛ اسحب الصور مسبقاً على العقد باستخدام DaemonSet أو سجل وسيط يُخزّن الصور مؤقتاً.
الحجم الصحيح للعوامل
اطلب فقط ما يحتاجه البناء فعلاً، لكن حدّد قيوداً لمنع مشكلة الجار المزعج. عيّن مواصفات البناء بـkubectl top pod أثناء تشغيل تمثيلي، ثم اضبط requests عند قيمة P50 المقاسة وlimits عند P99. هذا يمنع كلاً من نقص التوفير (OOMKilled) وزيادة التوفير (هدر في سعة المجموعة).