EduFlow

الوحدة 5 · التشغيل في الإنتاج

الحركة إلى الداخل والمشاكل إلى الخارج: Gateway API والتشخيص

22 دقراءة 4 داختر بحكمة

الدرس في لمحة

وجّه حركة HTTPS العامة إلى notes-api باستخدام Gateway API، وحصّن الـ Pods الخاصة به بـ securityContext، وشخّص الـ Pods المعطوبة بسرعة بالأوامر get وdescribe وlogs وevents وkubectl debug.

  1. 1إدخال حركة HTTP
  2. 2دليل التشخيص
  3. 3القطعة الأخيرة: الـ securityContext

لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.

شيئان يقفان بين notes-api والمستخدمين الحقيقيين. لا يمكن الوصول إليه من الإنترنت بعد، وحين ينكسر شيء في الثالثة فجرًا، تحتاج إلى معرفة ما هو خلال دقائق. هذا الدرس يغطّي الأمرين، وينتهي بإعدادات الأمان التي تكمل صورة الإنتاج.

إدخال حركة HTTP

‏Service من نوع LoadBalancer لكل تطبيق يصلح لخدمة واحدة. أما مع عشر خدمات، فأنت تدفع ثمن عشرة موازنات أحمال، وتدير عشر شهادات، والتوجيه حسب اسم المضيف أو المسار مستحيل. ما تريده نقطة دخول واحدة مشتركة توجّه طلبات HTTP إلى الـ Service الصحيح.

لسنوات كانت الإجابة Ingress. ما زال يعمل، لكن واجهة Ingress البرمجية مجمَّدة ولا تحصل على ميزات جديدة، والـ controller المجتمعي الواسع الانتشار ingress-nginx تقاعد في مارس 2026: لا إصدارات جديدة ولا إصلاحات أمنية. مشروع Kubernetes يوجّه العمل الجديد نحو Gateway API، المتاح رسميًا (GA) بالإصدار gateway.networking.k8s.io/v1. يُثبَّت كإضافة (الـ CRDs الخاصة به مع أداة تنفيذ (implementation)، مثل controller موازن الأحمال في منصّتك السحابية، أو Envoy Gateway، أو Cilium، أو Istio)، وكثير من الـ clusters المُدارة توفّره جاهزًا.

يقسّم Gateway API المهمّة حسب الأدوار:

  • GatewayClass: أي أداة تنفيذ تتولّى الحركة. يضبطه مرة واحدة من يشغّل الـ cluster.
  • Gateway: نقطة دخول فيها listeners ومنافذ وأسماء مضيفات وشهادات TLS. يملكها فريق المنصّة.
  • HTTPRoute: قواعد التوجيه لتطبيق واحد، مرتبطة بـ Gateway. يملكها فريق التطبيق.
مشغّل الـ cluster يختار الـ GatewayClass. الـ Gateway المسمّى public في الـ namespace ‏infra ينهي TLS على المنفذ 443. الـ HTTPRoute ‏notes-api في الـ namespace ‏notes يرتبط به ويرسل طلبات notes.skylane.example إلى الـ Service ‏notes-api، الذي يحوّلها إلى الـ Pods. GatewayClass مشغّل الـ cluster Gateway :443 فريق المنصّة HTTPRoute فريق notes Service Pods notes.skylane.example → notes-api:80
كل فريق يملك طبقته، والـ routes ترتبط بـ Gateway مشترك

الـ Gateway الخاص بفريق المنصّة، مرة واحدة لكل cluster:

infra/gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: public
  namespace: infra
spec:
  gatewayClassName: skylane-lb        # provided by your implementation
  listeners:
    - name: https
      protocol: HTTPS
      port: 443
      hostname: "*.skylane.example"
      tls:
        mode: Terminate
        certificateRefs:
          - name: skylane-wildcard-tls
      allowedRoutes:
        namespaces:
          from: All

والـ route الخاص بك، في الـ namespace ‏notes:

k8s/httproute.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: notes-api
  namespace: notes
spec:
  parentRefs:
    - name: public
      namespace: infra
  hostnames:
    - notes.skylane.example
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: notes-api
          port: 80

الأمر kubectl describe httproute notes-api يُظهر تحت Status هل قبل الـ Gateway هذا الـ route. وإذا كنت تنقل كائنات Ingress موجودة، فالأداة ingress2gateway تحوّلها، بما في ذلك كثير من annotations الخاصة بـ ingress-nginx.

دليل التشخيص

حين يسيء notes-api التصرّف، قاوم التخمين. اتّبع الترتيب نفسه في كل مرة، ودع كل خطوة تختار التالية:

Terminal
kubectl get pods -l app.kubernetes.io/name=notes-api
kubectl describe pod <pod>
kubectl logs <pod> --previous
kubectl events --for pod/<pod> --types=Warning

العمود STATUS يخبرك أين تنظر:

الحالة ماذا تعني أين تنظر
Pending لا يوجد node يستطيع استقبال الـ Pod ‏describe: أحداث مثل Insufficient cpu أو node selectors غير مطابقة
ImagePullBackOff لا يستطيع الـ kubelet سحب الـ image ‏describe: ‏tag خاطئ، أو بيانات اعتماد سحب مفقودة، أو معمارية خاطئة
CreateContainerConfigError مفتاح ConfigMap أو Secret مُشار إليه مفقود ‏describe يسمّي المفتاح
CrashLoopBackOff التطبيق يبدأ ويخرج، مرارًا ‏logs --previous، مع رمز الخروج في describe ‏(137 = نفاد ذاكرة أو قتل)
Running مع 0/1 جاهز الـ readiness probe يفشل ‏describe يُظهر إخفاقات الـ probe؛ تحقّق مما يعتمد عليه /readyz

إذا كانت الـ Pods سليمة لكن الطلبات تفشل، فاعمل من الداخل إلى الخارج: ‏kubectl get endpointslices -l kubernetes.io/service-name=notes-api (الفراغ يعني مشكلة في الـ selector أو الجاهزية)، ثم حالة الـ route، ثم الـ Gateway.

الـ images من نوع distroless لا تحتوي على shell، فلا يفيد kubectl exec. ألحِق ephemeral debug container (container تشخيص مؤقتًا) بدلًا من ذلك. ينضمّ إلى الـ network namespace الخاصة بالـ Pod، ومع --target يستطيع رؤية عمليات التطبيق أيضًا:

Terminal
kubectl debug -it <pod> --image=busybox:1.37 --target=api
# inside: nslookup notes-db, wget -qO- localhost:3000/readyz, ps

القطعة الأخيرة: الـ securityContext

في الدرس 2.2 شغّلت الـ image كمستخدم غير root ووعدت بفرض ذلك في الـ cluster. ها هو ذا، على container ‏notes-api:

k8s/deployment.yaml
          securityContext:
            runAsNonRoot: true
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities:
              drop: ["ALL"]

الحقل runAsNonRoot يجعل الـ kubelet يرفض بدء الـ container إذا كانت الـ image ستعمل بـ UID 0. إنه يفحص UID رقميًا، لذا فإن image يكون فيها USER اسمًا مثل node تفشل بـ CreateContainerConfigError؛ اكتب USER 1000 في الـ Dockerfile أو أضف runAsUser: 1000 هنا. وأعطِ التطبيق volume من نوع emptyDir في /tmp إن احتاج إلى مساحة مؤقتة تحت نظام ملفات جذري للقراءة فقط.

بهذا يكتمل مسار notes-api: بناء multi-stage يستفيد من الـ cache، وimage صغيرة بمستخدم غير root مثبّتة بالـ digest ومفحوصة، وبيئة Compose للتطوير، وDeployment مع probes وموارد وتوسّع تلقائي وrollouts آمنة وroute عبر Gateway وsecurity context محصّن. كل واحد من هذه الإعدادات موجود في الملف لأن حادثًا ما علّم أحدهم أنه ضروري. حافظ على هذه العادة: حين ينكسر شيء، اسأل أي إعداد كان سيجعله مستحيلًا، وأضِفه.

أهم النقاط

  • يقسّم Gateway API الحركة الخارجية إلى GatewayClass (أداة التنفيذ)، وGateway (نقطة الدخول وTLS)، وHTTPRoute (قواعد التوجيه لتطبيق ما)، فيملك كلٌّ من فريق المنصّة وفريق التطبيق جزأه.
  • الـ Ingress ما زال يعمل لكنه مجمَّد، والـ controller المجتمعي ingress-nginx تقاعد في مارس 2026؛ والإعدادات الجديدة يجب أن تستخدم Gateway API.
  • اقرأ حالة الـ Pod أولًا، ثم kubectl describe للأحداث، ثم kubectl logs --previous للانهيارات؛ فالحالة تخبرك بالأداة التي تلجأ إليها.
  • الأمر kubectl debug --target يُلحق container مؤقتًا فيه أدوات بـ Pod يعمل، وهكذا تفحص الـ images من نوع distroless.
  • ‏Pod الإنتاج يعمل كمستخدم غير root، دون تصعيد للصلاحيات، مع نظام ملفات جذري للقراءة فقط، وبعد إسقاط كل الـ capabilities.

قراءات إضافية

تحقّق من فهمك

4 أسئلة

السؤال 1 من 4

يشغّل فريق المنصّة لديكم Gateway مشتركًا في الـ namespace ‏infra. ماذا تنشئ أنت، بصفتك فريق notes-api، لعرض notes.skylane.example؟

السؤال 2 من 4

‏Pod يُظهر الحالة ImagePullBackOff. ما الخطوة التالية الأكثر فائدة؟

السؤال 3 من 4

‏notes-api في حالة CrashLoopBackOff. والأمر kubectl logs <pod> لا يعرض إلا سطرًا أو اثنين من مخرجات البدء. ماذا تشغّل؟

السؤال 4 من 4

الـ image الخاصة بـ notes-api من نوع distroless، فيفشل kubectl exec -it <pod> -- sh. كيف تتحقّق من تحليل DNS من داخل الـ Pod؟

تدريب

اختر بحكمة

الخطوة الأولى لكل عَرَض

أنت في المناوبة على notes-api. لكل عَرَض أدناه، يقترح زميلك خطوة أولى. اختر كل ربط تكون فيه الخطوة الأولى صحيحة.

الخطوة الأولى لكل عَرَض