تقريبا. العابرة. : هذا المقال جزء من المواد المتاحة مجانًا من مشروع learnk8s ، والذي يعلمك كيفية العمل مع شركات Kubernetes والمسؤولين الأفراد. في ذلك ، يشارك Daniele Polencic ، مدير المشروع ، تعليمات واضحة حول الخطوات التي يجب اتخاذها في حالة وجود مشاكل عامة للتطبيقات التي تعمل في مجموعة K8s.
TL ؛ DR: إليك مخطط يساعدك في تصحيح النشر في Kubernetes:
مخطط انسيابي للعثور على الأخطاء وإصلاحها في كتلة. في الأصل (باللغة الإنجليزية) وهي متوفرة في PDF وكصورة .عند نشر تطبيق على Kubernetes ، عادة ما تحتاج إلى تحديد ثلاثة مكونات:
- النشر هو وصفة لإنشاء نسخ من تطبيق يسمى القرون.
- خدمة - موازن التحميل الداخلي الذي يوزع حركة المرور بين القرون.
- دخول - وصف لكيفية تدفق حركة المرور من العالم الخارجي إلى الخدمة.
فيما يلي ملخص رسومي موجز:
1) في Kubernetes ، تستقبل التطبيقات حركة المرور من العالم الخارجي من خلال طبقتين من موازين التحميل: داخلية وخارجية.

2) يسمى الموازن الداخلي الخدمة ، الخارجية - دخول.

3) النشر يخلق القرون ويرصدها (لا يتم إنشاؤها يدوياً).

لنفترض أنك تريد نشر تطبيق بسيط باسم la
Hello World . سيبدو تكوين YAML كما يلي:
apiVersion: apps/v1 kind: Deployment # <<< metadata: name: my-deployment labels: track: canary spec: selector: matchLabels: any-name: my-app template: metadata: labels: any-name: my-app spec: containers: - name: cont1 image: learnk8s/app:1.0.0 ports: - containerPort: 8080 --- apiVersion: v1 kind: Service # <<< metadata: name: my-service spec: ports: - port: 80 targetPort: 8080 selector: name: app --- apiVersion: networking.k8s.io/v1beta1 kind: Ingress # <<< metadata: name: my-ingress spec: rules: - http: paths: - backend: serviceName: app servicePort: 80 path: /
التعريف طويل جدًا ، ومن السهل التورط في كيفية ارتباط المكونات ببعضها البعض.
على سبيل المثال:
- متى يجب أن تستخدم المنفذ 80 ، ومتى - 8080؟
- هل يجب علي إنشاء منفذ جديد لكل خدمة حتى لا تتعارض؟
- هل أسماء الملصقات مهمة؟ يجب أن تكون هي نفسها في كل مكان؟
قبل التركيز على تصحيح الأخطاء ، دعنا نتذكر كيف ترتبط المكونات الثلاثة ببعضها البعض. لنبدأ بالنشر والخدمة.
اتصال Deployment'a و Service'a
سوف تفاجأ ، لكن عمليات النشر والخدمة غير متصلة بأي شكل من الأشكال. بدلاً من ذلك ، تشير الخدمة مباشرةً إلى قرون تجاوز النشر.
وبالتالي ، نحن مهتمون بكيفية ارتباط القرون والخدمات ببعضهم البعض. ثلاثة أشياء لنتذكرها:
- يجب أن يتطابق
selector
الخدمة مع علامة Pod واحدة على الأقل. - يجب أن يتطابق
targetPort
مع containerPort
. - خدمة
port
يمكن أن يكون أي شيء. يمكن لخدمات مختلفة استخدام نفس المنفذ لأن لديهم عناوين IP مختلفة.
يمثل المخطط التالي كل ما سبق في شكل رسوم بيانية:
1) تخيل أن الخدمة توجه حركة المرور إلى جراب معين:

2) عند إنشاء جراب ، يجب عليك تحديد
containerPort
لكل حاوية في القرون:

3) عند إنشاء الخدمة ، يجب عليك تحديد
port
و
targetPort
.
لكن من الذي يتصل بالحاوية؟
4) عن طريق
targetPort
. يجب أن تطابق
containerPort
.

5) لنفترض أن المنفذ 3000 مفتوح في الحاوية ، ثم يجب أن تكون قيمة
targetPort
هي نفسها.

في ملف YAML ، يجب أن تتطابق التسميات
ports
/
targetPort
:
apiVersion: apps/v1 kind: Deployment metadata: name: my-deployment labels: track: canary spec: selector: matchLabels: any-name: my-app template: metadata: labels: # <<< any-name: my-app # <<< spec: containers: - name: cont1 image: learnk8s/app:1.0.0 ports: - containerPort: 8080 # <<< --- apiVersion: v1 kind: Service metadata: name: my-service spec: ports: - port: 80 targetPort: 8080 # <<< selector: # <<< any-name: my-app # <<<
ماذا عن track: canary
في الجزء العلوي من قسم النشر؟ يجب أن تتطابق؟تشير هذه التسمية إلى النشر ، ولا تستخدمها الخدمة لتوجيه حركة المرور. بمعنى آخر ، يمكن حذفه أو تعيين قيمة مختلفة له.
ماذا عن محددات matchLabels
؟يجب أن يتطابق دائمًا مع ملصقات Pod ، حيث يتم استخدامه بواسطة Deployment لتتبع السنفات.
لنفترض أنك أجريت التعديلات الصحيحة. كيفية التحقق منها؟يمكنك التحقق من الملصق من خلال الأمر التالي:
kubectl get pods --show-labels
أو ، إذا كانت القرون تنتمي إلى العديد من التطبيقات:
kubectl get pods --selector any-name=my-app --show-labels
حيث
any-name=my-app
هو
any-name: my-app
label.
هل هناك أي صعوبات؟يمكنك الاتصال جراب! للقيام بذلك ، استخدم الأمر
port-forward
في kubectl. يتيح لك الاتصال بالخدمة والتحقق من الاتصال.
kubectl port-forward service/<service name> 3000:80
هنا:
service/<service name>
- اسم الخدمة ؛ في حالتنا هو my-service
.- 3000 - المنفذ الذي تريد فتحه على الكمبيوتر ؛
- 80 - منفذ محدد في مجال
port
الخدمة.
إذا تمكنت من إنشاء اتصال ، فإن الإعدادات صحيحة.
إذا تعذر إنشاء الاتصال ، فهناك مشكلة في التسميات أو المنافذ غير متطابقة.
اتصال الخدمة والدخول
تتعلق الخطوة التالية في توفير الوصول إلى التطبيق بتكوين الدخول. يجب أن يعرف الإدخال كيفية العثور على الخدمة ، ثم ابحث عن الحاضرات وتوجيه حركة المرور إليها. دخول يجد الخدمة المطلوبة بالاسم والمنفذ المفتوح.
في وصف الدخول والخدمة ، يجب أن تتطابق معلمتان:
- يجب أن يتطابق
servicePort
في Ingress مع معلمة port
في الخدمة ؛ - يجب أن يتطابق
serviceName
في serviceName
مع حقل name
في الخدمة.
يلخص الرسم البياني التالي اتصال المنافذ:
1) كما تعلمون بالفعل ، تستمع الخدمة على
port
معين:

2) الدخول يحتوي على معلمة تسمى
servicePort
:

3) يجب أن تتطابق هذه المعلمة (
servicePort
) دائمًا مع
port
في تعريف الخدمة:

4) إذا تم تحديد المنفذ 80 في الخدمة ، فيجب أن تكون
servicePort
أيضًا 80:

في الممارسة العملية ، تحتاج إلى الانتباه إلى الأسطر التالية:
apiVersion: v1 kind: Service metadata: name: my-service # <<< spec: ports: - port: 80 # <<< targetPort: 8080 selector: any-name: my-app --- apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: my-ingress spec: rules: - http: paths: - backend: serviceName: my-service # <<< servicePort: 80 # <<< path: /
كيفية التحقق مما إذا كان الدخول يعمل؟يمكنك استخدام الأسلوب مع
kubectl port-forward
، ولكن بدلاً من الخدمة ، تحتاج إلى الاتصال بوحدة التحكم في Ingress.
تحتاج أولاً إلى معرفة اسم الجراب باستخدام وحدة التحكم في الدخول:
kubectl get pods --all-namespaces NAMESPACE NAME READY STATUS kube-system coredns-5644d7b6d9-jn7cq 1/1 Running kube-system etcd-minikube 1/1 Running kube-system kube-apiserver-minikube 1/1 Running kube-system kube-controller-manager-minikube 1/1 Running kube-system kube-proxy-zvf2h 1/1 Running kube-system kube-scheduler-minikube 1/1 Running kube-system nginx-ingress-controller-6fc5bcc 1/1 Running
حدد موقع جراب Ingress (قد يشير إلى مساحة اسم مختلفة) ثم قم بتشغيل الأمر description لمعرفة أرقام المنافذ:
kubectl describe pod nginx-ingress-controller-6fc5bcc \ --namespace kube-system \ | grep Ports Ports: 80/TCP, 443/TCP, 18080/TCP
أخيرًا ، اتصل بالجراب:
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system
الآن في كل مرة ترسل فيها طلبًا إلى منفذ 3000 على الكمبيوتر ، سيتم إعادة توجيهه إلى المنفذ 80 من الحافظة باستخدام وحدة التحكم في الدخول. بالانتقال إلى
http: // localhost: 3000 ، سترى الصفحة التي أنشأها التطبيق.
ملخص الميناء
دعونا نتذكر مرة أخرى المنافذ والعلامات التي يجب أن تتطابق:
- يجب أن يتطابق محدد في تعريف الخدمة مع التسمية pod.
- يجب أن يتطابق هدف
targetPort
في تعريف الخدمة مع containerPort
targetPort
الحاوية داخل الحافظة ؛ port
في تعريف الخدمة يمكن أن يكون أي شيء. يمكن لخدمات مختلفة استخدام نفس المنفذ لأن لديهم عناوين IP مختلفة ؛- يجب أن يتطابق
servicePort
Ingress مع port
في تعريف الخدمة ؛ - يجب أن يتطابق اسم الخدمة مع الحقل
serviceName
في Ingress.
للأسف ، لا يكفي معرفة كيفية هيكلة تكوين YAML بشكل صحيح.
ماذا يحدث عندما يحدث خطأ ما؟ربما لا يبدأ جراب أو تعطل.
3 خطوات لاستكشاف أخطاء فشل التطبيق في Kubernetes
قبل تصحيح النشر ، يجب أن يكون لديك فهم جيد لكيفية عمل Kubernetes.
نظرًا لوجود ثلاثة مكونات في كل تطبيق تم تنزيله على K8s ، فيجب تصحيحها بترتيب معين ، بدءًا من الأسفل.
- تحتاج أولاً إلى التأكد من أن القرون تعمل ، ثم ...
- تحقق مما إذا كانت الخدمة توفر حركة المرور إلى السنفات ، ثم ...
- تحقق مما إذا تم تكوين Ingress بشكل صحيح.
عرض مرئي:
1) بدء البحث عن المشاكل يجب أن يكون من الأسفل. تأكد أولاً من أن القرون لها أوضاع
Ready
Running
:

2) إذا كانت القرون
Ready
، يجب عليك معرفة ما إذا كانت الخدمة توزع حركة المرور بين القرون:

3) أخيرًا ، تحتاج إلى تحليل العلاقة بين الخدمة والدخول:

1. تشخيص القرون
في معظم الحالات ، تكون المشكلة مع جراب. تأكد من القرون
Ready
Running
. يمكنك التحقق من ذلك باستخدام الأمر:
kubectl get pods NAME READY STATUS RESTARTS AGE app1 0/1 ImagePullBackOff 0 47h app2 0/1 Error 0 47h app3-76f9fcd46b-xbv4k 1/1 Running 1 47h
في إخراج الأمر أعلاه ، يتم سرد الجراب الأخير باسم
Running
Ready
، ولكن بالنسبة للاثنين الأخريين فإنه ليس كذلك.
كيف نفهم ما الخطأ الذي حدث؟هناك أربعة أوامر مفيدة لتشخيص القرون:
kubectl logs < pod'>
يسمح لك باستخراج السجلات من حاويات في جراب.kubectl describe pod < pod'>
يتيح لك عرض قائمة بالأحداث المرتبطة بالجراب ؛kubectl get pod < pod'>
يسمح لك بالحصول على تكوين YAML للجراب المخزن في Kubernetes ؛- يسمح لك
kubectl exec -ti < pod'> bash
بتشغيل صدفة أوامر تفاعلية في إحدى حاويات pod
أي واحد للاختيار؟الحقيقة هي أنه لا يوجد فريق عالمي. مزيج من هذه ينبغي أن تستخدم.
مشاكل جراب المشتركة
هناك نوعان رئيسيان من أخطاء جراب: أخطاء بدء التشغيل وأخطاء وقت التشغيل.
أخطاء بدء التشغيل:
ImagePullBackoff
ImageInspectError
ErrImagePull
ErrImageNeverPull
RegistryUnavailable
InvalidImageName
أخطاء وقت التشغيل:
CrashLoopBackOff
RunContainerError
KillContainerError
VerifyNonRootError
RunInitContainerError
CreatePodSandboxError
ConfigPodSandboxError
KillPodSandboxError
SetupNetworkError
TeardownNetworkError
بعض الأخطاء هي أكثر شيوعا من غيرها. فيما يلي بعض الأخطاء الشائعة وكيفية إصلاحها.
ImagePullBackOff
يظهر هذا الخطأ عندما يتعذر على Kubernetes الحصول على صورة لأحد حاويات pod. فيما يلي الأسباب الثلاثة الأكثر شيوعًا لهذا:
- تم تحديد اسم الصورة بشكل غير صحيح - على سبيل المثال ، ارتكبت خطأ فيه ، أو كانت الصورة غير موجودة ؛
- يتم تحديد علامة غير موجودة للصورة ؛
- يتم تخزين الصورة في سجل خاص ، ولا تتمتع Kubernet بسلطة الوصول إليها.
يسهل التخلص من أول سببين - فقط قم بإصلاح اسم الصورة والعلامة. في حالة الأخير ، تحتاج إلى إدخال بيانات الاعتماد الخاصة بالسجل الخاص في Secret وإضافة روابط إليه في ملفات. تحتوي وثائق Kubernetes
على مثال عن كيفية القيام بذلك.
CrashLoopBackOff
سيقوم Kubenetes برمي خطأ CrashLoopBackOff إذا تعذر بدء تشغيل الحاوية. يحدث هذا عادة عندما:
- يوجد خطأ في التطبيق يمنعه من بدء التشغيل ؛
- تم تكوين الحاوية بشكل غير صحيح ؛
- فشل اختبار Liveness عدة مرات.
يجب أن تحاول الوصول إلى السجلات من الحاوية لمعرفة سبب فشلها. إذا كان الوصول إلى السجلات صعبًا ، نظرًا لإعادة تشغيل الحاوية بسرعة كبيرة ، يمكنك استخدام الأمر التالي:
kubectl logs <pod-name> --previous
يعرض رسائل خطأ من التناسخ الحاوية السابقة.
RunContainerError
يحدث هذا الخطأ عندما تفشل الحاوية في البدء. إنه يتوافق مع اللحظة التي سبقت إطلاق التطبيق. عادة ما يكون السبب هو التكوين غير الصحيح ، على سبيل المثال:
- محاولة تحميل وحدة تخزين غير موجودة ، مثل ConfigMap أو Secrets ؛
- محاولة تحميل وحدة تخزين للقراءة فقط للقراءة والكتابة.
kubectl describe pod <pod-name>
مناسب تمامًا لتحليل مثل هذه الأخطاء.
القرون في انتظار
بعد الخلق ، يبقى الملف في حالة
Pending
.
لماذا يحدث هذا؟فيما يلي الأسباب المحتملة (أفترض أن المجدول يعمل بشكل جيد):
- لا تحتوي المجموعة على موارد كافية ، مثل معالجة الطاقة والذاكرة ، لتشغيل الأداة.
- يتم تثبيت كائن
ResourceQuota
في مساحة الاسم المطابقة وسيؤدي إنشاء pod إلى تجاوز مساحة الاسم الحصة النسبية. - قرنة مرتبطة Pending
PersistentVolumeClaim
.
في هذه الحالة ، يوصى باستخدام أمر
kubectl describe
والتحقق من قسم
Events
:
kubectl describe pod <pod name>
في حالة وجود أخطاء متعلقة بـ
ResourceQuotas
، يوصى بعرض سجلات نظام المجموعة باستخدام الأمر
kubectl get events --sort-by=.metadata.creationTimestamp
القرون ليست جاهزة
إذا كانت الحافظة مدرجة على أنها
Running
، ولكنها ليست في حالة
Ready
، فإن
مسبار الاستعداد غير ناجح.
عندما يحدث هذا ، لا تتصل pod بالخدمة ، ولا تتدفق حركة المرور عليها. فشل اختبار الاستعداد بسبب مشكلات التطبيق. في هذه الحالة ، للعثور على الخطأ ، تحتاج إلى تحليل قسم
Events
في إخراج أمر
kubectl describe
.
2. تشخيص الخدمات
إذا تم سرد القرون على أنها
Running
Ready
، ولكن لا يوجد حتى الآن أي استجابة من التطبيق ، يجب عليك التحقق من إعدادات الخدمة.
وتشارك الخدمات في توجيه حركة المرور إلى القرون اعتمادا على التسميات الخاصة بهم. لذلك ، فإن أول شيء فعله هو التحقق من عدد القرون التي تعمل مع الخدمة. للقيام بذلك ، يمكنك التحقق من نقاط النهاية في الخدمة:
kubectl describe service <service-name> | grep Endpoints
نقطة النهاية هي زوج من قيم النموذج
<IP-:>
، ويجب أن يكون هناك زوج واحد على الأقل في الإخراج (أي ، جراب واحد على الأقل يعمل مع الخدمة).
إذا كان قسم
Endpoins
فارغًا ، فمن الممكن وجود خيارين:
- لا توجد حافظات تحتوي على الملصق الصحيح (تلميح: تحقق من تحديد مساحة الاسم بشكل صحيح) ؛
- يوجد خطأ في تسميات الخدمة في المحدد.
إذا رأيت قائمة
targetPort
النهاية ، ولكن لا يزال يتعذر عليك الوصول إلى التطبيق ، فإن الجاني المحتمل هو الخطأ في
targetPort
في وصف الخدمة.
كيفية التحقق من الخدمة للخدمة؟بغض النظر عن نوع الخدمة ، يمكنك استخدام الأمر
kubectl port-forward
للاتصال به:
kubectl port-forward service/<service-name> 3000:80
هنا:
<service-name>
- اسم الخدمة ؛- 3000 - المنفذ الذي تفتحه على الكمبيوتر ؛
- 80 - منفذ على جانب الخدمة.
3. دخول التشخيص
إذا قرأت هذا المكان ، فقم بما يلي:
- يتم سرد القرون كما
Running
Ready
. - توزع الخدمة بنجاح حركة المرور بين القرون.
ومع ذلك ، لا يزال يتعذر عليك "الوصول" إلى التطبيق.
هذا يعني أنه ، على الأرجح ، تم تكوين وحدة تحكم Ingress بشكل غير صحيح. نظرًا لأن وحدة تحكم Ingress هي مكون تابع لجهة خارجية في الكتلة ، فهناك العديد من طرق تصحيح الأخطاء وفقًا لنوعها.
ولكن قبل اللجوء إلى أدوات خاصة لتهيئة Ingress ، يمكنك القيام بشيء بسيط للغاية. يستخدم
serviceName
و
servicePort
للاتصال بالخدمة. يجب عليك التحقق من تكوينها بشكل صحيح. يمكنك القيام بذلك باستخدام الأمر:
kubectl describe ingress <ingress-name>
إذا كان العمود
Backend
فارغًا ، فهناك احتمال كبير لحدوث خطأ في التكوين. إذا كانت الخلفية موجودة في مكانها ، ولكن لا يوجد حتى الآن إمكانية الوصول إلى التطبيق ، فقد تكون المشكلة متعلقة بـ:
- دخول إعدادات الوصول من الإنترنت العام ؛
- إعدادات إمكانية الوصول إلى نظام المجموعة من الإنترنت العام.
يمكنك تحديد مشاكل البنية التحتية من خلال الاتصال مباشرة بقرنة Ingress. للقيام بذلك ، ابحث أولاً عن وحدة التحكم في Ingress (قد تكون في مساحة اسم مختلفة):
kubectl get pods --all-namespaces NAMESPACE NAME READY STATUS kube-system coredns-5644d7b6d9-jn7cq 1/1 Running kube-system etcd-minikube 1/1 Running kube-system kube-apiserver-minikube 1/1 Running kube-system kube-controller-manager-minikube 1/1 Running kube-system kube-proxy-zvf2h 1/1 Running kube-system kube-scheduler-minikube 1/1 Running kube-system nginx-ingress-controller-6fc5bcc 1/1 Running
استخدم أمر صف لتعيين المنفذ:
kubectl describe pod nginx-ingress-controller-6fc5bcc --namespace kube-system \ | grep Ports
أخيرًا ، اتصل بالجراب:
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system
سيتم الآن إعادة توجيه جميع الطلبات الخاصة بمنفذ 3000 على الكمبيوتر إلى المنفذ 80 pod.
هل تعمل الآن؟- إذا كان الأمر كذلك ، فإن المشكلة تكمن في البنية التحتية. من الضروري معرفة بالضبط كيف يتم توجيه حركة المرور إلى الكتلة.
- إذا لم يكن كذلك ، فإن المشكلة تكمن في وحدة التحكم في الدخول.
إذا لم تتمكن من تشغيل جهاز التحكم في الدخول ، فستضطر إلى تصحيحه.
هناك العديد من أنواع التحكم في الدخول. الأكثر شيوعًا هي Nginx و HAProxy و Traefik وما إلى ذلك
(لمزيد من المعلومات حول الحلول الحالية ، راجع مراجعتنا - الترجمة تقريبًا.) يجب
عليك استخدام دليل استكشاف الأخطاء وإصلاحها في وثائق وحدة التحكم المقابلة. نظرًا لأن
Ingress Nginx هو جهاز التحكم في Ingress الأكثر شعبية ، فقد قمنا بتضمين بعض النصائح حول حل المشكلات ذات الصلة في هذه المقالة.
تصحيح على وحدة تحكم Nginx Ingress
يحتوي مشروع Ingress-nginx على
مكون إضافي رسمي
لـ kubectl . يمكن استخدام الأمر
kubectl ingress-nginx
من أجل:
- تحليل السجلات ، والواجهات الخلفية ، والشهادات ، وما إلى ذلك ؛
- اتصال الدخول ؛
- دراسة التكوين الحالي.
سوف تساعدك الفرق الثلاثة التالية في هذا:
kubectl ingress-nginx lint
- يتحقق nginx.conf
؛kubectl ingress-nginx backend
- يفحص الخلفية (يشبه kubectl describe ingress <ingress-name>
) ؛kubectl ingress-nginx logs
- فحص السجلات.
يرجى ملاحظة أنه في بعض الحالات قد يكون من الضروري تحديد مساحة الاسم الصحيحة لجهاز التحكم في الدخول باستخدام -
--namespace <name>
العلامة.
ملخص
يمكن أن يشكل تشخيص Kubernetes مهمة شاقة إذا كنت لا تعرف من أين تبدأ. يجب دائمًا معالجة المشكلة وفقًا للمبدأ من القاعدة إلى القمة: ابدأ بالقرون ، ثم انتقل إلى الخدمة ودخول. يمكن تطبيق أساليب تصحيح الأخطاء الموضحة في المقالة على كائنات أخرى ، مثل:
- الخمول وظائف و CronJobs.
- StatefulSets و DaemonSets.
بفضل
Gergely Risko و
Daniel Weibel و
Charles Christyraj على التعليقات
والإضافات القيمة.
PS من المترجم
اقرأ أيضًا في مدونتنا: