شبكات Kubernetes والتخزين

Ingress ووحدات تحكم Ingress

18 دقيقة الدرس 3 من 31

Ingress ووحدات تحكم Ingress

تُنشئ خدمة Kubernetes من نوع LoadBalancer موزِّع تحميل سحابيًا لكل خدمة على حدة. عند عشر خدمات، يعني ذلك عشرة عناوين IP عامة، وعشرة فواتير شهرية، وعشرة شهادات TLS لتجديدها. تُشغِّل الكتل الإنتاجية الحقيقية عشرات إلى مئات أحمال عمل HTTP. Ingress هو كائن واجهة برمجة Kubernetes الذي يحل هذه المشكلة: نقطة دخول واحدة للكتلة، مع قواعد توجيه L7 (HTTP/HTTPS) تُوزِّع الحركة إلى الخدمات الصحيحة بناءً على اسم المضيف والمسار — دون موارد سحابية إضافية لكل خدمة.

واجهة Ingress API مقابل وحدة تحكم Ingress

كائن Ingress API هو مجرد إعلان تهيئة مُخزَّن في etcd — لا يفعل شيئًا بمفرده. يقوم بالعمل الفعلي Ingress Controller: نشر داخل الكتلة يراقب كائنات Ingress ويُبرمج وكيلًا عكسيًا حقيقيًا وفقًا لذلك. أكثر وحدتَي التحكم انتشارًا هما:

  • ingress-nginx (يُصونه مجتمع Kubernetes) — يُغلِّف NGINX؛ الاختيار الافتراضي للكتل ذاتية الإدارة وإعدادات EKS/GKE الأساسية.
  • AWS Load Balancer Controller — يُنشئ موزِّع تحميل تطبيقات (ALB) لكل Ingress أو يُشاركه عبر Ingresses باستخدام ربط مجموعة الأهداف؛ إلزامي على EKS عند الحاجة إلى WAF أو إدارة شهادات AWS الأصلية.

وحدات التحكم الأخرى تشمل Traefik وHAProxy Ingress وContour. مواصفة Ingress مستقلة عن وحدة التحكم: تعمل نفس YAML (في معظمها) عبر وحدات التحكم؛ يُعبَّر عن السلوك الخاص بكل وحدة تحكم عبر annotations على كائن Ingress.

الفكرة الجوهرية: كائن Ingress API هو دفتر قواعد. وحدة تحكم Ingress هي المُنفِّذ الذي يقرأ ذلك الدفتر ويُعيد تهيئة NGINX (أو ALB) في الوقت الفعلي. تثبيت Kubernetes بدون Ingress Controller ثم إنشاء كائنات Ingress لا يُنتج أي أثر — خطأ شائع جدًا للمبتدئين.

تثبيت ingress-nginx

في كتلة حقيقية، يُثبَّت ingress-nginx عبر Helm. ينشئ المخطط نشر وحدة التحكم، وخدمة من نوع LoadBalancer (موزِّع التحميل السحابي الوحيد)، وجميع أذونات RBAC اللازمة.

# إضافة مستودع Helm لـ ingress-nginx helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update # التثبيت في مساحة اسم مستقلة؛ الاحتفاظ بنسختين لضمان التوفر العالي helm install ingress-nginx ingress-nginx/ingress-nginx \ --namespace ingress-nginx \ --create-namespace \ --set controller.replicaCount=2 \ --set controller.resources.requests.cpu=100m \ --set controller.resources.requests.memory=128Mi # التحقق من pod وحدة التحكم وخدمة LoadBalancer (الحصول على IP/hostname الخارجي) kubectl -n ingress-nginx get pods kubectl -n ingress-nginx get svc ingress-nginx-controller

كتابة مانيفست Ingress

Ingress بسيط يوجِّه مضيفَين افتراضيَّين إلى خدمتين مختلفتين:

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: store-ingress namespace: production annotations: # إخبار Kubernetes بأي وحدة تحكم تتولى هذا Ingress kubernetes.io/ingress.class: "nginx" # إعادة توجيه HTTP إلى HTTPS تلقائيًا nginx.ingress.kubernetes.io/ssl-redirect: "true" # زيادة مهلة الوكيل للاستدعاءات الطويلة nginx.ingress.kubernetes.io/proxy-read-timeout: "120" spec: tls: - hosts: - api.example.com - www.example.com secretName: example-tls # يجب أن يكون Secret TLS في نفس مساحة الاسم rules: - host: api.example.com http: paths: - path: /v1 pathType: Prefix backend: service: name: api-service port: number: 80 - host: www.example.com http: paths: - path: / pathType: Prefix backend: service: name: frontend-service port: number: 80

الحقول الأساسية لفهمها:

  • spec.tls — يُفعِّل HTTPS. تُنهي وحدة التحكم TLS هنا وتُعيد توجيه HTTP العادي إلى خدمة الخلفية.
  • spec.rules[*].host — مطابقة اسم مضيف دقيقة؛ تستخدم وحدة التحكم رأس HTTP Host لاختيار القاعدة.
  • pathType: Prefix — يطابق أي مسار يبدأ بالنص المحدد. Exact يطابق المسار الحرفي فقط. ImplementationSpecific يُفوِّض التفسير لوحدة التحكم.
  • annotations — المنفذ لكل ما هو خارج مواصفة Ingress: تحديد المعدل، رأسيات CORS، المصادقة، قواعد WAF، أوزان الكناري، وما إلى ذلك.

إنهاء TLS بعمق

ينتهي TLS الخاص بـ Ingress عند وحدة التحكم. يجب أن يحتوي Secret على tls.crt وtls.key. الطريقة الأكثر احترافية في الإنتاج هي cert-manager، الذي يتكامل مع Let's Encrypt ويُجدِّد الشهادات تلقائيًا قبل انتهاء صلاحيتها:

# تثبيت cert-manager (يُدير دورة حياة شهادات TLS) helm repo add jetstack https://charts.jetstack.io helm repo update helm install cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --set crds.enabled=true # إنشاء ClusterIssuer لـ Let's Encrypt الإنتاجي cat <<EOF | kubectl apply -f - apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: ops@example.com privateKeySecretRef: name: letsencrypt-prod-key solvers: - http01: ingress: class: nginx EOF # ثم أضف هذا التعليق التوضيحي إلى Ingress لتفعيل إصدار الشهادة تلقائيًا: # cert-manager.io/cluster-issuer: "letsencrypt-prod" # سيُنشئ cert-manager ويُحدِّث Secret تلقائيًا.
ممارسة إنتاجية: لا تُودِع مفاتيح TLS الخاصة في git قط. استخدم cert-manager مع Let's Encrypt لأحمال العمل المواجهة للإنترنت، أو AWS ACM / شهادات GCP المُدارة للكتل السحابية المُدارة. اضبط nginx.ingress.kubernetes.io/ssl-redirect: "true" عالميًا حتى لا يُخدَّم HTTP أبدًا في الإنتاج.

مخطط تدفق حركة Ingress

Ingress L7 Traffic Flow: Client to Pod via Ingress Controller Client Browser/CLI HTTPS Cloud LB Service type: LoadBalancer TCP:443 Ingress Controller (NGINX Pod) TLS termination Host/path routing Reads Ingress rules api.example.com www.example.com api-service ClusterIP frontend-svc ClusterIP api Pod web Pod cert-manager Auto-renews TLS Secret
تدفق توجيه L7: موزِّع تحميل سحابي واحد يُعيد توجيه الحركة إلى وحدة تحكم Ingress، التي تُنهي TLS (عبر cert-manager) وتُوجِّه بناءً على اسم المضيف/المسار إلى خدمة ClusterIP الصحيحة ثم إلى Pods.

أنماط الفشل في الإنتاج

فهم ما يتعطل في الإنتاج — ولماذا — يُميِّز المهندسين الذين يُهيِّئون Ingress عمَّن يُشغِّلونه:

  • غياب ingressClassName / التعليق التوضيحي: إذا أدَّرت وحدتَي تحكم (nginx وALB في آنٍ واحد) وأغفلت محدِّد الفئة، فلن تطالب أيٌّ منهما بـ Ingress. لن تصل الحركة أبدًا. اضبط دائمًا spec.ingressClassName: nginx أو ما يعادله.
  • عدم تطابق منفذ الخدمة: تُشير خلفية Ingress إلى المنفذ 80 لكن الخدمة تُعرِض المنفذ 8080. تُعيد وحدة التحكم 503 بصمت. تحقَّق دائمًا بـ kubectl describe ingress <name> — ابحث عن Endpoints في الإخراج؛ إذا كان <none>، فتعيين الخلفية خاطئ.
  • Secret TLS في مساحة اسم خاطئة: يجب أن يكون Ingress وSecret tls.secretName في نفس مساحة الاسم. يفشل الإشارة عبر مساحات الأسماء بصمت، تاركًا وحدة التحكم تُقدِّم شهادة موقَّعة ذاتيًا — أسوأ أنواع الفشل لأن HTTPS يعمل، لكن بشهادة خاطئة.
  • وحدة التحكم غير متوفرة بعالية: نشر ingress-nginx بنسخة واحدة يعني أن إعادة تشغيل Pod أو تحديث متجدِّد لوحدة التحكم يُسقط كل الحركة الواردة لثوانٍ. شغِّل دائمًا نسختين على الأقل وهيِّئ PodDisruptionBudget بـ minAvailable: 1.
  • خطأ إملائي في التعليق التوضيحي: تُقرَأ تعليقات NGINX كنصوص خام — خطأ مثل nginx.ingress.kubernetes.io/ssl-redirct يُتجاهَل دون إشعار بخطأ. تحقَّق من مانيفستك بـ kubectl apply --dry-run=server وراجع سجلات وحدة التحكم بعد التطبيق.
مأزق إنتاجي — 413 Request Entity Too Large: الحد الافتراضي لـ NGINX client_max_body_size هو 1 ميجابايت. ترفع عمليات الملفات والحمولات الكبيرة هذا الحد فورًا. اضبط التعليق التوضيحي nginx.ingress.kubernetes.io/proxy-body-size: "50m" على Ingress لأي خدمة تقبل ملفات مرفوعة، أو تجاوزه عالميًا في ConfigMap وحدة التحكم. تشخيص هذا محبِط لأن الخطأ يظهر عند العميل لا في سجلات التطبيق.

فحص صحة Ingress

سير عمل من ثلاثة أوامر لتشخيص أي مشكلة في Ingress:

# 1. رؤية جدول التوجيه الذي بنته وحدة التحكم وما إذا كانت الخلفيات قد حُلَّت kubectl describe ingress store-ingress -n production # ابحث عن: قسم Rules (المضيفون/المسارات صحيحة؟)، Default backend، Endpoints تحت كل خدمة # 2. تتبع سجلات وحدة التحكم — كل طلب يُسجَّل مع اختيار upstream kubectl -n ingress-nginx logs -l app.kubernetes.io/name=ingress-nginx --tail=50 # 3. التحقق من وجود Secret TLS وصحة تنسيقه kubectl -n production get secret example-tls -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -subject -dates

Ingress + ingress-nginx + cert-manager هو حزمة نقطة الدخول L7 القياسية في Kubernetes. في الدرس التالي ستتعرَّف على Gateway API — الخلف من الجيل التالي لـ Ingress الذي يحل قيوده في تعدد الإيجار والتعبيرية مع الحفاظ على نفس نية توجيه L7.