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

بنية السايدكار والبنية المحيطية

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

بنية السايدكار والبنية المحيطية

قبل نشر شبكة الخدمات (Service Mesh)، يجب عليك أن تختار كيفية ربط الـ Proxy بأحمال عملك. هذا ليس مجرد إعداد بسيط، بل هو اختيار معماري جوهري يحدد تكلفة المعالج (CPU)، والذاكرة (RAM)، ونطاق الضرر عند الأعطال، وتعقيد عمليات الترقية، والوضع الأمني على نطاق واسع. يسود اليوم نموذجان رئيسيان: نموذج السايدكار (النهج الأصلي في Kubernetes، المستخدم في Istio قبل الإصدار 1.22، وفي Linkerd وConsul Connect) والنموذج المحيطي (Ambient) (Istio Ambient، الذي أصبح جاهزاً للإنتاج في Istio 1.22، مايو 2024). فهم الفوارق على المستوى الهندسي — لا على مستوى التسويق — هو ما يميز المهندسين القادرين على توصيل الأنظمة باستقرار.

نموذج السايدكار: كل Pod يحصل على Proxy خاص به

في نموذج السايدكار، يُحقن حاوية الـ Proxy — سواء كانت envoy في Istio أو linkerd-proxy في Linkerd — في كل Pod تلقائياً عند إنشائه عبر MutatingWebhookConfiguration. تشترك الحاوية المحقونة في نفس Network Namespace مع تطبيق الـ Pod، وتقوم حاوية initContainer (تعمل بصلاحية NET_ADMIN) بإعداد قواعد iptables لتحويل كل حركة TCP الواردة والصادرة عبر الـ Proxy على المنافذ 15001 (صادر) و15006 (وارد) في Istio. التطبيق نفسه لا يعلم شيئاً عن هذا الاعتراض.

كل اتصال TCP بين الخدمات يمر إذاً عبر أربع قفزات Proxy: Proxy الجانب المُرسِل ← الشبكة ← Proxy الجانب المستقبِل، مع تفعيل mTLS بين الـ Proxyين. التطبيق يكتب على مقبس عادي؛ الشبكة توصّل الاتصال مشفراً وموثّقاً وخاضعاً للسياسات.

Sidecar proxy architecture: per-pod proxy injection Pod A (Node 1) App Container :8080 Envoy Sidecar :15001/:15006 iptables REDIRECT (initContainer) all TCP → :15001 / :15006 istio-init (NET_ADMIN) programs rules at Pod start Pod B (Node 2) App Container :8080 Envoy Sidecar :15001/:15006 iptables REDIRECT (initContainer) all TCP → :15001 / :15006 istio-init (NET_ADMIN) programs rules at Pod start mTLS
نموذج السايدكار: كل Pod يحمل Proxy Envoy خاصاً به؛ iptables تعترض كل الحركة بشفافية.

في Google وLyft (المنشئ الأصلي لـ Envoy) وUber، تعمل أسطول تضم مئات الآلاف من الـ Sidecar Proxies بشكل اعتيادي. لكن التكلفة حقيقية: الـ Sidecar الأساسي في Istio يستهلك تقريباً 50–100 ميغابايت RAM و0.5–1 vCPU في وضع الخمول لكل Proxy، مع ارتفاع الـ CPU تحت الحمل. في مجموعة تضم 1,000 خدمة، كل منها تعمل على 5 نسخ، فهذا يعني 5,000 حاوية إضافية — تكلفة غير هيّنة. المقابل هو عزل كل حمل عمل بشكل مستقل: عطل أو خطأ في إعداد Proxy واحد لا يؤثر إلا على Pod واحد.

تداعيات الموارد ودورة حياة السايدكار

يجب أن يكون Webhook الحقن نشطاً حتى تدخل الـ Pods الجديدة في الشبكة. انقطاع istiod (أو linkerd-controller) أثناء عملية نشر متدحرجة يعني أن الـ Pods الجديدة تعمل بدون Proxy — إما يُرفض إنشاؤها (إذا كانت سياسة الـ Webhook تساوي failurePolicy: Fail) أو تنضم للمجموعة بدون تشفير أو مراقبة (إذا كانت Ignore). اختر Fail في بيئة الإنتاج؛ تقبّل خطر التوافرية أثناء أعطال المستوى التحكمي وخففها بتشغيل istiod على عدة نودات مع PodAntiAffinity وPodDisruptionBudgets.

ترقية الـ Proxy تستلزم إعادة تشغيل الـ Pod — لا يوجد تحديث في المكان. في مجموعة تضم 10,000 Pod، ترقية الشبكة تعني تدوير 10,000 Pod. استراتيجيات الترقية التدريجية (ترقية namespace واحد، التحقق من القياسات، ثم المتابعة) ضرورة وليست رفاهية.

# التحقق من تفعيل حقن السايدكار في namespace kubectl get namespace production -o jsonpath='{.metadata.labels}' # يجب أن يظهر: {"istio-injection":"enabled"} # تفعيل الحقن على namespace kubectl label namespace production istio-injection=enabled --overwrite # التحقق من حالة الحقن لجميع الـ Pods في الـ namespace kubectl get pods -n production \ -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{range .spec.containers[*]}{.name}{" "}{end}{"\n"}{end}' # ابحث عن 'istio-proxy' بجانب اسم كل حاوية تطبيق. # تأكيد برمجة قواعد iptables داخل Pod يعمل kubectl debug -it <pod-name> -n production --image=nicolaka/netshoot -- iptables -t nat -L -n -v | grep ISTIO # يجب أن تظهر سلاسل ISTIO_REDIRECT و ISTIO_IN_REDIRECT.

النموذج المحيطي (Ambient): Proxy بدون Pod

نموذج Istio Ambient (جاهز للإنتاج منذ Istio 1.22، يونيو 2024) يُلغي الـ Sidecar في كل Pod كلياً ويستبدله ببنية ذات طبقتين:

  1. ztunnel — DaemonSet مكتوب بـ Rust، يعمل على مستوى النود ومسؤول عن الطبقة L4 فقط: mTLS، والنفق عبر بروتوكول HBONE (HTTP/2-based overlay)، وقياسات أساسية. خفيف للغاية: ~30 ميغابايت لكل نود بغض النظر عن عدد أحمال العمل عليه.
  2. waypoint proxy — نسخة Envoy (واحدة لكل Service Account أو Namespace) تتولى الطبقة L7: توجيه HTTP، وإعادة المحاولة، وقطع الدائرة، والتحقق من JWT، والقياسات المتقدمة. لا يُنشأ الـ Waypoint إلا عند الحاجة الفعلية لسياسة L7؛ خدمة داخلية تحتاج فقط mTLS لن تُنشئ Waypoint أبداً.

يعتمد تحويل حركة البيانات في النموذج المحيطي على برامج eBPF (على أنوية Linux 5.4+) يحملها DaemonSet الـ istio-cni عند إنشاء الـ Pod، أو يرجع إلى iptables-in-netns على الأنوية الأقدم. الفارق الجوهري عن نموذج السايدكار: إعادة التوجيه تعمل في Network Namespace للـ Pod، لكن عملية الـ Proxy تعيش على النود وليس داخل الـ Pod.

Ambient mesh architecture: ztunnel per node, waypoint per service account Node 1 Pod A App only, no sidecar Pod B App only, no sidecar eBPF ztunnel (DaemonSet) L4 mTLS · HBONE tunnel · ~30 MiB Waypoint (Envoy) L7: routing, retries, JWT · optional Node 2 Pod C App only, no sidecar eBPF ztunnel (DaemonSet) L4 mTLS · HBONE tunnel · ~30 MiB HBONE / mTLS
النموذج المحيطي: ztunnel لكل نود يتولى L4؛ Waypoint Envoy اختياري لـ L7 — لا Sidecar في أي Pod.

مقارنة مباشرة بين البنيتين

لا يوجد نموذج أفضل على إطلاقه. الاختيار الصحيح يعتمد على مزيج الأحمال في مجموعتك، ومتطلبات الأمان، والنضج التشغيلي.

  • نطاق الضرر عند عطل الـ Proxy: السايدكار — تأثر Pod واحد؛ الاسترداد بإعادة تشغيله. النموذج المحيطي — عطل ztunnel على نود يوقف جميع أحمال العمل المسجلة في الشبكة على ذلك النود دفعة واحدة، مما يجعله مكوناً بنطاق ضرر على مستوى النود، مشابهاً لـ kubelet.
  • استهلاك الذاكرة على نطاق واسع: السايدكار — خطي مع عدد الـ Pods، قد يصل إلى 50–100 ميغابايت × عدد الـ Pods. النموذج المحيطي — ثابت لكل نود للـ L4 (~30 ميغابايت × عدد النودات)؛ Waypoints فقط للخدمات التي تحتاجها. مجموعة تضم 1,000 Pod على 50 نوداً توفر تقريباً 48 غيغابايت من ذاكرة الحاويات في النموذج المحيطي لأحمال العمل التي تحتاج L4 فقط.
  • دقة سياسة L7: السايدكار — كل Pod له Envoy خاص؛ يمكنك تطبيق AuthorizationPolicy لكل Pod. النموذج المحيطي — سياسات L7 تمر عبر Waypoint مشترك؛ نطاق الأمان هو Service Account للـ Waypoint.
  • عملية الترقية: السايدكار — يستلزم تدوير جميع الـ Pods؛ النموذج المحيطي — ترقية DaemonSets لـ ztunnel والـ Waypoints بشكل مستقل دون إعادة تشغيل أي Pod.
  • متطلبات النواة: النموذج المحيطي يحتاج نواة Linux 5.4+ لـ eBPF؛ النودات الأقدم تحتاج iptables كخيار احتياطي.
  • النضج: السايدكار — مختبر منذ 2017 بسجل إنتاجي واسع. النموذج المحيطي جاهز للإنتاج منذ مايو 2024 — في طور النضج السريع لكن بخبرة تشغيلية أقل.
فكرة جوهرية: في معظم عمليات النشر الكبيرة في Kubernetes اليوم (2025)، تُهاجر الفرق إلى Istio Ambient تدريجياً: تسجيل الـ Namespaces غير الحساسة في النموذج المحيطي أولاً، والإبقاء على أحمال العمل الحرجة أمنياً في نموذج السايدكار، والتشغيل بوضع مختلط حتى يثبت استقرار النموذج المحيطي في بيئتهم. Istio يدعم كلا النموذجين في نفس المجموعة.

تفعيل النموذج المحيطي والتحقق منه

النموذج المحيطي يُفعَّل اختيارياً لكل Namespace عبر Label. يجب أن يكون DaemonSet الـ istio-cni oDaemonSet الـ ztunnel يعملان قبل تسجيل أي أحمال عمل.

# تثبيت Istio بملف تعريف ambient (Helm، Istio 1.22+) helm repo add istio https://istio-release.storage.googleapis.com/charts helm repo update helm install istio-base istio/base -n istio-system --create-namespace helm install istiod istio/istiod -n istio-system --set profile=ambient helm install istio-cni istio/cni -n istio-system --set profile=ambient helm install ztunnel istio/ztunnel -n istio-system # التحقق من تشغيل جميع المكونات kubectl get pods -n istio-system # المتوقع: istiod، istio-cni (DaemonSet)، ztunnel (DaemonSet) # تسجيل Namespace في النموذج المحيطي kubectl label namespace production istio.io/dataplane-mode=ambient # التحقق من تسجيل Pod (ابحث عن الـ Annotation) kubectl get pod -n production <pod-name> -o jsonpath='{.metadata.annotations}' # يجب أن يتضمن: "ambient.istio.io/redirection":"enabled" # نشر Waypoint لسياسة L7 على Service Account istioctl waypoint apply --service-account checkout -n production kubectl get gateway -n production # يظهر الـ Waypoint كـ Gateway resource # تأكيد نشاط أنفاق HBONE عبر حالة ztunnel istioctl ztunnel-config workload -n production

Linkerd: سايدكار فقط، خفيف للغاية

يتخذ Linkerd (CNCF Graduated) مقايضة مختلفة: يبقى مع نموذج السايدكار فقط لكن يجعل الـ Proxy خفيفاً للغاية لدرجة تنهار معها حجة التكلفة. الـ linkerd-proxy هو Proxy مخصص مكتوب بـ Rust يستهلك ~10 ميغابايت RAM لكل Pod في وضع الخمول وكاد يكون معدوم الـ CPU — أخف بمقدار 5–10 أضعاف من Envoy لكل Sidecar. Linkerd يدفع ثمن ذلك بمجموعة ميزات أضيق: لا قابلية توسعة بـ Wasm، لا تكرار حركة معقد، دعم محدود لتحويل gRPC. للفرق التي تبحث أساساً عن mTLS شفاف + قياسات Golden Signal بدون الثقل التشغيلي لـ Istio، نموذج السايدكار في Linkerd غالباً هو الخيار الصحيح.

ممارسة احترافية: قبل اختيار بنية الشبكة، أجرِ اختبار حمل واقعياً على أحمال عملك الفعلية مع وبدون Proxy لقياس التأثير الحقيقي على الـ Latency في بيئتك — معايير الأداء التسويقية ليست بيئة الإنتاج لديك. إضافة 1–5 ملي ثانية لكل قفزة أمر طبيعي للـ Sidecars ذات الحمل الخفيف؛ تحت 10,000 طلب/ثانية مستمر لكل خدمة تصبح تكلفة CPU هي العامل الحاسم. قِس أولاً، ثم قرر.
مخاطرة في الإنتاج — iptables وUDP: كلا النموذجين — حقن iptables للسايدكار وإعادة توجيه eBPF للنموذج المحيطي — يعترضان TCP فقط بشكل افتراضي. DNS (UDP/53) لا يُعاد توجيهه عبر Proxy الشبكة إلا عند الإعداد الصريح لـ DNS Proxying (الخيار ISTIO_META_DNS_CAPTURE=true في Istio). الخدمات التي تعتمد على بروتوكولات UDP (NTP، syslog، بعض تطبيقات الألعاب) غير مرئية للشبكة ولا تحصل على أي من ضمانات الأمان أو الرصد. راجع أحمال عملك بحثاً عن حركة غير TCP قبل افتراض تغطية كاملة.