بدأنا في إنشاء أول مجموعة Kubernetes في عام 2017 (من الإصدار K8s 1.9.4). كان لدينا مجموعتان. عمل أحدهما في المعدن المكشوف ، على أجهزة RHEL الافتراضية ، والآخر في سحابة AWS EC2.
اليوم ، تضم بنيتنا التحتية أكثر من 400 جهاز افتراضي منتشرة عبر مراكز بيانات متعددة. تعمل المنصة كأساس لتطبيقات وأنظمة المهام الحرجة عالية التوفر والتي تقود شبكة ضخمة تضم ما يقرب من 4 ملايين جهاز نشط.
في النهاية ، جعل Kubernetes حياتنا أسهل ، لكن الطريق إلى ذلك كان شائكًا وتطلب تغييرًا كاملاً في النموذج. كان هناك تحول كلي ليس فقط في مجموعة المهارات والأدوات ، ولكن أيضًا في نهج التصميم والتفكير. كان علينا إتقان العديد من التقنيات الجديدة والاستثمار بكثافة في تطوير البنية التحتية وتطوير الفريق.
فيما يلي الدروس الأساسية التي تعلمناها من استخدام Kubernetes في الإنتاج على مدار ثلاث سنوات.
1. قصة مسلية مع تطبيقات جافا
عندما يتعلق الأمر بالخدمات المصغرة والحاويات ، يميل المهندسون إلى الابتعاد عن Java ، ويرجع ذلك أساسًا إلى إدارة الذاكرة غير الكاملة المعروفة. ومع ذلك ، فإن الوضع اليوم مختلف وقد تحسن توافق Java مع الحاويات في السنوات الأخيرة. بعد كل شيء ، حتى الأنظمة الشائعة مثل Apache Kafka و Elasticsearch تعمل في Java.
في 2017-2018 ، تم تشغيل بعض تطبيقاتنا في الإصدار 8 من Java. غالبًا ما رفضوا العمل في بيئات حاويات مثل Docker وتحطمت بسبب مشاكل في الذاكرة الكومة وجامعي القمامة غير المناسبين. كما اتضح ، كانت هذه المشكلات ناتجة عن عدم قدرة JVM على تشغيل آليات Linux (
cgroupsو namespaces).
منذ ذلك الحين ، بذلت Oracle جهودًا كبيرة لتحسين توافق Java مع عالم الحاويات. في وقت مبكر من الإصدار 8 من Java ، ظهرت أعلام JVM التجريبية لمعالجة هذه المشكلات:
XX:+UnlockExperimentalVMOptionsوعلى XX:+UseCGroupMemoryLimitForHeap.
الرغم من كل التحسينات ، لم يجادل أحد بأن Java لا تزال تتمتع بسمعة سيئة لكونها تستهلك الكثير من الذاكرة وبطيئة في البدء مقارنة ببايثون أو إذهب. هذا يرجع في المقام الأول إلى تفاصيل إدارة الذاكرة في JVM و ClassLoader.
اليوم، إذا كان لنا أن يكون لديك للعمل مع جافا، فإننا على الأقل في محاولة لاستخدام النسخة 11 أو أعلى. وحدود الذاكرة الخاصة بنا في Kubernetes أعلى بمقدار 1 جيجابايت من الحد الأقصى لذاكرة الكومة في JVM (
-Xmx) (فقط في حالة). أي ، إذا كان JVM يستخدم 8 جيجا بايت لذاكرة الكومة ، فسيتم تعيين حد ذاكرة Kubernetes للتطبيق على 9 جيجا بايت. بفضل هذه الإجراءات والتحسينات ، أصبحت الحياة أسهل قليلاً.
2. التحديثات المتعلقة بدورة حياة Kubernetes
تعد إدارة دورة حياة Kubernetes (التحديثات والإضافات) أمرًا مرهقًا وصعبًا ، خاصةً إذا كانت المجموعة تعتمد على أجهزة معدنية أو افتراضية . اتضح أنه للترقية إلى إصدار جديد ، يكون من الأسهل بكثير رفع مجموعة جديدة ثم نقل أعباء العمل إليها. إن ترقية المواقع الحالية غير عملية لأنها تتطلب الكثير من الجهد والتخطيط الدقيق.
وذلك لأن Kubernetes بها الكثير من الأجزاء "المتحركة" التي يجب مراعاتها عند الترقية. لكي تعمل الكتلة ، يجب عليك جمع كل هذه المكونات معًا - من Docker إلى مكونات CNI الإضافية مثل Calico أو Flannel. تعمل مشاريع مثل Kubespray و KubeOne و kops و kube-aws على تبسيط العملية إلى حد ما ، لكنها لا تخلو من العيوب.
نشرنا مجموعاتنا في أجهزة RHEL الافتراضية باستخدام Kubespray. لقد أثبت أنه ممتاز. كان لدى Kubespray نصوص برمجية لإنشاء العقد وإضافتها أو إزالتها وتحديث إصدار وكل ما تحتاجه تقريبًا للعمل مع Kubernetes في الإنتاج. ومع ذلك ، كان نص الترقية مصحوبًا بالتحذير من أنه حتى الإصدارات الثانوية لا ينبغي تخطيها. بمعنى آخر ، للوصول إلى الإصدار المطلوب ، كان على المستخدم تثبيت جميع الإصدارات الوسيطة.
تتمثل الفكرة الرئيسية هنا في أنه إذا كنت تخطط لاستخدام Kubernetes أو كنت تستخدمه بالفعل ، ففكر في خطوات دورة حياة K8s وكيف تتناسب مع الحل الخاص بك. غالبًا ما يكون إنشاء مجموعة وتشغيلها أسهل من إبقائها محدثة.
3. بناء ونشر
كن مستعدًا لحقيقة أنه سيتعين عليك مراجعة خطوط أنابيب البناء والنشر. مع الانتقال إلى Kubernetes ، مررنا بتحول جذري في هذه العمليات. لم نقم فقط بإعادة هيكلة خطوط أنابيب Jenkins ، ولكن بمساعدة أدوات مثل Helm ، قمنا بتطوير استراتيجيات جديدة للبناء والعمل مع Git ، ووضع علامات على صور Docker ، وإصدار مخططات Helm.
ستحتاج إلى استراتيجية واحدة للحفاظ على الكود الخاص بك ، وملفات نشر Kubernetes ، وملفات Dockerfiles ، وصور Docker ، ومخططات Helm ، وطريقة لربطها معًا.
بعد عدة تكرارات ، استقرنا على الرسم البياني التالي:
- يوجد كود التطبيق ومخططاته Helm في مستودعات مختلفة. يتيح لنا ذلك نسخها بشكل مستقل عن بعضها البعض (النسخ الدلالية ).
- , , . , ,
app-1.2.0charts-1.1.0. (values) Helm, patch- (,1.1.01.1.1). (RELEASE.txt) . - , Apache Kafka Redis ( ), . , Docker- Helm-. Docker- , .
(. .: Open Source- Kubernetes — werf — , .)
4. Liveness Readiness ( )
تعد عمليات التحقق من جاهزية واستعداد Kubernetes رائعة للتعامل مع مشكلات النظام بشكل مستقل. يمكنهم إعادة تشغيل الحاويات عند الفشل وإعادة توجيه حركة المرور من الحالات "غير الصحية". ولكن في بعض الحالات ، يمكن أن تتحول هذه الفحوصات إلى سيف ذي حدين وتؤثر على بدء تشغيل التطبيق واستعادته (ينطبق هذا بشكل خاص على التطبيقات ذات الحالة مثل منصات الرسائل أو قواعد البيانات).
أصبح كافكا لدينا ضحيتهم. كان لدينا مجموعة مصحوبة بالحالة من 3
Brokerو 3 Zookeeperمع replicationFactor= 3 وminInSyncReplica= 2. حدثت المشكلة عند إعادة تشغيل كافكا بعد حوادث أو أعطال عشوائية. عند بدء التشغيل ، قام كافكا بتشغيل نصوص برمجية إضافية لإصلاح الفهارس التالفة ، الأمر الذي استغرق من 10 إلى 30 دقيقة ، حسب خطورة المشكلة. تسبب هذا التأخير في فشل اختبارات النشاط باستمرار ، مما تسبب في "قتل" Kubernetes لكافكا وإعادة تشغيله. نتيجة لذلك ، لم يتمكن كافكا من إصلاح الفهارس فحسب ، بل حتى البدء.
كان الحل الوحيد في ذلك الوقت هو تكوين المعلمة
initialDelaySecondsفي إعدادات اختبار الفعالية بحيث لا يتم إجراء الفحوصات إلا بعد إطلاق الحاوية. التحدي الرئيسي ، بالطبع ، هو تحديد أي تأخير. يبدأ الفرد بعد الفشل يمكن أن يستغرق ما يصل إلى ساعة ، وهذا يجب أن يؤخذ في الاعتبار. من ناحية أخرى ، أكثرinitialDelaySeconds، سوف تستجيب Kubernetes الأبطأ للفشل أثناء بدء تشغيل الحاوية.
في هذه الحالة ، النقطة المثالية هي القيمة
initialDelaySecondsالتي تناسب متطلبات المرونة لديك مع استمرار منح التطبيق وقتًا كافيًا لبدء التشغيل بنجاح في جميع حالات الفشل (فشل القرص ، مشاكل الشبكة ، تعطل النظام ، إلخ)
تحديث : في الإصدارات الأخيرة من Kubernetes ، ظهر نوع ثالث من الاختبارات يسمى مسبار بدء التشغيل. وهي متوفرة كإصدار ألفا منذ الإصدار 1.16 ، وكإصدار تجريبي منذ 1.18.
يحل Startup Probe المشكلة المذكورة أعلاه عن طريق تعطيل عمليات التحقق من الجاهزية والحيوية حتى يتم بدء تشغيل الحاوية ، مما يسمح للتطبيق بالبدء بشكل طبيعي.
5. العمل مع IP الخارجي
كما اتضح ، فإن استخدام عناوين IP الخارجية الثابتة للوصول إلى الخدمات يضع ضغطًا كبيرًا على آلية تتبع اتصال kernel. إذا كنت لا تفكر في الأمر بعناية ، يمكن أن "ينكسر".
في مجموعتنا ، نستخدم
Calicoكلاً من CNI BGPوبروتوكول توجيه ، وكذلك للتفاعل مع أجهزة التوجيه الحدودية. تم تمكين وضع Kube-proxy iptables. نفتح الوصول إلى خدمتنا المزدحمة للغاية في Kubernetes (فهي تعالج ملايين الاتصالات كل يوم) من خلال IP خارجي. بسبب SNAT والإخفاء الذي يأتي من الشبكات المعرفة بالبرمجيات ، يحتاج Kubernetes إلى آلية لتتبع كل هذه التدفقات المنطقية. لهذا تستخدم K8s هذه الأدوات الأساسية كـ onntrackوnetfilter... بمساعدتهم ، يدير الاتصالات الخارجية لعنوان IP ثابت ، والذي يتم تحويله بعد ذلك إلى عنوان IP الداخلي للخدمة وأخيراً إلى عنوان IP الخاص بالجراب. ويتم كل هذا باستخدام جدول conntrackو iptables.
ومع ذلك ، فإن إمكانيات الجدول ليست
conntrackغير محدودة. عند الوصول إلى الحد الأقصى ، لن تتمكن مجموعة Kubernetes (بتعبير أدق ، نواة نظام التشغيل في جوهرها) من قبول اتصالات جديدة. في RHEL ، يمكن التحقق من هذا الحد على النحو التالي:
$ sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_maxnet.netfilter.nf_conntrack_count = 167012
net.netfilter.nf_conntrack_max = 262144
تتمثل إحدى طرق التغلب على هذا القيد في الجمع بين مضيفين متعددين مع أجهزة توجيه الحافة بحيث يتم توزيع الاتصالات الواردة إلى عنوان IP ثابت عبر المجموعة بأكملها. إذا كان لديك أسطول كبير من الآلات في مجموعتك ، يمكن أن يؤدي هذا الأسلوب إلى زيادة حجم الجدول
conntrackبشكل كبير للتعامل مع عدد كبير جدًا من الاتصالات الواردة.
لقد أربكنا هذا تمامًا عندما بدأنا لأول مرة في عام 2017. ومع ذلك ، نشر مشروع كاليكو مؤخرًا نسبيًا (في أبريل 2019) دراسة تفصيلية تحت العنوان المناسب " لماذا لم يعد conntrack صديقك " (توجد مثل هذه الترجمة إلى اللغة الروسية - تقريبًا. مترجم) .
هل أنت حقًا بحاجة إلى Kubernetes؟
مرت ثلاث سنوات ، لكننا ما زلنا نكتشف / نتعلم شيئًا جديدًا كل يوم. Kubernetes عبارة عن نظام أساسي معقد به مجموعة من التحديات الخاصة به ، خاصة في مجال بدء البيئة والحفاظ عليها تعمل. سوف يغير تفكيرك والهندسة المعمارية والموقف تجاه التصميم. سيكون عليك التعامل مع زيادة الفرق وترقيتها.
من ناحية أخرى ، فإن العمل في السحابة والقدرة على استخدام Kubernetes كخدمة سيوفر لك معظم المخاوف المرتبطة بصيانة النظام الأساسي (مثل تمديد CIDR للشبكة الداخلية وتحديث Kubernetes).
اليوم توصلنا إلى فهم أن السؤال الرئيسي الذي يجب طرحه على أنفسنا هو حقًاهل تحتاج Kubernetes؟ سيساعدك على تقييم مدى عالمية المشكلة وما إذا كان برنامج Kubernetes سيساعدك في التعامل معها.
الشيء هو أن الانتقال إلى Kubernetes مكلف. لذا فإن الجوانب الإيجابية لحالة الاستخدام الخاصة بك (ومقدارها وكيفية تعزيزها للمنصة) يجب أن تبرر السعر الذي تدفعه. إذا كان الأمر كذلك ، يمكن لـ Kubernetes تحسين إنتاجيتك بشكل كبير.
تذكر أن التكنولوجيا من أجل التكنولوجيا لا معنى لها.
PS من المترجم
اقرأ أيضًا على مدونتنا: