أين تذهب ملفات البناء؟ القطعة المفقودة بين الكود والإنتاج
لقد انتهيت للتو من بناء تطبيقك. نجحت عملية البناء، واجتازت الاختبارات، وأصبح لديك ملف بناء (artifact) جديد لامع في مجلد على حاسوبك المحمول. ماذا الآن؟
إذا كنت مثل معظم الفرق التي تنشئ خط أنابيبها الأول، فإن الخطوة التالية تبدو واضحة: انشره. ولكن هناك مشكلة مخفية في العلن. ملف البناء الموجود على حاسوبك المحمول لا فائدة منه لخادم الإنتاج الموجود في مركز بيانات أو منطقة سحابية. لا يمكنه الوصول إلى مجلدك المحلي وسحب الملف. حتى إذا تم تشغيل البناء على جهاز CI مخصص، فإن هدف النشر لا يزال غير قادر على الوصول إلى الملفات الموجودة على القرص المحلي لذلك الجهاز.
هنا تتعثر معظم تصميمات خطوط الأنابيب في أول عقبة حقيقية. أنت بحاجة إلى مكان لوضع ملف البناء حيث يمكن لكل من عملية البناء وهدف النشر الوصول إليه.
مشكلة التخزين المشترك
فكر فيما يحدث عندما تنتهي من طهي وجبة لحفلة. لا تترك الطعام في مطبخك وتتوقع من الضيوف الدخول وتقديم الطعام لأنفسهم من على موقدك. أنت تضع الطعام على طاولة حيث يمكن للجميع الوصول إليه.
تعمل ملفات البناء بنفس الطريقة. عملية البناء تنشئ ملف البناء. عملية النشر تحتاج إلى استرجاعه. قد تعمل هاتان العمليتان على أجهزة مختلفة، في شبكات مختلفة، وفي أوقات مختلفة. إنهما بحاجة إلى موقع مشترك يمكن لكليهما الوصول إليه عبر الشبكة.
هذا الموقع المشترك يسمى سجل القطع البرمجية (Artifact Registry) أو مستودع القطع البرمجية (Artifact Repository). وظيفته بسيطة: تخزين ملفات البناء وتوفير طريقة لجلبها. في كل مرة ينتهي فيها البناء، يدفع ملف البناء إلى هذا السجل. لاحقًا، عندما يبدأ النشر، يسحب خادم الهدف ملف البناء من السجل ويشغله.
يوضح الرسم البياني التالي التدفق الأساسي:
إليك كيفية دفع ملف بناء بعد البناء وسحبه على هدف النشر:
# على جهاز البناء: دفع ملف البناء إلى السجل
curl -X POST \
-F "file=@myapp-v1.2.3.jar" \
https://registry.example.com/upload
# على هدف النشر: سحب ملف البناء من السجل
curl -O https://registry.example.com/artifacts/myapp-v1.2.3.jar
أكثر من مجرد خادم ملفات
السجل يفعل أكثر من مجرد الاحتفاظ بالملفات. فهو يحتفظ أيضًا ببيانات وصفية (metadata) حول كل ملف بناء: رقم الإصدار، الطابع الزمني للإنشاء، وغالبًا ما يكون تجزئة commit Git التي أنتجته. تصبح هذه البيانات الوصفية حاسمة عندما يحدث خطأ ما في الإنتاج.
تخيل أنك تنشر الإصدار 2.3.1 ويبدأ المستخدمون في رؤية أخطاء. تحتاج إلى معرفة تغييرات الكود التي دخلت في ملف البناء هذا بالضبط. بدون بيانات وصفية تربط ملف البناء بمصدر commit، فأنت تخمن. معها، يمكنك التحقق من الفرق (diff)، وتحديد المشكلة، واتخاذ قرار بالتراجع أو الإصلاح للأمام.
تدعم بعض السجلات أيضًا التصنيفات (labels) أو العلامات (tags). يمكنك وضع علامة على ملف بناء كـ "staging-validated" بعد اجتيازه اختبارات التكامل، أو "production-ready" بعد الموافقة اليدوية. تساعد هذه العلامات في أتمتة ملفات البناء التي يتم نشرها في أي بيئة.
فخ الاتصال
إليك خطأ يقع فيه العديد من الفرق: يقومون بإعداد سجل في السحابة، ولكن خوادم الإنتاج الخاصة بهم تعمل في شبكة خاصة لا يمكنها الوصول إلى الإنترنت العام. ينجح البناء في دفع ملفات البناء، ولكن عندما يحاول النشر السحب، يفشل مع انتهاء مهلة الاتصال.
يجب أن يكون السجل قابلاً للوصول من كل خادم يحتاج إلى النشر. إذا كانت بيئة الإنتاج الخاصة بك معزولة، فيجب أن يكون السجل داخل نفس تلك الشبكة، أو تحتاج إلى آلية لمزامنة ملفات البناء عبر حدود الشبكة. تدير بعض الفرق وكيلًا محليًا أو مرآة (mirror) تخزن مؤقتًا ملفات البناء من سجل مركزي. يستخدم آخرون سجلًا يدعم نقاط نهاية الشبكة الخاصة.
يبدو هذا واضحًا عندما تقرأه، ولكن من السهل التغاضي عنه عندما تركز على جعل خط الأنابيب يعمل من البداية إلى النهاية. تحقق من الاتصال قبل بناء عملية النشر بأكملها حول سجل لا تستطيع خوادمك الوصول إليه.
أهمية الثبات (Immutability)
يمنع السجل الجيد تعديل ملفات البناء بعد تخزينها. هذه الخاصية تسمى الثبات (Immutability). وهذا يعني أن ملف البناء الذي تخزنه اليوم سيكون مطابقًا لملف البناء الذي تسترجعها بعد ستة أشهر.
لماذا هذا مهم؟ بدون الثبات، لا يمكنك الوثوق بما تنشره. يمكن لشخص ما تعديل ملف بناء بعد اجتيازه الاختبارات. يمكن أن يظهر خطأ تم اكتشافه في بيئة الاختبار (staging) مرة أخرى في الإنتاج لأن ملف البناء تغير بين البيئات. يصبح تصحيح الأخطاء كابوسًا لأنك لست متأكدًا أبدًا مما إذا كان ملف البناء الذي يعمل في الإنتاج يطابق ما تم اختباره.
يفرض الثبات سير عمل نظيفًا: كل تغيير ينتج ملف بناء جديدًا بإصدار جديد. لا يوجد "تحديث في المكان" لملفات البناء. إذا كنت بحاجة إلى إصلاح شيء ما، فأنت تعيد البناء وتنشئ إصدارًا جديدًا. هذا الانضباط يجعل عمليات النشر قابلة للتنبؤ وعمليات التراجع (rollbacks) مباشرة.
فصل البناء عن النشر
مع وجود السجل، يصبح البناء والنشر عمليتين منفصلتين يمكن تشغيلهما بشكل مستقل. ينتهي البناء، ويدفع ملف البناء، ويمضي قدمًا. يمكن أن يحدث النشر بعد دقائق أو ساعات أو أيام. يظل ملف البناء بأمان في السجل، في انتظار استرجاعه.
هذا الفصل قوي. يمكنك بناء واختبار ملف بناء في الصباح، ومراجعته من قبل مهندس أول في فترة ما بعد الظهر، ونشره إلى الإنتاج في الليل عندما تكون حركة المرور منخفضة. تحدث كل خطوة في جدولها الزمني الخاص، لكنها جميعًا تشير إلى نفس ملف البناء الثابت.
كما يعني أيضًا أنه يمكنك إعادة بناء وإعادة نشر نفس ملف البناء إلى بيئات متعددة. ملف البناء الذي اجتاز اختبارات بيئة الاختبار (staging) هو نفس ملف البناء تمامًا الذي يذهب إلى الإنتاج. لا إعادة ترجمة، ولا بنيات خاصة بالبيئة، ولا مفاجآت من نوع "كان يعمل على جهازي".
قائمة تحقق عملية سريعة
عند إعداد سجل القطع البرمجية الخاص بك، تحقق من هذه النقاط:
- قابلية الوصول (Accessibility): هل يمكن لكل خادم يحتاج إلى النشر الوصول إلى السجل عبر الشبكة؟
- الثبات (Immutability): هل يمنع السجل تعديل ملفات البناء المخزنة؟
- البيانات الوصفية (Metadata): هل يحمل كل ملف بناء معلومات الإصدار والطابع الزمني ومصدر commit؟
- الاحتفاظ (Retention): كم من الوقت تحتفظ بملفات البناء القديمة؟ هل لديك سياسة تنظيف؟
- المصادقة (Authentication): من يمكنه دفع ملفات البناء؟ من يمكنه سحبها؟ هل يتم تدوير بيانات الاعتماد؟
الخلاصة
يحتاج مخرجات البناء الخاصة بك إلى منزل يمكن لكل من عملية البناء وأهداف النشر الوصول إليه. يوفر سجل القطع البرمجية هذا التخزين المشترك، ويحتفظ بالبيانات الوصفية لإمكانية التتبع، ويفرض الثبات حتى تتمكن من الوثوق بما تنشره، ويفصل البناء عن النشر بحيث يمكن لكل خطوة أن تحدث في جدولها الزمني الخاص. بدونه، يكون خط الأنابيب الخاص بك مجرد بناء ينتهي بملف يجلس على جهاز لا يمكن لأحد الوصول إليه.