فكر جيدًا قبل استخدام Docker-in-Docker لـ CI أو بيئة الاختبار

فكر جيدًا قبل استخدام Docker-in-Docker لـ CI أو بيئة الاختبار

Docker-in-Docker هي بيئة Docker افتراضية تعمل داخل الحاوية نفسها لإنشاء صور الحاوية. كان الغرض الرئيسي من إنشاء Docker-in-Docker هو المساعدة في تطوير Docker نفسه. يستخدمه العديد من الأشخاص لتشغيل Jenkins CI. يبدو هذا طبيعيًا في البداية، ولكن بعد ذلك تظهر مشكلات يمكن تجنبها عن طريق تثبيت Docker في حاوية Jenkins CI. يخبرك هذا المقال بكيفية القيام بذلك. إذا كنت مهتمًا بالحل النهائي دون تفاصيل، فما عليك سوى قراءة القسم الأخير من المقالة “حل المشكلة”.

فكر جيدًا قبل استخدام Docker-in-Docker لـ CI أو بيئة الاختبار

عامل ميناء في عامل ميناء: "جيد"

منذ أكثر من عامين وضعت في Docker علم -متميز وكتب النسخة الأولى من dind. كان الهدف هو مساعدة الفريق الأساسي على تطوير Docker بشكل أسرع. قبل Docker-in-Docker، كانت دورة التطوير النموذجية تبدو كما يلي:

  • اختراق القرصنة.
  • يبني؛
  • إيقاف تشغيل برنامج Docker الخفي؛
  • إطلاق برنامج Docker الخفي الجديد؛
  • الاختبار؛
  • كرر الدورة.

إذا كنت ترغب في إنشاء مجموعة جميلة وقابلة للتكرار (أي في حاوية)، فقد أصبح الأمر أكثر تعقيدًا:

  • اختراق القرصنة.
  • تأكد من تشغيل نسخة صالحة للعمل من Docker؛
  • إنشاء Docker جديد باستخدام Docker القديم؛
  • إيقاف برنامج Docker الخفي؛
  • بدء برنامج Docker الخفي الجديد؛
  • امتحان؛
  • إيقاف البرنامج الخفي Docker الجديد؛
  • يكرر.

مع ظهور Docker-in-Docker، أصبحت العملية أكثر بساطة:

  • اختراق القرصنة.
  • التجميع + الإطلاق في مرحلة واحدة؛
  • كرر الدورة.

أليس الأمر أفضل بكثير بهذه الطريقة؟

فكر جيدًا قبل استخدام Docker-in-Docker لـ CI أو بيئة الاختبار

عامل ميناء في عامل ميناء: "سيئ"

ومع ذلك، خلافًا للاعتقاد الشائع، فإن Docker-in-Docker ليس 100% نجومًا ومهورًا ووحيدات القرن. ما أعنيه هو أن هناك العديد من المشكلات التي يجب على المطور أن يكون على دراية بها.

تتعلق إحداها بوحدات LSM (وحدات أمان Linux) مثل AppArmor وSELinux: عند تشغيل حاوية، قد يحاول "Docker الداخلي" تطبيق ملفات تعريف الأمان التي قد تتعارض أو تربك "Docker الخارجي". هذه هي المشكلة الأكثر صعوبة في حلها عند محاولة دمج التطبيق الأصلي للعلامة المميزة. نجحت التغييرات التي قمت بها وستمر جميع الاختبارات على جهاز Debian الخاص بي واختبار Ubuntu VMs، لكنها ستتعطل وتحترق على جهاز مايكل كروسبي (كان لديه Fedora على ما أذكر). لا أستطيع أن أتذكر السبب الدقيق للمشكلة، ولكن ربما كان السبب هو أن مايك رجل حكيم يعمل مع SELINUX=enforce (لقد استخدمت AppArmor) ولم تأخذ التغييرات التي قمت بها ملفات تعريف SELinux بعين الاعتبار.

عامل ميناء في عامل ميناء: "الشر"

المشكلة الثانية تتعلق ببرامج تشغيل التخزين Docker. عند تشغيل Docker-in-Docker، يعمل Docker الخارجي فوق نظام ملفات عادي (EXT4 أو BTRFS أو أي شيء لديك) ويعمل Docker الداخلي فوق نظام النسخ عند الكتابة (AUFS أو BTRFS أو Device Mapper ، وما إلى ذلك). ، اعتمادًا على ما تم تكوينه لاستخدام Docker خارجي). يؤدي هذا إلى إنشاء العديد من المجموعات التي لن تنجح. على سبيل المثال، لن تتمكن من تشغيل AUFS فوق AUFS.

إذا قمت بتشغيل BTRFS فوق BTRFS، فمن المفترض أن يعمل في البداية، ولكن بمجرد وجود مجلدات فرعية متداخلة، سيفشل حذف المجلد الفرعي الأصلي. لا تحتوي وحدة Device Mapper على مساحة اسم، لذا إذا كانت مثيلات Docker متعددة تقوم بتشغيلها على نفس الجهاز، فستكون جميعها قادرة على رؤية (والتأثير) على الصور على بعضها البعض وعلى أجهزة النسخ الاحتياطي للحاوية. هذا سيء.

هناك حلول لحل العديد من هذه المشاكل. على سبيل المثال، إذا كنت تريد استخدام AUFS في Docker الداخلي، فما عليك سوى تحويل المجلد /var/lib/docker إلى وحدة تخزين وستكون الأمور على ما يرام. أضاف Docker بعض مساحات الأسماء الأساسية إلى الأسماء المستهدفة لـ Device Mapper بحيث إذا تم تشغيل عدة مكالمات Docker على نفس الجهاز، فلن تتعارض مع بعضها البعض.

ومع ذلك، فإن مثل هذا الإعداد ليس بسيطًا على الإطلاق، كما يتبين من ذلك مقالات في مستودع dind على جيثب.

Docker-in-Docker: الأمر يزداد سوءًا

ماذا عن ذاكرة التخزين المؤقت للبناء؟ قد يكون هذا أيضًا صعبًا للغاية. كثيرًا ما يسألني الناس "إذا كنت أقوم بتشغيل Docker-in-Docker، فكيف يمكنني استخدام الصور المستضافة على مضيفي بدلاً من سحب كل شيء مرة أخرى إلى Docker الداخلي الخاص بي"؟

حاول بعض الأشخاص المغامرين ربط /var/lib/docker من المضيف بحاوية Docker-in-Docker. في بعض الأحيان يقومون بمشاركة /var/lib/docker مع حاويات متعددة.

فكر جيدًا قبل استخدام Docker-in-Docker لـ CI أو بيئة الاختبار
هل تريد إتلاف بياناتك؟ لأن هذا هو بالضبط ما سيضر بياناتك!

من الواضح أن برنامج Docker الخفي مصمم ليتمتع بوصول حصري إلى /var/lib/docker. لا شيء آخر يجب أن "يلمس أو يضغط أو يحث" أي ملفات Docker موجودة في هذا المجلد.

لماذا هو كذلك؟ لأن هذا هو نتيجة أحد أصعب الدروس المستفادة أثناء تطوير dotCloud. تم تشغيل محرك حاوية dotCloud من خلال الوصول إلى عمليات متعددة /var/lib/dotcloud في وقت واحد. الحيل الماكرة مثل استبدال الملف الذري (بدلاً من التحرير في مكانه)، وتزويد التعليمات البرمجية بأقفال استشارية وإلزامية، وتجارب أخرى مع أنظمة آمنة مثل SQLite وBDB لم تنجح دائمًا. عندما كنا نعيد تصميم محرك الحاوية الخاص بنا، والذي أصبح في النهاية Docker، كان أحد قرارات التصميم الكبيرة هو دمج جميع عمليات الحاوية تحت برنامج خفي واحد للتخلص من كل هراء التزامن.

لا تفهموني خطأ: من الممكن تمامًا صنع شيء جيد وموثوق وسريع يتضمن عمليات متعددة وتحكمًا متوازيًا حديثًا. لكننا نعتقد أنه من الأسهل والأسهل كتابة التعليمات البرمجية وصيانتها باستخدام Docker باعتباره المشغل الوحيد.

هذا يعني أنه إذا قمت بمشاركة الدليل /var/lib/docker بين مثيلات Docker المتعددة، فستواجه مشاكل. وبطبيعة الحال، يمكن أن ينجح هذا الأمر، خاصة في المراحل الأولى من الاختبار. "اسمع يا أمي، يمكنني تشغيل أوبونتو كعامل إرساء!" لكن جرب شيئًا أكثر تعقيدًا، مثل سحب نفس الصورة من حالتين مختلفتين، وسوف ترى العالم يحترق.

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

الحل

دعونا نعود خطوة إلى الوراء. هل تحتاج حقًا إلى Docker-in-Docker أم أنك تريد فقط أن تكون قادرًا على تشغيل Docker وبناء وتشغيل الحاويات والصور من نظام CI الخاص بك بينما يكون نظام CI نفسه في حاوية؟

أراهن أن معظم الناس يريدون الخيار الأخير، مما يعني أنهم يريدون نظام CI مثل Jenkins ليكون قادرًا على تشغيل الحاويات. وأسهل طريقة للقيام بذلك هي ببساطة إدخال مقبس Docker في حاوية CI الخاصة بك وربطه بالعلامة -v.

ببساطة، عند تشغيل حاوية CI الخاصة بك (Jenkins أو غيرها)، بدلاً من اختراق شيء ما باستخدام Docker-in-Docker، ابدأ تشغيله بالسطر:

docker run -v /var/run/docker.sock:/var/run/docker.sock ...

ستتمكن هذه الحاوية الآن من الوصول إلى مقبس Docker وبالتالي ستكون قادرة على تشغيل الحاويات. باستثناء أنه بدلاً من تشغيل الحاويات "الفرعية"، سيتم تشغيل الحاويات "التابعة".

جرب ذلك باستخدام صورة عامل الإرساء الرسمية (التي تحتوي على ملف Docker الثنائي):

docker run -v /var/run/docker.sock:/var/run/docker.sock 
           -ti docker

يبدو ويعمل مثل Docker-in-Docker، ولكنه ليس Docker-in-Docker: عندما تقوم هذه الحاوية بإنشاء حاويات إضافية، سيتم إنشاؤها في Docker ذو المستوى الأعلى. لن تواجه الآثار الجانبية للتداخل وستتم مشاركة ذاكرة التخزين المؤقت للتجميع عبر مكالمات متعددة.

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

لذلك، إذا كنت تريد استخدام Docker من Jenkins CI، فلديك خياران:
تثبيت Docker CLI باستخدام نظام تغليف الصور الأساسي (أي إذا كانت صورتك تعتمد على Debian، فاستخدم حزم .deb)، باستخدام Docker API.

بعض الاعلانات 🙂

أشكركم على البقاء معنا. هل تحب مقالاتنا؟ تريد أن ترى المزيد من المحتوى المثير للاهتمام؟ ادعمنا عن طريق تقديم طلب أو التوصية للأصدقاء ، Cloud VPS للمطورين يبدأ من 4.99 دولارًا, تناظرية فريدة من خوادم المستوى المبتدئ ، اخترعناها من أجلك: الحقيقة الكاملة حول VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps من 19 دولارًا أو كيفية مشاركة الخادم؟ (متوفر مع RAID1 و RAID10 ، حتى 24 مركزًا وحتى 40 جيجا بايت DDR4).

Dell R730xd أرخص مرتين في مركز بيانات Equinix Tier IV في أمستردام؟ هنا فقط 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6 جيجا هرتز 14C 64 جيجا بايت DDR4 4x960 جيجا بايت SSD 1 جيجابت في الثانية 100 تلفزيون من 199 دولارًا في هولندا! Dell R420 - 2x E5-2430 2.2 جيجا هرتز 6C 128 جيجا بايت DDR3 2x960 جيجا بايت SSD 1 جيجا بايت في الثانية 100 تيرا بايت - من 99 دولارًا! أقرأ عن كيفية بناء شركة البنية التحتية. فئة مع استخدام خوادم Dell R730xd E5-2650 v4 بقيمة 9000 يورو مقابل فلس واحد؟

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

إضافة تعليق