نموذج GitOps
نموذج GitOps
GitOps هو إطار تشغيلي يأخذ أفضل ممارسات DevOps — التحكم بالإصدارات، التعاون، و CI/CD — ويطبّقها مباشرةً على تسليم البنية التحتية والتطبيقات. المبدأ الجوهري بسيط في ظاهره لكن عميق الأثر: Git هو المصدر الوحيد للحقيقة لكامل الحالة المطلوبة للنظام. ما لم يكن موجوداً في Git، فهو غير موجود أصلاً.
في Google وMeta وكل بيئة عمل cloud-native كبرى، البنية التحتية التي تشغّل الإنتاج موصوفة كـ code في مستودعات. الكلاستر الذي يعمل في بيئة الإنتاج ليس نتيجة شخص يشغّل kubectl apply من حاسوبه الشخصي. إنه نتيجة حلقة مصالحة مستمرة تقرأ Git وتجعل الكلاستر الحي يطابق ما تقوله Git. هذا هو نموذج GitOps.
نموذجا النشر: Push مقابل Pull
لفهم سبب أهمية GitOps، يجب أن تشعر بمشاكل البديل — نموذج النشر الكلاسيكي المبني على الدفع (Push) المستخدم في تدفقات CI/CD التقليدية.
في نموذج Push، يحتفظ نظام CI (Jenkins، GitHub Actions، أو سكريبت Shell) ببيانات اعتماد النشر ويتواصل بشكل نشط مع الكلاستر. بعد نجاح البناء، تشغّل الـ pipeline أمر kubectl apply أو helm upgrade، دافعةً المانيفستات الجديدة مباشرةً إلى الكلاستر. هذا يعمل، لكنه يخلق مجموعة من المشاكل البنيوية:
- سطح تسرب بيانات الاعتماد: عداء CI يحتاج إلى صلاحيات واسعة على الكلاستر — غالباً cluster-admin — يمكن سرقتها، أو تدويرها بشكل خاطئ، أو تحديد نطاقها بصورة غلط.
- الانجراف غير مرئي: يمكن لشخص لديه وصول إلى
kubectlتغيير عدد نسخ الـ Deployment مباشرةً على الكلاستر. نظام CI لن يدري بذلك. Git والواقع ينجرفان في صمت. - قابلية التدقيق هشة: يجب إعادة بناء ما تم نشره من خلال البحث في سجلات الـ pipeline ومقارنة التوقيتات. لا يوجد سجل موحد للحالة المطلوبة عبر الزمن.
- التعافي من الكوارث بطيء: إعادة بناء كلاستر من الصفر يتطلب إعادة تشغيل الـ pipelines بالترتيب الصحيح، مع أمل أن تكون جميع التبعيات لا تزال متاحة.
المصالحة المبنية على السحب (Pull): الآلية الجوهرية
في نموذج GitOps المبني على السحب، يعمل عميل مخصص — ArgoCD أو Flux — داخل الكلاستر. يقوم باستمرار باستطلاع (أو تلقي إشعارات webhook من) مستودع Git، ومقارنة الحالة المُعلنة في Git مع الحالة الفعلية للكلاستر. عندما يكتشف فرقاً (يُسمى انجراف/drift)، يطبّق الإجراءات التصحيحية بنفسه. لا يحتاج مشغّل الكلاستر أبداً للتدخل من الخارج.
لهذا الانعكاس عواقب عملية هائلة:
- لا بيانات اعتماد صادرة: الكلاستر لا يكشف بيانات الاعتماد للـ CI. يستخدم العميل حسابات الخدمة داخل الكلاستر. يحتاج الـ pipeline فقط إلى صلاحية الكتابة على Git — وليس على الكلاستر.
- تصحيح تلقائي للانجراف: إذا شغّل مهندس
kubectl edit deployment/api --replicas=5في الإنتاج الساعة 2 صباحاً خلال حادثة، سيلاحظ عميل GitOps ذلك ويعود للقيمة الموجودة في Git خلال دقائق — ما لم تُعلّمه صراحةً كاستثناء. - تاريخ Git هو سجل التدقيق: كل تغيير على الإنتاج هو
git commit. أوامرgit logوgit blameومراجعات Pull Request هي الآن نظام إدارة التغييرات لديك. - التعافي من الكوارث هو مجرد
git clone: لإعادة بناء كلاستر من الصفر، اضبط عميلاً جديداً ليشير إلى نفس المستودع. الحالة المطلوبة بالكامل موجودة هناك.
- تصريحي (Declarative): يجب وصف النظام بأكمله بشكل تصريحي. تقول ماذا تريد، لا كيف تحققه.
- موثّق وغير قابل للتغيير (Versioned & Immutable): الحالة المطلوبة مخزّنة في نظام تحكم بالإصدارات يفرض عدم القابلية للتغيير ويحتفظ بتاريخ كامل.
- مسحوب تلقائياً (Pulled automatically): تسحب عملاء البرمجيات تلقائياً تصريحات الحالة المطلوبة من المصدر.
- مُصالَح باستمرار (Continuously reconciled): يراقب العملاء باستمرار حالة النظام الفعلية ويحاولون تطبيق الحالة المطلوبة.
ما الذي يدخل في مستودع Git
يحتوي مستودع GitOps على الحالة المطلوبة للنظام — مانيفستات Kubernetes، قيم Helm charts، طبقات Kustomize، أو مزيج من الثلاثة. لا يحتوي على الكود المصدري للتطبيق (ذاك يبقى في مستودع التطبيق). هذا الفصل مقصود: تريد أن تكون قادراً على تحديث عنوان image الذي يُنشر دون تشغيل بناء تطبيق كامل.
هيكل بداية بسيط يبدو هكذا:
مانيفست Kubernetes Deployment ملموس في المجلد الأساسي:
main في مستودع الإعدادات في الإنتاج دون بوابة مراجعة.
المصالحة في الممارسة العملية
عندما تحتفظ بتغيير في مستودع الإعدادات، إليك تسلسل الأحداث في نظام مبني على السحب:
- تفتح PR تُغيّر فيه
image: ghcr.io/myorg/api-service:v1.4.2إلى:v1.5.0. يوافق عليها زميل ويدمجها. - عميل GitOps (الذي يعمل داخل الكلاستر) يكتشف الـ commit الجديد — إما بالاستطلاع على فترة زمنية (الافتراضي: 3 دقائق في ArgoCD، دقيقة واحدة في Flux) أو عبر Git webhook يُشغّل مزامنة فورية.
- يحسب العميل الفرق بين ما هو في Git وما يعمل حالياً في الكلاستر.
- يطبّق العميل
kubectl apply(أو عملية Helm/Kustomize المكافئة) داخلياً، مستهدفاً فقط الموارد التي تغيّرت. - Kubernetes ينفّذ التحديث المتدرج. يتابع العميل وينبّه بحالة الصحة في لوحة التحكم.
kubectl اليدوية في نفس الكلاستر. إذا دمجت فريقك مع عميل GitOps لكن المهندسين استمروا في تطبيق المانيفستات يدوياً، ستواجه صراعات مصالحة مستمرة حيث يتراجع العميل عن التغييرات اليدوية. أرسِّ هذه القاعدة من اليوم الأول: كل التغييرات على الكلاستر تمر عبر Git. استخدم RBAC لإزالة صلاحيات kubectl apply المباشرة من المستخدمين البشريين في الإنتاج — أجبر التغييرات على المرور عبر عملية PR.
لماذا GitOps هو المعيار على نطاق واسع
يمكن أن تعمل الـ pipelines المبنية على Push للفرق الصغيرة التي لديها كلاستر واحد وبيئة واحدة. تنهار عندما يكون لديك 50 microservice و5 بيئات ومنظمة هندسية من 200 شخص. يحل GitOps مشكلة التنسيق: الحالة المطلوبة لكل فريق في مكان واحد، مُصالَحة باستمرار، مع تاريخ كامل لكل تغيير ومن وافق عليه. متطلبات الامتثال والتدقيق التي اعتادت تتطلب أدوات مخصصة تصبح بسيطة للغاية — فقط اعرض git log.
الدرس التالي يغطي كيفية تصميم هيكل مستودع Git نفسه — mono-repo مقابل multi-repo، اتفاقيات المجلدات، وإستراتيجيات التفريع التي تعمل مع GitOps على نطاق منظمة هندسية حقيقية.