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

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

على الرغم من أنني أعرف أن هذه ليست مشكلة تتعلق بـ discourse نفسها (يمكن أن تواجه بيئة تحتوي على عدة نسخ طبق الأصل هذه المشكلة إذا تم تحديث إحدى النسخ قبل الأخرى، ما لم يتم إيقاف جميعها قبل الترقية، ولكن هذا على الأرجح لن يكون الحال إذا كنت تريد التوفر العالي)، فإن العملية التي وصفتها لا تزال آمنة بشكل عام؟

أحد الأشياء التي يمكنني التفكير فيها هو التأكد من الحفاظ على تحديث discourse دائمًا لتحقيق الحد الأدنى من ترحيل قاعدة البيانات بين عمليات إعادة البناء. ولكن في أي حال، لا يزال هذا غير مثالي، وقد تنشأ مشاكل حتى في هذه الحالة.

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

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

إذا كنت تريد انقطاعًا صفرًا للخدمة، فهناك بضع خطوات إضافية يجب تنفيذها: قم بتعطيل “post-migrations” في الحاويات الجديدة، ثم انشر الحاوية الجديدة بالكامل، ثم فعّل post-migrations، ثم انشر مرة أخرى. سيؤدي هذا إلى منع تنفيذ أي عمليات ترحيل تقوم بحذف الأعمدة حتى يتوقف الكود القديم عن العمل.

لا توجد دليل تعليمي (howto) لذلك حتى الآن، وهو موثق فقط هنا:

ولكن في الغالب، يمكن لمعظم المنتديات تحمل دقيقة أو ثلاث دقائق من التوقف شهريًا.

4 إعجابات

نعم. في معظم الأحيان، لا توجد هجرات تكسر الحاوية العاملة.

يمكنك أيضًا تعطيل الهجرات في ملف web_only.yml، ثم بعد تشغيل الحاوية الجديدة، قم بتنفيذ أمر مثل

 cd /var/www/discourse;SKIP_POST_DEPLOYMENT_MIGRATIONS=0 rake db:migrate 

داخل الحاوية العاملة.

3 إعجابات

نعم، يعمل هذا بشكل مثالي في الإنتاج باستخدام nginx كخادم وكيل عكسي (reverse proxy server) أمامي.

إليك ما أقوم به:

ثلاث حاويات:

  • البيانات (data.yml)
  • Socket1 (socket1.yml)
  • Socket2 (socket2.yml)

نحدد نقطة اتصال يونكس (unix domain socket) واحدة في إعدادات nginx, على سبيل المثال:

location / {
       proxy_pass http://unix:/var/run/nginx.http.sock;
       proxy_set_header Host $http_host;
       proxy_http_version 1.1;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header X-Forwarded-Proto https;
       proxy_set_header X-Real-IP $remote_addr;
}

ثم نختار الحاوية التي نريد أن تكون نشطة (live) من خلال رابط رمزي (symbolic link) إلى نقطة الاتصال الفعلية، مثل هذا:

لنفترض أننا نريد أن تكون حاوية socket2 نشطة:

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

لنفترض أننا نريد إجراء تغيير على socket1 وجعل socket1 نشطًا:

cd /var/discourse
./launcher rebuild socket1
ls -sf /var/discourse/shared/socket1/nginx.http.sock /var/run/nginx.http.sock

لاحظ أنه لا يوجد سبب لإجراء عملية التمهيد (bootstrap) فقط لحاوية socket1, لأن الحاوية معروضة عبر نقطة اتصال يونكس في دليلها أو حجمها المشترك الخاص بها، لذا يمكن تشغيل كلا هذين الحاويتين “تطبيق الويب” في نفس الوقت:

  • Socket1: /var/discourse/shared/socket1/nginx.http.sock
  • Socket2: /var/discourse/shared/socket2/nginx.http.sock

لا يوجد هنا “تصادم في ربط المنافذ” (port binding collision) كما هو الحال عند تعريض منفذ حاوية TCP/IP. لهذا السبب، أقوم فقط بتعريض نقطة اتصال يونكس في الإنتاج (وليس منفذ TCP/IP).

بالطبع، يمكنك إجراء عملية التمهيد (bootstrap) إذا أردت:

cd /var/discourse
./launcher bootstrap socket1
./launcher start socket1
ls -sf /var/discourse/shared/socket1/nginx.http.sock /var/run/nginx.http.sock

الأمر يعود لك، ولكن ضع في اعتبارك أنه إذا قمت بتشغيل الحاويتين في نفس الوقت، فسيتم تشغيل sidekiq في كل منهما وتشغيل المهام المجدولة، وهذا ما كان تجربه لدينا؛ لذلك نقوم أحيانًا بمزامنة التحميلات (uploads) في كلا الحاويتين.

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

ملاحظة:

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

لذا، أنا أقوم فعليًا بالعكس من هذا:

كما قلت، في بيئة التطوير يعمل بشكل جيد.

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

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


بواسطة “التطوير”، أعني تطوير البرمجيات (على سبيل المثال، تطوير الإضافات plugins)؛ وليس مجرد “تجهيز” (staging) تثبيت لـ Discourse، وهو ما أشير إليه بـ “التجهيز” وليس “التطوير” (فقط لتكون الأمور واضحة تمامًا).

إعجابَين (2)

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

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

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

لقد قصدت ببيئة التطوير أنها بيئة تطوير عن بعد استخدمتها لاختبار إعداد متعدد الحاويات (سواء على نفس الجهاز أو مع وجود الحاويات على أجهزة مختلفة).

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

إعجابَين (2)

بحسب ما أستطيع استنتاجه، هذا الدليل يحتوي على الكثير من الكلام حول:

  • النسخ الاحتياطي
  • إنشاء مثيل discourse جديد تمامًا، بمزيد من الكلمات ولكن بنفس النتائج التي نحصل عليها من مجرد تشغيل discourse_setup 2container
  • الاستعادة

لماذا لا تقوم ببساطة بنقل أو نسخ /var/discourse/shared/standalone/{postgres,redis}* إلى /var/discourse/shared/data بعد إيقاف تشغيل نظيف وقبل بدء تشغيل حاويتين جديدتين من ملفات containers/*.yml منفصلة؟ يبدو أن عملية النسخ الاحتياطي والاستعادة طريقة ثقيلة جدًا لنقل كل هذه البيانات، مما يضيف ساعات غير ضرورية إلى العملية. هل فاتني شيء واضح هنا؟

لقد جربت هذه العملية للتو على discourse التجريبي الخاص بي، وقمت بفصل redis أيضًا طالما أنني كنت أعمل على ذلك، فقط للتأكد من أنني أغطي جميع الجوانب. تعديل: لقد نقلت الوصف إلى موضوع جديد:

يبدو أن الموقع يعمل بشكل جيد دون دورة نسخ احتياطي/استعادة. هل هناك شيء غير واضح يجب أن أتحقق منه؟

لقد قمت بنفس العملية لـ discourse كبير نسبيًا وهو يعمل بشكل جيد. قررت أنه في بيئة الإنتاج سأقوم بتسمية حاوية web_only الجديدة باسم app حتى تستمر أصابعي في فعل الشيء الصحيح بشكل طبيعي. بعد كتابة ملفات container/*.yml الجديدة، كان وقت التوقف عن العمل طوال عملية الهجرة 12 دقيقة فقط، وهو أسرع بكثير مما كان سيكون عليه الحال في دورة النسخ الاحتياطي والاستعادة.

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

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

أعتقد أننا إذن نوافق على الاختلاف. أظن أنه إذا كان شخص ما كفؤًا في تشغيل حاويات متعددة، فبإمكانه تنفيذ بعض الأوامر، ولا أعتقد أن هذه الأوامر أصعب في الكتابة من أمر bin/rails c ثم كتابة أوامر Ruby هنا، أو أنها تتطلب مهارات أكثر أو مختلفة بشكل جوهري عن تلك المطلوبة لاستخدام حاويات متعددة على الإطلاق. :smiling_face: لكنني سأقوم بنقل المحتوى إلى منشور جديد منفصل بدلًا من تركه مدفونًا في تعليق هنا.

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

هذا حجة معقولة. ربما جعل الإجراء يبدو أكثر رعبًا سيبقي أولئك الذين لا يمتلكون المهارات عن تجربة الأمر.

…وإذا ارتكبوا خطأً، فلا بديل عن نسخة احتياطية قبل الهجرة! أتمنى أن تكون هذه النقطة واضحة في تدوينتي المرتبطة أعلاه الآن! :smiling_face:

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

هنا تكمن الثغرة في حجتك. إضافة 2container إلى ./discourse-setup لا تتضمن أي مقياس للكفاءة. هناك الكثير من الأشخاص الذين يديرون حاويتين ببساطة لأنهم يرون مواضيع مثل هذه ويفترضون وجود سر خفي أو أن هذا هو “الشيء الذي يجب فعله”.

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

إعجابَين (2)

@ستيفن هناك ثغرة في حجتك: وصف الحاويات المتعددة مليء بالتحذيرات التي تنص على أنك تتحمل مسؤولية التحديثات وتفهم كيفية عملها، والوصف الطويل أعلاه غامض لدرجة أن أي شخص ينظر إليه على الأرجح سيتخلى عن الأمر. اذهب واقرأ مقالتي على Migrate quickly to separate web and data containers وأخبرني ألا تخيف الأشخاص الذين سيواجهون صعوبة في متابعته، أو أنه يفشل في التأكيد على ضرورة النسخ الاحتياطي والقدرة على العودة إلى النسخة الاحتياطية في حال حدوث أي خطأ!

كنت غير سعيد للغاية عندما نفذت الأمر ./launcher rebuild app بعد وقت قصير من الانتقال إلى خادم أكثر كفاءة (لتطبيق إصلاح أمني)، مما أدى إلى توقف موقعي لفترة طويلة بشكل فاضح، وكان جزء كبير من ذلك الوقت مخصصًا لإعادة بناء أجزاء postgres في الحاوية. كان ذلك هو الوقت الذي وجدت فيه وثائق الحاويتين ووثائق هذا الموقع، ولم أكن أريد حقًا تحمل فترة توقف أخرى مدتها 4 ساعات للانتقال، لذا استمريت في تحمل فترات توقف طويلة لتنفيذ ./launcher rebuild app لتجنب 4 ساعات من التوقف التي يتطلبها الاستعادة. كشخص يتمتع بكفاءة متوسطة، كنت منزعجًا لفترة طويلة لأن هذا التكوين كان مخفيًا فعليًا.

موضوع postgres 12 مرجع ممتاز، لأن الناس ينتهي بهم المطاف إلى توقف أطول لأنهم يضطرون إلى إعادة بناء التطبيق كاملًا عدة مرات، بينما كان بإمكانهم إعادة بناء حاوية postgres فقط مرتين. لا يمكنني القول إنني قرأت الموضوع بأكمله بسبب ميزة الحذف التلقائي بعد 6 أيام، لكنه ليس واضحًا على الإطلاق بالنسبة لي أن عمليات نشر الحاويات المتعددة غير الكفؤة هي المشكلة الكبيرة هناك، أو حتى مشكلة كبيرة.

(آسف، أحيانًا أتعب قليلاً من فكرة أن “جميع المستخدمين غير أكفاء” هنا.)

إعجابَين (2)

قد لا يبدو ذلك منطقيًا بالنسبة لك، لكن بالنسبة لنا الذين نعمل هنا في ميتا منذ 6 أو 7 سنوات ونقدم المساعدة للناس في قناة #الدعم، فسيظل وجود استراتيجية للعودة إلى الخلف أمرًا منطقيًا دائمًا.

فالأخطاء البرمجية تتسلل بالفعل إلى الاختبارات التي تجاوزتها، وأحيانًا تؤثر قيود معدل الوصول في RubyGems على عمليات إعادة البناء، وحتى GitHub مرّ بتعثرات فردية. ولأسباب من هذا القبيل وحدها، لا أرى أي قيمة في إجراء تغيير في الحالة يجعل من الصعب ببساطة إعادة تسمية ملف وتشغيل الأمر ./launcher start app.

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

3 إعجابات

لا أشعر أنك قرأت بالفعل العملية التي كتبتها، حيث تكتب كما لو أنني لم أؤكد على الحاجة إلى إمكانية الاستعادة. يرجى قراءتها ثم العودة ومراجعة ما كتبته لتصبح عبارة صادقة فيما يتعلق بتعليماتي. كما هو الحال، أشعر أنك تُعلّمني دون أن تكرمني بمحاولة قراءة ما كتبته.

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

إعجابَين (2)

أولاً، شكرًا لك على محاولة تطهير هذه “الغابة” لنا، أيها المغامرون :sweat_smile:، سأكون على الأرجح خلفك بعد بضعة أيام… ما الذي يحتويه ملف multisite.yml؟

مرحبًا.

لقد قمت مؤخرًا بإعداد منتدى Discourse مستضاف ذاتيًا على خادم افتراضي خاص (VPS). يتم تخزين الملفات المرفوعة على Wasabi، وكذلك النسخ الاحتياطية. كل شيء مستضاف على Linode.

استخدمت قالبًا مستقلاً ووجدت أن الإعداد كان نسمّة هواء منعشة مقارنة بالبرمجيات الأخرى. كان رائعًا! سرور خالص. أتمنى أن يولي كل مشروع مفتوح المصدر اهتمامًا كبيرًا للتثبيت والإعداد مثلما فعلت Discourse.

إليك المشكلة: لدي خادم PostgreSQL مخصص يعمل على خادم منفصل، ويمكن الوصول إليه فقط عبر عنوان RFC-1918 غير متاح للإنترنت، وأود أن تستخدمه Discourse. لست من محبي تشغيل خوادم قواعد البيانات على نفس الخادم الذي يستضيف الويب أو التطبيق.

إذًا، هل هناك طريقة لفصل قاعدة البيانات المستقلة ونقلها إلى مجموعة قواعد البيانات المخصصة لدي؟

أفترض أن كل ما سأحتاجه هو إجراء نسخة احتياطية (pgdump) لقاعدة بيانات Discourse، ونقلها إلى قاعدة البيانات المخصصة، ثم استعادتها، متبوعة بتشغيل أمر vacuum analyze على جميع الجداول بعد الاستيراد، ثم مجرد توجيه تطبيق Discourse إلى قاعدة البيانات الجديدة عبر الشبكة؟

لكنني لا أستطيع العثور على مكان تخزين بيانات اعتماد قاعدة البيانات. لقد بحثت في ملف app.yml، لكن لم أجد أي إدخالات تتعلق بقاعدة البيانات، وعندما نظرت في مجلد ../templates/، لم أجد أن أيًا من ملفات yml يحتوي على بيانات اعتماد قاعدة البيانات.

هل ما أحاول فعله ممكن فعليًا؟

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

يمكنك اتباع هذا الدليل الذي يشرح إعداد بيانات الاعتماد:

3 إعجابات

ممتاز! هذا بالضبط ما كنت أبحث عنه. شكرًا جزيلاً لك!

الآن لنجعل nginx يرى عنوان IP الحقيقي خلف CloudFlare… :wink:

إذا لم تكن هناك بيانات اعتماد افتراضية لقاعدة بيانات postgres المدمجة، فهل توجد طريقة لتشغيل pgdump وتصدير قاعدة البيانات من الحاوية المستقلة؟

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

النسخ الاحتياطي القياسي لـ Discourse هو ملف pg_dump مضغوط في ملف tar، لذا يمكنك استخدامه.

إذا كنت ترغب في تنفيذ شيء مخصص، مثل تمرير النسخة الاحتياطية عبر خط أنابيب أو استخدام تنسيق مختلف، فيمكنك دائمًا فعل ذلك:

ssh root@forum
cd /var/discourse
./launcher enter app
su postgres
psql # أو pg_dump
إعجابَين (2)