مشكلة التنظيف "الذكي" لصور الحاويات وحلها في werf

مشكلة التنظيف "الذكي" لصور الحاويات وحلها في werf

تناقش المقالة مشاكل تنظيف الصور التي تتراكم في سجلات الحاويات (Docker Registry ونظائرها) في واقع خطوط أنابيب CI/CD الحديثة للتطبيقات السحابية الأصلية المقدمة إلى Kubernetes. يتم تقديم المعايير الرئيسية لملاءمة الصور والصعوبات الناتجة في أتمتة التنظيف وتوفير المساحة وتلبية احتياجات الفرق. أخيرًا، باستخدام مثال مشروع محدد مفتوح المصدر، سنخبرك كيف يمكن التغلب على هذه الصعوبات.

مقدمة

يمكن أن يتزايد عدد الصور الموجودة في سجل الحاوية بسرعة، مما يؤدي إلى استهلاك مساحة تخزين أكبر وبالتالي زيادة تكلفتها بشكل كبير. للتحكم في النمو المقبول للمساحة المشغولة في السجل أو الحد منه أو الحفاظ عليه، من المقبول:

  1. استخدام عدد محدد من العلامات للصور؛
  2. تنظيف الصور بطريقة ما.


يكون القيد الأول مقبولًا أحيانًا للفرق الصغيرة. إذا كان لدى المطورين ما يكفي من العلامات الدائمة (latest, main, test, boris وما إلى ذلك)، لن يتضخم حجم السجل ولن تضطر إلى التفكير في تنظيفه لفترة طويلة على الإطلاق. بعد كل شيء، يتم مسح جميع الصور غير ذات الصلة، ولم يتبق أي عمل للتنظيف (كل شيء يتم بواسطة جامع القمامة العادي).

ومع ذلك، فإن هذا النهج يحد بشكل كبير من التطوير ونادرًا ما ينطبق على مشاريع CI/CD الحديثة. كان جزءًا لا يتجزأ من التطوير أتمتة، والذي يسمح لك باختبار ونشر وتقديم وظائف جديدة للمستخدمين بشكل أسرع بكثير. على سبيل المثال، في جميع مشاريعنا، يتم إنشاء خط أنابيب CI تلقائيًا مع كل التزام. في ذلك، يتم تجميع الصورة واختبارها ونشرها على دوائر Kubernetes المختلفة لتصحيح الأخطاء والفحوصات المتبقية، وإذا كان كل شيء على ما يرام، فإن التغييرات تصل إلى المستخدم النهائي. وهذا لم يعد علم الصواريخ، ولكنه حدث يومي بالنسبة للكثيرين - على الأرجح بالنسبة لك، لأنك تقرأ هذا المقال.

نظرًا لأن إصلاح الأخطاء وتطوير وظائف جديدة يتم بالتوازي، ويمكن إجراء الإصدارات عدة مرات في اليوم، فمن الواضح أن عملية التطوير مصحوبة بعدد كبير من الالتزامات، مما يعني عدد كبير من الصور في التسجيل. ونتيجة لذلك، تنشأ مسألة تنظيم التنظيف الفعال للسجل، أي. إزالة الصور غير ذات الصلة.

ولكن كيف يمكنك حتى تحديد ما إذا كانت الصورة ذات صلة؟

معايير ملاءمة الصورة

في الغالبية العظمى من الحالات، ستكون المعايير الرئيسية هي:

1. الأول (الأكثر وضوحًا والأكثر أهمية على الإطلاق) هو الصور التي المستخدمة حاليا في Kubernetes. يمكن أن تؤدي إزالة هذه الصور إلى تكاليف كبيرة لتوقف الإنتاج (على سبيل المثال، قد تكون الصور مطلوبة للنسخ المتماثل) أو إبطال جهود الفريق في تصحيح الأخطاء في أي من الحلقات. (ولهذا السبب قمنا بعمل خاص مصدر بروميثيوس، الذي يتتبع عدم وجود مثل هذه الصور في أي مجموعة Kubernetes.)

2. ثانيًا (أقل وضوحًا، ولكنها أيضًا مهمة جدًا وتتعلق مرة أخرى بالاستغلال) - الصور التي مطلوب للتراجع في حالة اكتشاف مشاكل خطيرة في الإصدار الحالي. على سبيل المثال، في حالة Helm، هذه هي الصور المستخدمة في الإصدارات المحفوظة من الإصدار. (بالمناسبة، الحد الأقصى افتراضيًا في Helm هو 256 مراجعة، ولكن من غير المرجح أن يحتاج أي شخص حقًا إلى الحفظ مثل هذا عدد كبير من الإصدارات؟..) ففي نهاية المطاف، نحن، على وجه الخصوص، نقوم بتخزين الإصدارات حتى نتمكن من استخدامها لاحقًا، أي. "التراجع" لهم إذا لزم الأمر.

3. ثالثًا - احتياجات المطور: جميع الصور المتعلقة بعملهم الحالي. على سبيل المثال، إذا كنا نفكر في العلاقات العامة، فمن المنطقي ترك صورة تتوافق مع الالتزام الأخير، على سبيل المثال، الالتزام السابق: بهذه الطريقة يمكن للمطور العودة بسرعة إلى أي مهمة والعمل مع أحدث التغييرات.

4. الرابع - الصور التي تتوافق مع إصدارات تطبيقنا، أي. هي المنتج النهائي: v1.0.0، 20.04.01/XNUMX/XNUMX، سييرا، وما إلى ذلك.

ملحوظة: تمت صياغة المعايير المحددة هنا بناءً على الخبرة في التفاعل مع العشرات من فرق التطوير من شركات مختلفة. ومع ذلك، بالطبع، اعتمادًا على تفاصيل عمليات التطوير والبنية التحتية المستخدمة (على سبيل المثال، لا يتم استخدام Kubernetes)، قد تختلف هذه المعايير.

الأهلية والحلول القائمة

تقدم الخدمات الشائعة مع سجلات الحاويات، كقاعدة عامة، سياسات تنظيف الصور الخاصة بها: حيث يمكنك تحديد الشروط التي بموجبها تتم إزالة العلامة من السجل. ومع ذلك، فإن هذه الشروط مقيدة بمعلمات مثل الأسماء ووقت الإنشاء وعدد العلامات*.

* يعتمد على تطبيقات تسجيل الحاويات المحددة. لقد أخذنا في الاعتبار إمكانيات الحلول التالية: Azure CR وDocker Hub وECR وGCR وGitHub Packages وGitLab Container Registry وHarbour Registry وJFrog Artifactory وQuay.io - اعتبارًا من سبتمبر 2020.

هذه المجموعة من المعلمات كافية للوفاء بالمعيار الرابع - أي اختيار الصور التي تتوافق مع الإصدارات. ومع ذلك، بالنسبة لجميع المعايير الأخرى، يتعين على المرء أن يختار نوعا من الحل الوسط (سياسة أكثر صرامة، أو على العكس من ذلك، أكثر تساهلاً) - اعتماداً على التوقعات والقدرات المالية.

على سبيل المثال، يمكن حل المعيار الثالث - المتعلق باحتياجات المطورين - من خلال تنظيم العمليات داخل الفرق: تسمية محددة للصور، والحفاظ على قوائم السماح الخاصة والاتفاقيات الداخلية. ولكن في النهاية لا يزال يتعين تشغيله آليًا. وإذا كانت إمكانيات الحلول الجاهزة غير كافية، عليك أن تفعل شيئاً خاصاً بك.

الوضع مع المعيارين الأولين مشابه: لا يمكن استيفاءهما دون تلقي البيانات من نظام خارجي - وهو النظام الذي يتم فيه نشر التطبيقات (في حالتنا، Kubernetes).

رسم توضيحي لسير العمل في Git

لنفترض أنك تعمل بشيء مثل هذا في Git:

مشكلة التنظيف "الذكي" لصور الحاويات وحلها في werf

يشير الرمز ذو الرأس في الرسم التخطيطي إلى صور الحاوية التي يتم نشرها حاليًا في Kubernetes لأي مستخدمين (المستخدمين النهائيين، والمختبرين، والمديرين، وما إلى ذلك) أو التي يستخدمها المطورون لتصحيح الأخطاء وأغراض مماثلة.

ماذا يحدث إذا كانت سياسات التنظيف تسمح فقط بالاحتفاظ بالصور (وليس حذفها) بواسطة أسماء العلامات المحددة?

مشكلة التنظيف "الذكي" لصور الحاويات وحلها في werf

ومن الواضح أن مثل هذا السيناريو لن يجعل أي شخص سعيدا.

ما الذي سيتغير إذا سمحت السياسات بعدم حذف الصور؟ وفقًا لفاصل زمني محدد/عدد الالتزامات الأخيرة?

مشكلة التنظيف "الذكي" لصور الحاويات وحلها في werf

أصبحت النتيجة أفضل بكثير، لكنها لا تزال بعيدة عن المثالية. بعد كل شيء، لا يزال لدينا مطورين يحتاجون إلى صور في السجل (أو حتى نشرها في K8s) لتصحيح الأخطاء...

لتلخيص الوضع الحالي للسوق: الوظائف المتاحة في سجلات الحاويات لا توفر مرونة كافية عند التنظيف، والسبب الرئيسي لذلك هو لا توجد وسيلة للتفاعل مع العالم الخارجي. اتضح أن الفرق التي تتطلب مثل هذه المرونة تضطر إلى تنفيذ حذف الصور بشكل مستقل "من الخارج"، باستخدام Docker Registry API (أو واجهة برمجة التطبيقات الأصلية للتنفيذ المقابل).

ومع ذلك، كنا نبحث عن حل عالمي من شأنه أتمتة عملية تنظيف الصور لفرق مختلفة باستخدام سجلات مختلفة...

طريقنا إلى التنظيف الشامل للصورة

من أين تأتي هذه الحاجة؟ الحقيقة هي أننا لسنا مجموعة منفصلة من المطورين، ولكننا فريق يخدم العديد منهم في وقت واحد، مما يساعد على حل مشكلات CI/CD بشكل شامل. والأداة التقنية الرئيسية لهذا هي الأداة المساعدة مفتوحة المصدر werf. وتكمن خصوصيتها في أنها لا تؤدي وظيفة واحدة، ولكنها تصاحب عمليات التسليم المستمرة في جميع المراحل: من التجميع إلى النشر.

يعد نشر الصور إلى السجل* (مباشرة بعد إنشائها) وظيفة واضحة لمثل هذه الأداة المساعدة. وبما أن الصور يتم وضعها هناك للتخزين، إذن - إذا لم تكن مساحة التخزين الخاصة بك غير محدودة - فيجب أن تكون مسؤولاً عن تنظيفها لاحقًا. كيف حققنا النجاح في هذا، وتلبية جميع المعايير المحددة، سيتم مناقشتها بمزيد من التفصيل.

* على الرغم من أن السجلات نفسها قد تكون مختلفة (Docker Registry، وGitLab Container Registry، وHarbour، وما إلى ذلك)، إلا أن مستخدميها يواجهون نفس المشكلات. الحل الشامل في حالتنا لا يعتمد على تنفيذ التسجيل، لأنه يعمل خارج السجلات نفسها ويقدم نفس السلوك للجميع.

على الرغم من أننا نستخدم werf كمثال للتنفيذ، إلا أننا نأمل أن تكون الأساليب المستخدمة مفيدة للفرق الأخرى التي تواجه صعوبات مماثلة.

لذلك انشغلنا خارجي تنفيذ آلية لتنظيف الصور - بدلاً من تلك القدرات المضمنة بالفعل في سجلات الحاويات. كانت الخطوة الأولى هي استخدام Docker Registry API لإنشاء نفس السياسات البدائية لعدد العلامات ووقت إنشائها (المذكور أعلاه). مضاف إليهم قائمة السماح بناءً على الصور المستخدمة في البنية التحتية المنشورة، أي. كوبيرنيتيس. بالنسبة للأخيرة، كان يكفي استخدام Kubernetes API للتكرار عبر جميع الموارد المنشورة والحصول على قائمة بالقيم image.

لقد حل هذا الحل التافه المشكلة الأكثر خطورة (المعيار رقم 1)، لكنه كان مجرد بداية رحلتنا لتحسين آلية التنظيف. الخطوة التالية - والأكثر إثارة للاهتمام - كانت القرار ربط الصور المنشورة بسجل Git.

مخططات وضع العلامات

في البداية، اخترنا نهجًا يجب أن تخزن فيه الصورة النهائية المعلومات الضرورية للتنظيف، وقمنا ببناء العملية على مخططات وضع العلامات. عند نشر صورة، حدد المستخدم خيار وضع علامات محدد (git-branch, git-commit أو git-tag) واستخدم القيمة المقابلة. في أنظمة CI، يتم ضبط هذه القيم تلقائيًا بناءً على متغيرات البيئة. في الحقيقة ارتبطت الصورة النهائية ببدائية Git محددةوتخزين البيانات اللازمة للتنظيف في الملصقات.

أدى هذا النهج إلى مجموعة من السياسات التي سمحت باستخدام Git كمصدر وحيد للحقيقة:

  • عند حذف فرع/علامة في Git، يتم حذف الصور المرتبطة في السجل تلقائيًا.
  • يمكن التحكم في عدد الصور المرتبطة بعلامات Git والالتزامات من خلال عدد العلامات المستخدمة في المخطط المحدد والوقت الذي تم فيه إنشاء الالتزام المرتبط.

وبشكل عام، كان التنفيذ الناتج يلبي احتياجاتنا، ولكن سرعان ما كان ينتظرنا تحدٍ جديد. الحقيقة هي أنه أثناء استخدام مخططات وضع العلامات المستندة إلى عناصر Git الأولية، واجهنا عددًا من أوجه القصور. (بما أن وصفها خارج نطاق هذه المقالة، فيمكن للجميع التعرف على التفاصيل هنا.) لذلك، بعد أن قررنا التحول إلى نهج أكثر كفاءة لوضع العلامات (وضع العلامات على المحتوى)، كان علينا إعادة النظر في تنفيذ تنظيف الصورة.

خوارزمية جديدة

لماذا؟ باستخدام العلامات المستندة إلى المحتوى، يمكن لكل علامة تلبية التزامات متعددة في Git. عند تنظيف الصور، لم يعد بإمكانك أن تتحمل فقط من الالتزام حيث تمت إضافة العلامة الجديدة إلى السجل.

بالنسبة لخوارزمية التنظيف الجديدة، تقرر الابتعاد عن مخططات وضع العلامات والبناء عملية الصورة الفوقية، كل منها يخزن مجموعة من:

  • الالتزام الذي تم تنفيذ النشر عليه (لا يهم ما إذا كانت الصورة قد تمت إضافتها أو تغييرها أو بقائها كما هي في سجل الحاوية)؛
  • ومعرفنا الداخلي المطابق للصورة المجمعة.

وبعبارة أخرى، تم توفيره ربط العلامات المنشورة بالالتزامات في Git.

التكوين النهائي والخوارزمية العامة

عند تكوين التنظيف، أصبح لدى المستخدمين الآن إمكانية الوصول إلى السياسات التي تحدد الصور الحالية. يتم تعريف كل سياسة من هذا القبيل:

  • العديد من المراجع، أي. علامات Git أو فروع Git المستخدمة أثناء المسح؛
  • وحد الصور التي تم البحث عنها لكل مرجع من المجموعة.

للتوضيح، هذا ما بدأ يبدو عليه تكوين السياسة الافتراضية:

cleanup:
  keepPolicies:
  - references:
      tag: /.*/
      limit:
        last: 10
  - references:
      branch: /.*/
      limit:
        last: 10
        in: 168h
        operator: And
    imagesPerReference:
      last: 2
      in: 168h
      operator: And
  - references:  
      branch: /^(main|staging|production)$/
    imagesPerReference:
      last: 10

يحتوي هذا التكوين على ثلاث سياسات تتوافق مع القواعد التالية:

  1. احفظ الصورة لآخر 10 علامات Git (حسب تاريخ إنشاء العلامة).
  2. لا تقم بحفظ أكثر من صورتين منشورتين في الأسبوع الماضي لما لا يزيد عن 2 مواضيع مع نشاط في الأسبوع الماضي.
  3. حفظ 10 صور للفروع main, staging и production.

تتلخص الخوارزمية النهائية في الخطوات التالية:

  • استرجاع البيانات من سجل الحاوية.
  • باستثناء الصور المستخدمة في Kubernetes، لأن لقد قمنا بالفعل باختيارهم مسبقًا من خلال استطلاع K8s API.
  • مسح سجل Git واستبعاد الصور بناءً على السياسات المحددة.
  • إزالة الصور المتبقية.

وبالعودة إلى الرسم التوضيحي، هذا ما يحدث مع werf:

مشكلة التنظيف "الذكي" لصور الحاويات وحلها في werf

ومع ذلك، حتى إذا كنت لا تستخدم werf، فيمكن تطبيق أسلوب مماثل للتنظيف المتقدم للصور - في تطبيق أو آخر (وفقًا للأسلوب المفضل لوضع علامات على الصور) - على الأنظمة/الأدوات المساعدة الأخرى. للقيام بذلك، يكفي أن تتذكر المشكلات التي تنشأ والعثور على تلك الفرص في مجموعتك التي تسمح لك بدمج حلها بسلاسة قدر الإمكان. نأمل أن يساعدك المسار الذي سلكناه في النظر إلى حالتك الخاصة بتفاصيل وأفكار جديدة.

اختتام

  • عاجلاً أم آجلاً، تواجه معظم الفرق مشكلة تجاوز سعة التسجيل.
  • عند البحث عن حلول، من الضروري أولاً تحديد معايير ملاءمة الصورة.
  • تتيح لك الأدوات التي تقدمها خدمات تسجيل الحاويات الشهيرة تنظيم عملية تنظيف بسيطة جدًا لا تأخذ في الاعتبار "العالم الخارجي": الصور المستخدمة في Kubernetes وخصائص سير عمل الفريق.
  • يجب أن تتمتع الخوارزمية المرنة والفعالة بفهم لعمليات CI/CD ولا تعمل فقط مع بيانات صورة Docker.

PS

اقرأ أيضًا على مدونتنا:

المصدر: www.habr.com

إضافة تعليق