عندما تكون صورة الحاوية جاهزة، أين يتم تشغيلها فعليًا؟
لقد بنيت الصورة. لقد فحصتها بحثًا عن الثغرات الأمنية. لقد دفعتَها إلى السجل. الآن تأتي اللحظة التي تفصل بين خط أنابيب يعمل ونشر حقيقي: تشغيل تلك الحاوية في مكان يمكن للمستخدمين الوصول إليه.
الطريقة التي تشغّل بها تلك الحاوية تعتمد كليًا على المكان الذي ستذهب إليه. خادم واحد ومجموعة Kubernetes قد يبدوان متشابهين على الورق - كلاهما يشغّل حاويات - لكن التجربة التشغيلية مختلفة تمامًا. يؤثر الاختيار على كيفية التحديث، وكيفية التعافي من الأعطال، ومقدار التنسيق اليدوي الذي يحتاجه فريقك في كل مرة يتم فيها إصدار نسخة جديدة.
تشغيل الحاويات على خادم واحد
نشر خادم واحد يبدو مباشرًا. تتصل SSH بالجهاز، وتشغّل docker run مع علامة الصورة التي رقيتها للتو، ويبدأ التطبيق. في بيئة تجريبية، هذه نهاية القصة.
في الممارسة العملية، نادرًا ما يشغّل خادم واحد حاوية واحدة فقط. عادةً ما يكون لديك حاوية تطبيق، وحاوية قاعدة بيانات، وذاكرة تخزين مؤقت، وربما عامل قائمة انتظار. تحتاج هذه الحاويات إلى البدء بالترتيب الصحيح، والتواصل مع بعضها البعض عبر الشبكة الصحيحة، والتعامل مع حالة تعطل إحداها. هذا هو المكان الذي يصبح فيه docker-compose مفيدًا. يمكنك تعريف جميع الخدمات، وتبعياتها، ومنافذها، وسياسات إعادة التشغيل في ملف واحد. أمر واحد يشغّل كل شيء بالتسلسل الصحيح.
التحدي الحقيقي يظهر عندما تحتاج إلى تحديث إصدار التطبيق. على خادم واحد، توقف الحاوية القديمة وتشغّل الجديدة. خلال تلك النافذة، لا يمكن للتطبيق معالجة الطلبات. إذا كان التطبيق مستخدمًا من قبل أشخاص حقيقيين، فإن وقت التوقف هذا مهم.
أبسط طريقة لتقليل وقت التوقف هي تشغيل حاويتين جنبًا إلى جنب. أبقِ الإصدار القديم قيد التشغيل بينما يبدأ الإصدار الجديد. بمجرد أن تصبح الحاوية الجديدة جاهزة لقبول الاتصالات، حوّل حركة المرور إليها، ثم أوقف الحاوية القديمة. هذا هو التحديث المتداول في أبسط صوره. يمكنك القيام بذلك يدويًا باستخدام سكريبت، أو يمكنك استخدام وكيل عكسي مثل Nginx أو Traefik للتعامل مع تبديل حركة المرور.
لكن حتى مع نمط التحديث المتداول، فإن الخادم الواحد له حد صعب. إذا تعطل الخادم نفسه، يتعطل التطبيق. إذا كنت بحاجة إلى تطبيق تصحيح أمني على نظام التشغيل المضيف، فستحتاج إلى جدولة وقت توقف. بالنسبة للأدوات الداخلية التي يستخدمها فريق صغير، غالبًا ما تكون هذه المقايضة مقبولة. بالنسبة للتطبيقات الموجهة للعملاء، عادةً لا تكون كذلك.
تشغيل الحاويات على Kubernetes
تتعامل Kubernetes مع مشاكل النشر على خادم واحد على أنها مشاكل محلولة وتبني عليها. أنت لا تدير الحاويات مباشرة. أنت تعرّف كائن Deployment يصف الحالة المرغوبة: أي صورة تشغيل، وعدد النسخ المتماثلة، وفحوصات الصحة التي يجب استخدامها، وكيفية إجراء التحديثات.
عندما تحدّث علامة الصورة في Deployment، لا توقف Kubernetes كل شيء وتعيد التشغيل. إنها تنشئ pods جديدة بالصورة الجديدة، وتنتظر حتى تجتاز فحوصات الصحة الخاصة بها، ثم تنهي الـ pods القديمة تدريجيًا. خلال العملية بأكملها، هناك دائمًا pod واحد على الأقل يخدم حركة المرور. لا يرى المستخدمون أي انقطاع في الخدمة.
الـ pod هو أصغر وحدة في Kubernetes. يمكنه تشغيل حاوية واحدة أو أكثر، لكن الفكرة الأساسية هي أن الـ pod مؤقت. تنشئ Kubernetes الـ pods، وتدمرها، وتنقلها إلى عقد مختلفة حسب الحاجة. أنت لا تفكر أبدًا في أي خادم محدد يعمل عليه الـ pod. المجموعة تتعامل مع ذلك.
الفرق بين خادم واحد وKubernetes لا يتعلق فقط بالتوسع لحركة مرور أكبر. يتعلق الأمر بمن يملك التنسيق. على خادم واحد، أنت تقرر ترتيب بدء التشغيل، وسياسة إعادة التشغيل، ومعالجة الأعطال. أنت تكتب سكريبتات أو تستخدم docker-compose لفرض هذه القرارات. على Kubernetes، يمتلك المنظم (orchestrator) هذا التنسيق. يتحقق من صحة الـ pods بشكل دوري، ويعيد تشغيل الـ pods الفاشلة، ويعيد توزيع الـ pods على العقد السليمة عندما تتعطل عقدة.
هذا التحول في الملكية يغير كيفية عمل فريقك. تتوقف عن كتابة سكريبتات تتعامل مع دورة حياة الحاوية. تبدأ في كتابة بيانات Deployment تصف الحالة المرغوبة، وتترك للمجموعة معرفة كيفية الوصول إلى تلك الحالة.
إليك ما يبدو عليه بيان Deployment الأدنى في الممارسة العملية:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-registry/my-app:v1.2.3
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
يخبر هذا البيان Kubernetes بتشغيل ثلاث نسخ متماثلة، وتحديثها واحدة تلو الأخرى، وتوجيه حركة المرور فقط إلى pod بعد أن يستجيب نقطة النهاية /health بنجاح.
كيفية الاختيار بين الاثنين
الاختيار بين خادم واحد وKubernetes ليس اختبارًا تقنيًا بحتًا. إنه قرار يعتمد على المتطلبات التشغيلية.
يمكن أن يساعدك المخطط الانسيابي التالي في تحديد المسار الذي يناسب حالتك:
استخدم خادمًا واحدًا مع docker-compose عندما:
- التطبيق يستخدم من قبل فريق داخلي صغير.
- وقت التوقف للتحديثات أو الصيانة مقبول.
- لديك خدمة أو خدمتان لإدارتهما.
- لا تحتاج إلى التوسع أفقيًا.
- حجم فريقك صغير وتريد الحد الأدنى من تعقيد البنية التحتية.
استخدم Kubernetes عندما:
- يجب أن يكون التطبيق متاحًا حتى أثناء التحديثات.
- تحتاج إلى توسيع نطاق الخدمات بشكل مستقل بناءً على حركة المرور.
- تدير خدمات متعددة تحتاج إلى النشر والتحديث بشكل منفصل.
- تريد التعافي التلقائي من أعطال العقد.
- فريقك لديه النضج التشغيلي لإدارة مجموعة.
هناك حل وسط. بعض الفرق تشغّل مجموعة Kubernetes صغيرة بعقدة واحدة باستخدام أدوات مثل K3s أو MicroK8s. يمنحك هذا ميزات التحديث المتداول وفحوصات الصحة في Kubernetes دون التعقيد الكامل لمجموعة متعددة العقد. يجدر النظر فيه إذا كنت تريد أنماط النشر ولكنك لا تحتاج بعد إلى الحجم.
القاعدة الوحيدة التي لا تتغير أبدًا
بغض النظر عن مكان النشر، تبقى قاعدة واحدة كما هي: الصورة التي تعمل في الإنتاج يجب أن تكون بالضبط نفس الصورة التي اجتازت جميع الاختبارات والفحوصات في خط الأنابيب.
لا تقم أبدًا بإعادة بناء الصورة على الخادم. لا تسحب أبدًا علامة مختلفة لأن "يجب أن تكون هي نفسها". لا تدع أبدًا أي شخص يتصل SSH بالخادم ويشغّل حاوية بصورة معدلة محليًا. إذا كانت الصورة في السجل ليست الصورة التي تعمل، فقد فقدت القدرة على إعادة الإنتاج والتدقيق والتراجع.
لهذا السبب فإن وضع العلامات على الصور وترقيتها أمر مهم. عندما ترقّي صورة من مرحلة الاختبار إلى الإنتاج، فإنك لا تعيد بناء أي شيء. أنت ببساطة تغير البيئة المسموح لها بسحب تلك العلامة المحددة. البايتات متطابقة.
قائمة التحقق العملية لنشر الحاوية
قبل نشر حاوية في أي بيئة، تأكد من هذه النقاط:
- علامة الصورة في النشر تطابق العلامة التي اجتازت خط الأنابيب.
- الحاوية لديها نقطة نهاية لفحص الصحة تخبر المنظم بأنها جاهزة.
- متغيرات البيئة والأسرار مضبوطة بشكل صحيح للبيئة المستهدفة.
- استراتيجية التحديث محددة: تحديث متداول لوقت توقف صفري، إعادة إنشاء للحالات البسيطة.
- لديك طريقة لرؤية أي إصدار من الصورة يعمل حاليًا.
- لديك خطة تراجع: إما علامة صورة سابقة أو بيان نشر سابق.
ماذا بعد ذلك
تشغيل الحاوية هو نصف العمل فقط. بمجرد تشغيلها، تحتاج إلى معرفة أي إصدار يخدم حركة المرور فعليًا، وما إذا كان سليمًا، وماذا تفعل عندما يواجه الإصدار الجديد مشكلة. هذا هو المكان الذي يأتي فيه تتبع إصدار الصورة والتراجع. هذه هي مواضيع الجزء التالي من هذه المناقشة.
في الوقت الحالي، الشيء المهم هو اختيار هدف النشر الذي يتطابق مع واقعك التشغيلي، والتأكد من أن الصورة التي تشغّلها هي الصورة التي اختبرتها. كل شيء آخر يتبع من ذلك.