قبل ستة أشهر ، أكملنا ترحيل جميع خدماتنا عديمة الجنسية إلى kubernetes. للوهلة الأولى ، تكون المهمة بسيطة للغاية: تحتاج إلى نشر مجموعة وكتابة مواصفات التطبيق والذهاب. بسبب الهوس بضمان الاستقرار في عمل خدمتنا ، كان علي أن أبدأ على الفور في فهم كيفية عمل k8s واختبار سيناريوهات الفشل المختلفة. معظم الأسئلة التي طرحتها عن كل ما يتعلق بالشبكة. واحدة من هذه القضايا الزلقة هي تشغيل الخدمات في kubernetes.
تخبرنا الوثائق:
- طرح التطبيق
- تعيين عينات من الحيوية / الاستعداد
- إنشاء خدمة
- ثم سيعمل كل شيء: موازنة التحميل ، تجاوز الفشل ، إلخ.
ولكن من الناحية العملية ، كل شيء معقد إلى حد ما. دعونا نرى كيف يعمل في الواقع.
جزء من النظرية
علاوة على ذلك ، أعني أن القارئ على دراية بالفعل بجهاز kubernetes ومصطلحاته ؛ نتذكر فقط ما هي الخدمة.
الخدمة هي جوهر k8s ، الذي يصف مجموعة من المداخن وطرق الوصول إليها.
على سبيل المثال ، أطلقنا تطبيقنا:
apiVersion: apps/v1 kind: Deployment metadata: name: webapp spec: selector: matchLabels: app: webapp replicas: 2 template: metadata: labels: app: webapp spec: containers: - name: webapp image: defaultxz/webapp command: ["/webapp", "0.0.0.0:80"] ports: - containerPort: 80 readinessProbe: httpGet: {path: /, port: 80} initialDelaySeconds: 1 periodSeconds: 1
$ kubectl get pods -l app=webapp NAME READY STATUS RESTARTS AGE webapp-5d5d96f786-b2jxb 1/1 Running 0 3h webapp-5d5d96f786-rt6j7 1/1 Running 0 3h
الآن ، للوصول إليه ، يجب أن ننشئ خدمة نحدد فيها القنوات التي نريد الوصول إليها (المحدد) والمنافذ:
kind: Service apiVersion: v1 metadata: name: webapp spec: selector: app: webapp ports: - protocol: TCP port: 80 targetPort: 80
$ kubectl get svc webapp NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE webapp ClusterIP 10.97.149.77 <none> 80/TCP 1d
الآن يمكننا الوصول إلى خدمتنا من أي جهاز في المجموعة:
curl -i http://10.97.149.77 HTTP/1.1 200 OK Date: Mon, 24 Sep 2018 11:55:14 GMT Content-Length: 2 Content-Type: text/plain; charset=utf-8
كيف يعمل كل شيء

مبسط للغاية:
- قمت بتطبيق kubectl بتطبيق مواصفات النشر
- يحدث السحر ، وتفاصيله ليست مهمة في هذا السياق
- ونتيجة لذلك ، تبين أن عقد العمل في التطبيق موجودة على بعض العقد
- بمجرد أن يقوم كل فاصل زمني لـ kubelet (وكيل k8s على كل عقدة) بأداء عينات من الحيوية / الاستعداد لجميع القرون التي تعمل على عقدة ، فإنه يرسل النتائج إلى apiserver (واجهة لأدمغة k8s)
- يتلقى kube-proxy على كل عقدة إشعارات من apiserver حول جميع التغييرات في الخدمات والمداخن التي تشارك في الخدمات
- يعكس kube-proxy جميع التغييرات في تكوين الأنظمة الفرعية الأساسية (iptables ، ipvs)
من أجل البساطة ، خذ بعين الاعتبار طريقة الوكيل الافتراضية - iptables. في iptables ، لدينا IP الافتراضي الخاص بنا 10.97.149.77:
-A KUBE-SERVICES -d 10.97.149.77/32 -p tcp -m comment --comment "default/webapp: cluster IP" -m tcp --dport 80 -j KUBE-SVC-BL7FHTIPVYJBLWZN
تنتقل حركة المرور إلى سلسلة KUBE-SVC-BL7FHTIPVYJBLWZN ، حيث يتم توزيعها بين سلسلتين أخريين
-A KUBE-SVC-BL7FHTIPVYJBLWZN -m comment --comment "default/webapp:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-UPKHDYQWGW4MVMBS -A KUBE-SVC-BL7FHTIPVYJBLWZN -m comment --comment "default/webapp:" -j KUBE-SEP-FFCBJRUPEN3YPZQT
هذه هي قروننا:
-A KUBE-SEP-UPKHDYQWGW4MVMBS -p tcp -m comment --comment "default/webapp:" -m tcp -j DNAT --to-destination 10.244.0.10:80 -A KUBE-SEP-FFCBJRUPEN3YPZQT -p tcp -m comment --comment "default/webapp:" -m tcp -j DNAT --to-destination 10.244.0.11:80
اختبار فشل أحد المواقد
تطبيق اختبار webapp الخاص بي قادر على التبديل إلى وضع "rash error" ، لذلك تحتاج إلى سحب عنوان URL "/ err".
سحب نتائج ab -c 50 -n 20000 في منتصف الاختبار "/ err" على أحد المداخن:
Complete requests: 20000 Failed requests: 3719
النقطة هنا ليست العدد المحدد للأخطاء (سيختلف عددها تبعاً للحمل) ، ولكنها تختلف. بشكل عام ، قمنا بإلقاء "السيئ" تحت التوازن ، ولكن في وقت تبديل عميل الخدمة تلقى أخطاء. سبب الأخطاء سهل بما يكفي لتفسير: يتم إجراء اختبارات الاستعداد kubelet مرة واحدة في الثانية + حتى وقت قصير لنشر المعلومات التي لم تستجب للاختبار.
هل ستساعد IPVS الخلفية لـ kube-proxy (التجريبي)؟
ليس بالفعل! إنه يحل مشكلة تحسين الوكيل ويقدم خوارزمية موازنة مخصصة ، ولكنه لا يحل مشكلة معالجة الفشل.
كيف تكون
لا يمكن حل هذه المشكلة إلا من خلال موازن يمكنه إعادة المحاولة (إعادة المحاولة). وبعبارة أخرى ، بالنسبة لـ http ، نحتاج إلى موازن L7. مثل هذه الموازنات لـ kubernetes قيد الاستخدام الكامل بالفعل إما في شكل دخول (ضمنيًا كنقطة في الانتقال إلى الكتلة ، ولكن بشكل عام يفعل بالضبط ما يحتاجه) ، أو كتطبيق لطبقة منفصلة - شبكة خدمة ، على سبيل المثال ، istio .
في إنتاجنا ، لم نبدأ بعد في استخدام الدخول أو شبكة الخدمة بسبب التعقيد الإضافي. هذه التجريد ، في رأيي ، تساعد في الحالات التي تحتاج فيها إلى تكوين عدد كبير من الخدمات. ولكن في الوقت نفسه ، "تدفع" إمكانية التحكم والبنية التحتية البسيطة. ستقضي وقتًا إضافيًا لمعرفة كيفية إعداد rertai والمهلة لخدمة معينة.
كيف نفعل
نحن نستخدم خدمات k8s مقطوعة الرأس. لا تحتوي هذه الخدمات على IP افتراضي ، وبالتالي ، لا يشارك kube-proxy و iptables في عملهم. لكل خدمة من هذه الخدمات ، يمكنك الحصول على قائمة المداخن الحية إما من خلال DNS أو من خلال API.
بالنسبة للتطبيقات التي تتفاعل مع الخدمات الأخرى ، نصنع حاوية جانبية مع المبعوث . يتلقى Evoy بشكل دوري قائمة محدثة من الحجرات لجميع الخدمات الضرورية من خلال DNS ، والأهم من ذلك ، أنها قادرة على القيام بمحاولات متكررة للاستعلام عن حوامل أخرى في حالة حدوث خطأ. يمكنك تشغيله كـ DaemonSet على كل عقدة ، ولكن إذا فشل هذا المثيل ، ستتوقف جميع التطبيقات التي تستخدمه عن العمل. نظرًا لأن استهلاك الموارد بواسطة هذا الوكيل صغير جدًا ، فقد قررنا استخدامه في متغير حاوية السيارة المسحوبة.
هذا هو بالضبط ما يفعله istio ، ولكن في حالتنا تحول التوازن نحو البساطة (لا حاجة لتعلم istio ، واجهت أخطاءه). ربما سيتغير هذا التوازن ، وسنبدأ في استخدام شيء مثل istio.
نحن في okmeter.io kubernetes قد تأصلنا بالتأكيد ، ونؤمن بتوزيعه الإضافي. دعم مراقبة k8s في خدمتنا على الطريق ، ترقبوا!