الانتقال من حاوية مستقلة إلى حاويات ويب وبيانات منفصلة

مرحبًا جايز @pfaffman، شكرًا لك على هذا المنشور والمنشورات الأخرى حول موضوع “حاويتين”، بما في ذلك كتابات سام حول هذا الموضوع أيضًا.

سؤال:

لقد حاولنا إعداد حاويتين كما ذكرت، حاوية واحدة لـ data وحاوية واحدة لـ web-only، وواجهنا عددًا من العقبات في تشغيل هذا الإعداد على نظام macOS.

ولكن قبل أن نقلق بشأن تصحيح أخطاء إعداد “الحاويتين” هذا على نظام macOS أو Ubuntu، نود التأكد من أننا نفعل ذلك للأسباب الصحيحة.

السبب الذي يجعلنا نرغب في تنفيذ “رقصة الحاويتين” هو ألا ينقطع الموقع عند إعادة بناء تطبيق الويب، على سبيل المثال عند تثبيت إضافة. أيضًا، عندما نقوم بضبط إضافة مطورة داخليًا؛ لاحظنا أن الطريقة الوحيدة أحيانًا لضمان عمل تعديلاتنا هي إعادة البناء (وهذه قصة ليوم آخر). لقد كافحت أيضًا للحصول على إعداد “سريع ومريح” لتطوير الويب إلى حد رضائي؛ لكن هذا موضوع آخر ليوم آخر.

إذن، سؤالي هو: هل إعداد “الحاويتين” يقلل بشكل كبير من وقت التوقف عند إعادة بناء الجزء الخاص بـ “web-only” من التطبيق؟

هذا هو التفكير الصحيح في الأمر، أليس كذلك؟

عند تثبيت إضافة أو ضبط واحدة، هل نحتاج إلى إعادة بناء ملف yml الخاص بـ “web-only” فقط وليس ملف yml الخاص بـ البيانات؟

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

هل يُظهر حل “الحاويتين” تحسينات كبيرة في وقت التوقف عندما نقوم إما (1) بإعادة بناء التطبيق (للإضافات، وضبط الكود، إلخ) أو (2) بالاستعادة من نسخة احتياطية كاملة؟

أشعر أنني سأُنتقد (مرة أخرى) لطرح هذا السؤال لأننا نبحث عن طريقة لتشغيل Discourse في بيئة الإنتاج وإجراء تغييرات مع توقف شبه معدوم، ولم نجد بعد طريقة للقيام بأشياء يسهل القيام بها مع تطبيقات LAMP أو VueJS (على سبيل المثال).

ومن هنا، الصراع / الاهتمام بطريقة “الحاويتين” التي لم نتمكن بعد من تشغيلها.

شكرًا لك!

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

لا يوجد فرق عند الاستعادة من نسخة احتياطية.

4 إعجابات

شكرًا لك يا جاي @pfaffman،

أنت حقًا مورد قيم من الطراز الرفيع هنا، بلا شك!

ما رأيك في هذه الفكرة ربما المجنونة (بناءً على فهمي المحدود حتى الآن)؟

إعداد nginx كوكيل عكسي في الواجهة الأمامية؛ وفقًا لهذا الدليل:

ثم إنشاء مجلدين / نسختين مع discourse_docker (مستقلة) مُعدّتين، على سبيل المثال:

  1. /var/discourse1
  2. /var/discourse2

في كلتا النسختين، قم بإعداد discourse_docker (مستقلة) للاستماع إلى منفذ سوكيت مختلف، مع تعديل هذا القالب في كل نسخة:

 - "templates/web.socketed.template.yml"

إذن، باختصار، قمنا ببساطة بإعادة بناء بيئة الإنتاج (في وقت هدوء) لتعمل في حاوية مختلفة تستمع إلى سوكيت مختلف (nginx.https.sock2)، وبالتالي لا يوجد تضارب في السوكيت؛ ويمكننا بناؤها في وضع مستقل أيضًا (بهدف إزالة الحاجة إلى حاويتين، data و web-only).

على سبيل المثال (للمناقشة / التوضيح)، في web.socketed.template.yml في discourse1:

  - replace:
     filename: "/etc/nginx/conf.d/discourse.conf"
     from: /listen 80;/
     to: |
       listen unix:/shared/nginx.http.sock;
       set_real_ip_from unix:;
  - replace:
     filename: "/etc/nginx/conf.d/discourse.conf"
     from: /listen 443 ssl http2;/
     to: |
       listen unix:/shared/nginx.https.sock ssl http2;
       set_real_ip_from unix:;

وفي discourse2:

 - replace:
     filename: "/etc/nginx/conf.d/discourse.conf"
     from: /listen 80;/
     to: |
       listen unix:/shared/nginx.http.sock2;
       set_real_ip_from unix:;
  - replace:
     filename: "/etc/nginx/conf.d/discourse.conf"
     from: /listen 443 ssl http2;/
     to: |
       listen unix:/shared/nginx.https.sock2 ssl http2;
       set_real_ip_from unix:;

ومع ذلك، بدلاً من السماح لقالب discourse بالقيام بالسحر، نقوم ببساطة بالتبديل اليدوي للسوكيت في /etc/nginx/conf.d/discourse.conf وإعادة تشغيل nginx، لذا سنقوم بإزالة أمر replace: في قالب web.socketed.template.yml.

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

يبدو هذا واضحًا وسهلًا وربما مفيدًا (خلال فترة هدوء لا توجد فيها منشورات جديدة في النسخة الحية) لأولئك الذين قد لا يرغبون (أو يحتاجون) إلى تعقيد حاويتين (data و web-only) لكل نسخة واحدة من discourse (تطبيق).

بالطبع، فإن التكوين الأكثر متانة (من منظور البيانات) ومع ذلك، للحصول على الكمال للمواقع المزدحمة، هو حل “الحاويتين” لأننا سنرغب في وجود نسختي data و web-only (التي تستمع الآن إلى سوكيتين مختلفين، sock و sock2.

في حل “الحاويتين” مع واجهة nginx الأمامية، فإن “التكوين القياسي” هو أن تستمع كلتا الحاويتين web-only إلى نفس السوكيت، وبالتالي لا يمكن تشغيلهما في نفس الوقت؛ ولكن إذا (على سبيل المثال فقط) جعلناهما تستمعان إلى سوكيت مختلف، فيمكن تشغيلهما في نفس الوقت ويمكننا ببساطة استخدام ملف تكوين nginx (وإعادة تشغيل nginx) للتبديل بينهما.

هل هذا هو الفهم الصحيح؟

هل أبدأ في (ببطء ولكن على أمل بالتأكيد) فهم هذا؟

شكرًا!

ملاحظة متابعة فقط: لدي تكوين “الحاويتين” يعمل على أحد أجهزة Mac الخاصة بي على سطح المكتب:

Screen Shot 2020-04-11 at 12.41.24 PM

التحذير الوحيد في تثبيتنا كان الحاجة إلى إنشاء هذه المجلدات يدويًا (وتعيين الملكية والأذونات) لأن هذه المجلدات لا يتم إنشاؤها لسبب ما بواسطة البرامج النصية:

~discourse/discourse/shared/data
~discourse/discourse/shared/web-only

وبالطبع، في البداية جربت بكلمة مرور فارغة لقاعدة البيانات، ولم ينجح ذلك (التعليمات تقول بوضوح تعيين كلمة مرور، لكنني كنت فقط أختبر).

في الخطوة التالية، سأقوم بإعداد واجهة nginx الأمامية وأحاول الانتقال إلى هذا التكوين باستخدام websocket لتطبيق web-only.

هذا كثير للاستيعاب. لكن لا داعي لوجود دليلين لـ discourse. فقط أنشئ ملفات متعددة بصيغة yml في دليل الحاويات. سمّها كما تشاء.

إعجابَين (2)

شكرًا للتأكيد. هذا بالضبط كيف تم إعدادنا (مجلد واحد) بعد تجربة اليوم.

كل شيء سار على ما يرام في إعداد الحاويتين (2CC)، لكنني أواجه صعوبة في إعداد وكيل عكسي لـ nginx على macOS.

لا يمكنني الحصول على اتصال يعمل مع منفذ النطاق UNIX في المجلد /shared، رغم أن المنفذ يمكن الوصول إليه من خارج الحاوية. جربت nginx و Python و socat (للاختبار). دائمًا ما يظهر خطأ 61 (رفض الاتصال)… hmmmm

عالق طوال اليوم في رسالة “رفض الاتصال”!!

غدًا يوم آخر.

كان لدي سؤال بسيط.
إذا كان لدينا إعداد حاوية واحدة فقط (ملف ‘app.yml’ فقط)، وقمنا بتشغيل الأمر ./launcher bootstrap app.
هل سيتوقف موقعنا الإلكتروني/واجهة المستخدم أم لا؟

إذا كان الجواب نعم، فلماذا لا يتسبب الأمر ‘bootstrap web-only’ في إيقاف موقعنا الإلكتروني؟

إذا كان الجواب لا، فما الفائدة من إعداد الحاويتين المنفصلتين، من حيث توفير الوقت أثناء إعادة بناء الحاوية؟ وبعبارة أخرى، إذا كان بإمكاننا إبقاء موقعنا الإلكتروني قيد التشغيل حتى أثناء إعداد الحاوية الوحيدة، فلماذا نحتاج إلى وجود حاويتين منفصلتين؟

إعجاب واحد (1)

لا، إذا قمت بإنشاء ملف yml جديد، وسمّيته على سبيل المثال new_image

عملية التمهيد (Bootstrapping) لا تبدأ أو توقف أي خدمة عند تكوينها بشكل صحيح. الصور التي تم تمهيدها لا تعمل. وهذا هو السبب في تسميتها “تم تمهيدها”.

ومع ذلك، تحتاج إلى إنشاء ملف yml جديد لأنك بحاجة إلى إنشاء صورة جديدة باسم صورة جديد.

لذلك، مع اسم صورة جديد، فإن الصورة الممهدة الجديدة لم تعمل بعد. إنها فقط “ممهدة”.

يمكنك بناء الصورة الجديدة باسم جديد (ليس app) وتنتهي عملية البناء. لنسمّ هذه الصورة “new_image”.

ثم، إذا أردنا استبدال صورة قيد التشغيل، لنسمّها “old_image”، يمكنك القيام بما يلي:

./launcher stop old_image; ./launcher start new_image

في حالتك:

./launcher bootstrap new_image          #صورة البيانات وصورة الويب "app" قيد التشغيل
./launcher stop app; ./launcher start new_image

بما أن حاوية البيانات جاهزة بالفعل، فإنك توفر الوقت (1) من خلال عدم بناء صورة البيانات، و(2) عدم وجود وقت توقف أثناء إعادة بناء صورة الويب لأنك يمكنك بناء هذه الصورة (تمهيد الصورة) بينما الصور الأخرى قيد التشغيل.

هذا أسرع بكثير؛ لكنه ليس سريعًا مثل استخدام وكيل عكسي أمام الحاويات.

في سؤالك في الرسالة الأصلية، لديك صورة قيد التشغيل باسم app. إذا حاولت تمهيد الصورة المسماة app مرة أخرى، فإنك تعيد بناء نفس الصورة (الاسم). هذا لن يوفر لك أي وقت، كما أخبرتك غرائزك.

هل أصبح الأمر واضحًا الآن؟

إذا لم يكن كذلك، يرجى السؤال. الجميع يمكنه التعلم؛ والتعلم مثير. هذا (في الواقع) سهل الفهم لكنه يتطلب بعض الوقت إذا كنت جديدًا على هذه المفاهيم.

إعجابَين (2)

للصدق، لم أفهم شيئًا. لقد حاولت، لكنني فشلت.

كان سؤالِي بسيطًا.
إذا كان لدينا إعدادان لحاويتين، وقمنا بـ “تجهيز” (وليس إعادة بناء) الحاوية “المخصصة للويب فقط”، فإن حاوية الويب الحالية ستستمر في العمل (لأن موقعنا الإلكتروني يظهر كعمل/جيد).

أما إذا كان لدينا إعداد لحاوية واحدة، مثل “app.yml”، ثم قمنا بتجهيز حاوية “app” هذه، فهل سيستمر موقعنا الإلكتروني في العمل؟

وإذا كان التفسير بسيطًا، فلماذا يحدث ذلك؟

إعجاب واحد (1)

ربما يجب عليك توظيف شخص لمساعدتك؟

إعجاب واحد (1)

لا مشكلة.

كان مجرد لبس بسيط. قد تكون إحدى جزئياته قابلة للإجابة بـ “نعم/لا” أيضًا.

لا يوجد شيء كبير.

إعجاب واحد (1)

اقتراحي هو الاستمتاع بتجربتها بنفسك.

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

ستحصل على إجابة لسؤالك إذا جربته؛ لذا يجب عليك تجربة هذه الأمور في سيناريو اختبار حتى لا تتعطل تطبيقك الإنتاجي :slight_smile:

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

إذا لم تكن مستعدًا لبذل بعض الجهد في مهام إدارة الأنظمة الأساسية، فقد قدم @codinghorror اقتراحًا رائعًا بشأن توظيف المواهب المحلية هنا.

إعجاب واحد (1)

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

لا. لا يمكن لعملية معالجة قاعدة بياناتتين الوصول إلى نفس الملفات في نفس الوقت.

3 إعجابات

أوه!!
شكرًا لك على توضيح هذا الأمر.

إعجاب واحد (1)

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

إعجاب واحد (1)

استفسار سريع بخصوص هذا النهج: كيف يمكن للمرء المضي قدمًا في عمليات إعادة البناء (Rebuilds) مع هذا الإعداد؟

بافتراض أننا سننتقل إلى إعداد الحاويتين من الصفر الذي أضافه @pfaffman، فإننا سنحصل على “app”: “data” و “web_only”.

جميع عمليات إعادة البناء وما إلى ذلك موجهة إلى حاوية “web_only”، لكن هل نقوم بأي شيء مع حاوية “data” أم أن عملية التمهيد (bootstrap) في “web_only” تتولى ذلك؟ (أسأل فقط لأنني أقوم ببعض الاختبارات وحاوية البيانات لا تتوقف عن العمل في أي لحظة).

نحن نستخدم “ثلاثة حاويات” ووكيل عكسي nginx:

  1. data
  2. socket1
  3. socket2

لنفترض أننا ندير حاليًا socket1 (ما تسميه ‘ويب فقط’) ونريد إعادة البناء واختبار شيء ما. سنقوم بإعادة بناء socket2 بينما يعمل socket1. لأن كلًا من هذه الحاويات يستخدم منفذ نطاق يونكس، يمكن تشغيلها في نفس الوقت لأن المنافذ المشتركة موجودة في ملفات مختلفة (مواقع مختلفة).

ثم، لنفترض أن socket2 تم بناؤه وجاهز للعمل.

أقوم بالآتي:

ln -sf /var/discourse/shared/socket2/nginx.http.sock /var/run/nginx.http.sock

الآن نعمل مباشرة على socket2.

إذا، على سبيل المثال، كانت هناك مشكلة، يمكنني ببساطة فعل الآتي:

ln -sf /var/discourse/shared/socket1/nginx.http.sock /var/run/nginx.http.sock

ونعود إلى حيث كنا من قبل، نعمل على socket1.

للمتعة، أضفت بعض الكود إلى ملف تعريف الدخول في bash، لذا عندما أبدأ جلسة الدخول إلى الخادم، يخبرني دائمًا بأي منفذ (حاوية) يعمل:

Last login: Fri May 15 09:39:39 2020 from 159.192.33.138
srw-rw---- 1 root docker  0 May  5 07:38 /var/run/docker.sock
lrwxrwxrwx 1 root root   44 May 15 09:16 /var/run/nginx.http.sock -> /var/discourse/shared/socket/nginx.http.sock

أتمنى أن يكون هذا مفيدًا.

في رأيي، هذا (بشكل عام) هو “الطريقة الصحيحة” (وهو “المعيار الافتراضي” الخاص بي، في الإنتاج وليس في بيئة الاختبار أو التطوير)، لكن هذا رأيي فقط، وقد يختلف الأمر من شخص لآخر. يتطلب ذلك بعض العمل الإضافي للإعداد، لكنني أعتقد أنه يستحق العناء (في بيئة الإنتاج).


تنبيه:


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

إعجابَين (2)

لا تحتاج إلى إعادة بناء حاوية البيانات إلا في حال وجود ترقية لـ PostgreSQL (كما حدث للتو) أو لـ Redis (التي حدثت منذ حوالي 6 أشهر).

في الغالب، ما عليك سوى استبدال web_only بـ app في التعليمات التي تراها. لدي ملاحظات على Managing a Two-Container Installation - Documentation - Literate Computing Support

5 إعجابات

إذن، في هذا النهج، لديك نسختان من الويب وتستخدم النسخة الخاملة لاختبار الأشياء بنفس البيانات؟ هذا مثير للاهتمام، وسأجربه بالتأكيد بمجرد أن أستقر على استراتيجية “محاولة توفير المساحة” هذه :stuck_out_tongue:

شكرًا جزيلاً لك. قرأت مقالتك من البداية إلى النهاية، لكن لدي سؤال صغير فقط: هل تقصد هنا “البيانات”، صحيح؟ (أي، إعادة بناء البيانات بدلاً من web_only) كما هو مذكور في المقالة؟ أم ربما هناك حيلة مختلفة أفتقدها (أي: عند وجود ترقية كبيرة، تحتاج إلى دمجها ثم فصلها مرة أخرى)؟

نعم، نقوم بالاختبار والإضافة وإعادة البناء في حاوية واحدة تعتمد على المنافذ (socket-based) بينما تعمل الأخرى.

نعم، كلاهما يستخدم حاوية البيانات نفسها. ولا “تهتم” حاوية البيانات بأي تطبيق ويب “تتحدث” إليه.

الأمر بسيط جدًا حقًا، بمجرد أن تفهم الفكرة الأساسية حول كيفية تشغيل الحاويات على منافذ يونكس المشتركة (unix domain sockets) وليس على منافذ TCP/IP المكشوفة خارجيًا.

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

إعجاب واحد (1)

شكرًا على التفاصيل. جربت للتو وجود “حاويتين للتطبيق” تشيران إلى “Data One” في بيئة اختبارية، ويعمل الأمر بسلاسة تامة.

لكن لا يمكنني نقله إلى بيئة الإنتاج (PRD)، لأنني لا أستطيع إعادة بناء حاوية البيانات في بيئة الإنتاج، ولا أريد تغيير أي شيء دون حل هذه المشكلة. الأمر يتسبب فقط في إيقاف العمليات برسالة خطأ: discourse@discourse FATAL: terminating connection due to administrator command