شبكة الخدمات: Istio وLinkerd

معمارية Istio

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

معمارية Istio

تُعدّ Istio المنظومة الأكثر اكتمالاً من حيث الميزات بين شبكات الخدمات المستخدمة اليوم في بيئات الإنتاج. تنقسم معمارتها عمداً إلى مستويين: مستوى التحكم ومستوى البيانات، بهدف فصل قرارات السياسة عن تنفيذ حركة المرور. فهم هذا الفصل هو المدخل الأساسي لتشخيص كل عطل Istio ستواجهه في الإنتاج.

مستوى التحكم: istiod

قبل Istio 1.5، كان مستوى التحكم يتكوّن من ثلاثة عمليات منفصلة: Pilot لإعدادات xDS، وCitadel لإدارة الشهادات، وGalley للتحقق من صحة الإعدادات. في الإصدار 1.5 اندمجت جميعها في ملف تنفيذي واحد يُسمى istiod. يعمل كـ Deployment في istio-system ويؤدي ثلاث مسؤوليات رئيسية:

  • خادم xDS (نظام Pilot الفرعي): يراقب خادم Kubernetes API بحثاً عن Services وEndpoints وVirtualServices وDestinationRules وغيرها، ويُترجمها إلى استجابات xDS (Envoy Discovery Service) ويبثّها لكل sidecar عبر اتصالات gRPC طويلة الأمد. الواجهات الأربع الرئيسية هي LDS للمستمعين، وRDS للمسارات، وCDS للعناقيد، وEDS للنقاط النهائية.
  • المرجع الجذري للشهادات (نظام Citadel الفرعي): يُصدر شهادات X.509 متوافقة مع معيار SPIFFE لكل عبء عمل. يُقدّم كل sidecar طلب CSR عند بدء التشغيل؛ يوقّعه istiod ويعيد الشهادة والمفتاح الخاص. تتجدد الشهادات تلقائياً (مدة الصلاحية الافتراضية 24 ساعة مع هامش تجديد 30 دقيقة).
  • التحقق من الإعدادات (نظام Galley الفرعي): يشغّل Admission Webhook يرفض موارد CRD المُشوَّهة قبل وصولها لخادم API. لهذا يفشل تطبيق VirtualService بصياغة خاطئة فوراً بدلاً من أن يكسر حركة المرور بصمت وقت التشغيل.

في عمليات نشر بمقياس Google، يعمل istiod عادةً بثلاث نسخ مع PodDisruptionBudget بقيمة 1، ويُفعّل HPA عند تجاوز 70٪ من استخدام المعالج. نموذج الدفع عبر gRPC يعني أن أي انقطاع مؤقت في istiod لا يُوقف حركة المرور الحية — إذ تحتفظ sidecars بآخر إعداد معروف وتواصل التوجيه ريثما يستعيد istiod عافيته.

istiod ليس في المسار الحرج لحركة المرور. بمجرد أن يتلقى sidecar إعدادات xDS وشهادة mTLS، يُنفّذ السياسة باستقلالية تامة. لا يحتاج istiod إلا لأن يكون متاحاً لدفع التحديثات عند تغيير الإعدادات أو الشهادات. هذه هي الخاصية الأساسية للمرونة المتأتية من فصل مستويَي التحكم والبيانات.

مستوى البيانات: Envoy Sidecars

Envoy proxy هو مكوّن مستوى البيانات الشامل. تحصل كل Pod في الشبكة على نسخة مُحقونة منه (عبر حاوية init تُسمى istio-proxy وخطاف Admission مُغيِّر). يعترض sidecar كل حركة TCP الواردة والصادرة باستخدام قواعد iptables تكتبها حاوية init لحظة بدء تشغيل Pod — المنفذ 15001 للصادر و15006 للوارد.

المسؤوليات الرئيسية لـ Envoy في الشبكة:

  • إنهاء mTLS / تأسيسها: يحمل Envoy هوية SPIFFE SVID الخاصة بعبء العمل ويتولى مصافحات TLS بشفافية تامة. تكتب التطبيقات HTTP عادياً وتُرقّيه Envoy إلى mTLS عند الحدود.
  • تشكيل حركة المرور: قواعد VirtualService (إعادة المحاولات، المهل، التوجيه الموزون، مطابقة الترويسات) تُقدَّم كإعدادات مسارات Envoy تُدفع عبر RDS/CDS.
  • توليد بيانات القياس: يُصدر كل sidecar مقاييس L7 (طلبات/ث، زمن الاستجابة، معدل الأخطاء) إلى نقطة Prometheus على المنفذ 15090، ويُرسل التتبعات الموزعة عبر المُصدِّر المُعدَّ (متوافق مع Zipkin أو OTLP).
  • تطبيق السياسات: تُترجم AuthorizationPolicies بواسطة istiod إلى إعدادات RBAC filter خاصة بـ Envoy وتُدفع عبر xDS. تُطبَّق الأذونات/الرفض على L7 في sidecar لا في التطبيق.
# التحقق من تفعيل حقن sidecar للـ namespace kubectl label namespace production istio-injection=enabled # فحص ما تلقّاه Envoy من istiod — تفريغ xDS الحيّ istioctl proxy-config listeners deploy/checkout -n production istioctl proxy-config routes deploy/checkout -n production --name 8080 istioctl proxy-config clusters deploy/checkout -n production # عرض الشهادة التي دفعها istiod للـ pod istioctl proxy-config secret deploy/checkout -n production # تفريغ كامل للإعدادات (ضخم — مرره عبر jq) kubectl exec -n production deploy/checkout -c istio-proxy -- \ curl -s http://localhost:15000/config_dump | jq '.configs[] | select(.["@type"] | test("RouteConfiguration"))'

معمارية مستويَي التحكم والبيانات في Istio

Istio control-plane and data-plane architecture Control Plane (istio-system) istiod Pilot (xDS) Citadel (CA) Galley (Val.) Webhook Kubernetes API Server watch CRDs (VS / DR / PA) Data Plane — Pod sidecars Pod: checkout App :8080 Envoy iptables redirect Pod: inventory App :3000 Envoy iptables redirect Pod: payment App :9000 Envoy iptables redirect xDS push mTLS mTLS
مستوى التحكم (istiod) يدفع إعدادات xDS لكل sidecar من Envoy؛ تسير حركة البيانات عبر mTLS بين sidecars دون المرور بـ istiod.

كيف تتدفق إعدادات xDS

عند تطبيق VirtualService، تسير السلسلة على النحو التالي:

  1. يصل kubectl apply إلى خادم API؛ يتحقق Admission Webhook الخاص بـ Galley من صحة CRD.
  2. يتلقى نظام Pilot الفرعي في istiod حدث المراقبة من خادم API.
  3. يعيد Pilot حساب لقطة xDS للخدمات المتأثرة ويدفع تحديثات تدريجية (delta xDS) لكل sidecar Envoy متصل عبر تدفقات gRPC مفتوحة.
  4. تُبادل Envoy إعداداتها للمستمعين/المسارات بشكل ذري وتُؤكّد الاستلام (ACK). إذا رفضت Envoy الإعداد (NACK)، يسجّل istiod الخطأ — ويحتفظ sidecar بالإعداد السابق الصحيح.

في عنقود يضم 500 Pod تكتمل هذه العملية في أقل من ثانيتين لتغيير اعتيادي. عند 5000 Pod، يُبقي التوسع الأفقي الصحيح لـ istiod (3 نسخ على الأقل مع ضبط PILOT_PUSH_THROTTLE) زمن الاستجابة أقل من 10 ثوانٍ.

# التحقق من حالة مزامنة xDS — هل هناك sidecars أرسلت NACK؟ istioctl proxy-status # أعمدة المخرجات النموذجية: # NAME CLUSTER CDS LDS EDS RDS ECDS ISTIOD VERSION # checkout-6d8b9f-xtz2p ... SYNCED SYNCED SYNCED SYNCED ... istiod-xxx 1.20.3 # payment-7c9b4f-abc1q ... STALE SYNCED SYNCED SYNCED ... istiod-xxx 1.20.3 # ^-- CDS stale يعني Envoy لم تؤكد تحديث العنقود بعد # ضبط حد الدفع لعناقيد كبيرة (متغير بيئي على Deployment istiod) kubectl set env deployment/istiod -n istio-system PILOT_PUSH_THROTTLE=200

دورة حياة الشهادة

نظام Citadel الفرعي هو مرجع جذري متوافق مع SPIFFE. عند بدء تشغيل Pod، تُولّد عملية istio-agent داخل حاوية istio-proxy زوج مفاتيح مؤقت، وتنشئ CSR يحمل معرّف SPIFFE URI للـ Pod (spiffe://cluster.local/ns/production/sa/checkout)، وترسله إلى istiod عبر قناة gRPC ذات مصادقة متبادلة. يوقّع istiod الطلب بمرجع الجذر الخاص بالشبكة، وتُكتب الشهادة على مجلد tmpfs في /var/run/secrets/istio وتُجدَّد بالوكيل قبل انتهاء صلاحيتها.

تجديد المرجع الجذري للشبكة دون توقف باستخدام ميزة CA bundle في Istio: أضف المرجع الوسيط الجديد إلى حزمة الثقة، دعه ينتشر، أعد توقيع شهادات أعباء العمل، ثم احذف المرجع القديم. لا تُبادل المرجع الجذري دفعة واحدة — فذلك يكسر mTLS لجميع Pods التي لم تُعد مصافحة TLS بعد.

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

أكثر حوادث istiod شيوعاً على نطاق واسع:

  • قتل istiod بسبب نفاد الذاكرة: كل Envoy متصلة تحمل تدفق gRPC مفتوحاً؛ 2000 sidecar ≈ 2-4 GB من ذاكرة istiod. حدّد طلبات/حدود الذاكرة بسخاء (مثلاً 2Gi طلباً، 4Gi حداً) وراقب مقياس pilot_xds_push_time_seconds.
  • ضغط الكتابة المتزامن للـ CRD: نشر 50 VirtualService في آن واحد يُطلق 50 دورة دفع. استخدم istioctl analyze قبل الإيداع ووزّع عمليات النشر.
  • تباين الإصدارات: sidecars Envoy على إصدار N-2 نسبةً إلى istiod مدعومة، لكن معدلات NACK ترتفع. تابع pilot_xds_push_errors_total بعد ترقيات مستوى التحكم.
  • سباق iptables عند بدء تشغيل Pod: تكتب حاوية init قواعد iptables قبل بدء التطبيق، لكن إذا تعطّلت حاوية sidecar وأُعيد تشغيلها تبقى القواعد — فتُحال حركة المرور إلى منفذ لا يستمع. راقب PILOT_ENABLE_AMBIENT (يُلغي الوضع Ambient هذه الفئة من الأعطال بالكامل، وإن كان لا يزال في مرحلة الاستقرار في 1.21+).
لا تشغّل istiod بنسخة واحدة في الإنتاج أبداً. إعادة التشغيل الدورية لـ istiod المنفرد تُفقد جميع sidecars تدفقات xDS في آن واحد. تُخزّن في الذاكرة ما يصل إلى PILOT_DEBOUNCE_MAX (10 ثوانٍ افتراضياً) من إعدادات قديمة. وفي حال استمرار الانقطاع، قد يبدأ انتهاء صلاحية الشهادات في التسبب بفشل mTLS في العناقيد ذات التغيير المتكرر.
# التحقق من عدد نسخ istiod واستهلاك الموارد kubectl get hpa -n istio-system kubectl top pod -n istio-system -l app=istiod # مقاييس Prometheus الرئيسية للتنبيه عليها # pilot_xds_push_time_seconds{quantile="0.99"} -- زمن دفع p99؛ تنبيه عند > 5 ثوانٍ # pilot_xds_push_errors_total -- عدد NACK؛ تنبيه عند > 0 مستمر # citadel_server_csr_sign_error_count -- فشل توقيع الشهادات # envoy_cluster_upstream_rq_5xx -- 5xx لكل خدمة من sidecars # التحقق من تماثل إصدار الشبكة istioctl version