المفاهيم الأساسية لـ Envoy Gateway: شرح Gateway و Listener و Proxy وعائلة Route
الانطباع الأول لدى كثير من الناس عن Gateway API يكون شيئًا مثل: "عدد المصطلحات ليس ضخمًا، لكن عقلي يشعر وكأنه يشاهد قائمة شخصيات أسماؤها متشابهة ولا أستطيع تمييز البطل من الشخصيات الجانبية." هذه المقالة موجودة لتقطع هذا الالتباس، وتغطي أيضًا أنواع الـ route الشائعة في الطريق.
البنية العامة
تقسّم مفاهيم Envoy Gateway الرسمية النظام إلى ثلاث طبقات:
- User Configuration: موارد
Gateway APIو CRDs التوسعية الخاصة بـ Envoy Gateway التي تكتبها - Envoy Gateway Controller: يقرأ الموارد ويتحقق منها ويترجم الإعدادات
- Envoy Proxy: مستوى البيانات الذي يتعامل فعليًا مع المرور
هذا يعني أن ما تقوم بتعديله عادة ليس Envoy Proxy نفسه، بل إنك "تصرّح بما تريده". ويقوم Envoy Gateway بترجمة هذه التصريحات إلى إعدادات يستطيع Envoy Proxy تنفيذها. وهذا هو السبب الذي يجعله ألطف من كتابة إعدادات البروكسي يدويًا.
الأدوار الأساسية
يكفي أن تتذكر هذه الآن:
GatewayClass: يعرّف "أي implementation من Gateway يُستخدم في هذا الـ cluster"Gateway: يعرّف "أين يوجد ingress وما البروتوكول الذي يتحدث به"Listener: يعرّف فتحة ingress محددة بحسب port/protocol/hostnameRoute: يعرّف "أي الطلبات تذهب إلى أي Service"Envoy Proxy: الـ Gateway Proxy الفعلي الذي يستقبل المرور ويوجهه
بلغة بسيطة:
GatewayClassهو ورقة المواصفاتGatewayهو المدخل الأمامي للمبنىListenerهو مكتب الاستقبالRouteهو اللوحات الإرشادية داخل المبنىEnvoy Proxyهو نظام الحماية الذي يطبّق التحكم ويرافق المرور
من دون أي واحد من هذه العناصر، لن يصل المرور إلى المكان الذي تريده.
YAML مصغّر يوضح الصورة كاملة
إليك أصغر مثال مفهوم:
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: eg
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: eg
spec:
gatewayClassName: eg
listeners:
- name: http
protocol: HTTP
port: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: backend
spec:
parentRefs:
- name: eg
hostnames:
- "www.example.com"
rules:
- backendRefs:
- name: backend
port: 3000وعند ربطها معًا تصبح المنطقية كالتالي:
GatewayClassيقول إنEnvoy Gatewaycontroller هو المسؤولGatewayيصرّح بمدخل HTTP واحد على المنفذ80HTTPRouteيقول إن الطلبات الخاصة بـwww.example.comيجب أن تذهب إلىbackend:3000- يقوم
Envoy Gatewayبترجمة كل ذلك إلى ما يفهمهEnvoy Proxy
فهم كل حقل
GatewayClass
هذا تعريف على مستوى الـ cluster لنوع ingress. وأكثر حقل حاسم فيه غالبًا هو:
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controllerومعناه ببساطة:
"هذا الـ GatewayClass تتم إدارته بواسطة Envoy Gateway controller."
إذا لم يتطابق controllerName، فالأمر يشبه إرسال طلب توصيل إلى الشركة الخطأ، ولن يلتقطه أحد.
Gateway
هذا يعرّف "كيف يبدو ingress." وأكثر حقل يتم الرجوع إليه هو listeners:
listeners:
- name: http
protocol: HTTP
port: 80وهذا يعني:
- افتح listener اسمه
http - اقبل مرور HTTP
- استمع خارجيًا على المنفذ
80
وبالنسبة إلى HTTPS، ستضيف عادة listener آخر مع protocol: HTTPS وتربط به إعدادات TLS.
ما يديره Gateway عادة:
- المنفذ والبروتوكول الخارجيان
- hostname لكل listener
- موضع TLS termination
- أي namespaces يمكن أن ترتبط routes الخاصة بها
Gateway هو في العادة مسؤولية طبقة المنصة، لذلك تكون ملكيته غالبًا لدى فريق المنصة.
Listener
هذا الدور هو الأكثر تجاهلًا من المبتدئين، لكنه في الحقيقة حاسم جدًا.
الـ listener هو فتحة ingress مواجهة للخارج على الـ Gateway. وهو يعرّف:
nameportprotocolhostnametlsallowedRoutes
مثال:
listeners:
- name: https
protocol: HTTPS
port: 443
hostname: api.example.comوهذا يعني:
- اسم هذه الفتحة هو
https - تقبل HTTPS
- تستمع على المنفذ
443 - مخصصة لـ
api.example.com
إذا كان لديك عدة listeners مثل:
httpللمنفذ 80httpsللمنفذ 443grpcللمنفذ 50051
فأنت تفتح عدة فتحات ingress على نفس الـ Gateway، ويمكن لكل واحدة منها أن ترتبط بها routes مختلفة.
Envoy Proxy
كثير من الناس يركزون فقط على YAML وينسون أن Envoy Proxy هو الذي يتعامل فعليًا مع المرور الحي.
ودوره هو:
- استقبال طلبات العميل
- مطابقة الإعدادات التي دفعها Envoy Gateway
- توجيه المرور إلى backend المناسب
- التعامل مع TLS و headers و timeouts و retries وسلوكيات مستوى البيانات الأخرى
لذلك اعتبر Envoy Gateway هو "مستوى التحكم"، و Envoy Proxy هو "مستوى البيانات / Gateway Proxy."
عائلة Route
Route ليس مجرد HTTPRoute. فالعائلة كلها عنصر أساسي في تصميم Gateway API.
HTTPRoute
هذا هو النوع الذي ستكتبه وتعدله غالبًا. وهناك ثلاثة حقول أساسية:
spec:
parentRefs:
- name: eg
hostnames:
- "www.example.com"
rules:
- backendRefs:
- name: backend
port: 3000parentRefs: إلى أي Gateway يجب أن يرتبطhostnames: أي Host header يفعّل هذه القاعدةbackendRefs: إلى أين تُرسل الطلبات المطابقة
أكثر نقطة يختلط فهمها على الناس: Gateway ليس المكان الذي تكتب فيه التوجيه الدقيق، بل HTTPRoute هو الذي يقرر فعليًا "كيف يُقسّم المرور."
GRPCRoute
إذا كنت تتعامل مع gRPC، فـ GRPCRoute أكثر طبيعية من حشره داخل HTTPRoute.
يمكنه المطابقة على:
- gRPC hostname
- gRPC service
- gRPC method
- headers
مثال:
matches:
- method:
service: com.example.User
method: Loginهذه الدلالات تنسجم طبيعيًا مع gRPC، فأنت لا تطابق فقط URL paths، بل تطابق مباشرة نموذج gRPC service/method.
وتشير الوثائق الرسمية أيضًا إلى أنه إذا كان GRPCRoute و HTTPRoute يشتركان في نفس الـ listener ولديهما hostnames متعارضة، فيجب على الـ implementations رفض أحدهما. وباختصار: لا تجعل HTTP و gRPC يتقاتلان على نفس الـ hostname.
TCPRoute
TCPRoute يتعامل مع مرور TCP الخام.
وعلى عكس HTTPRoute، فهو لا يفهم path أو header على مستوى L7، بل هو أقرب إلى forwarding على مستوى L4.
السيناريوهات المناسبة:
- خدمات ذات بروتوكولات غير HTTP
- خدمات TCP صِرفة
- توجيه الاتصالات إلى backends مختلفة بالاعتماد فقط على منفذ الـ listener
قواعد البيانات ذات البروتوكولات المخصصة أو بروتوكولات TCP الخاصة أمثلة نموذجية لاستخدام TCPRoute.
TLSRoute
TLSRoute يتعامل مع مرور TLS، وهو شائع جدًا في سيناريوهات TLS passthrough.
الفكرة الأساسية:
- الـ Gateway لا يقوم بالضرورة بإنهاء TLS
- قد يوجّه المرور فقط بناءً على SNI hostname داخل مصافحة TLS
- يبقى المرور المشفّر محفوظًا حتى الـ backend
وهذا مهم في السيناريوهات التي تتطلب تشفيرًا من الطرف إلى الطرف، أو عندما لا تريد إنهاء TLS عند Gateway.
كيف تختار نوع Route
| المتطلب | استخدم هذا |
|---|---|
| مواقع الويب و REST APIs والمرور العام للويب | HTTPRoute |
| توجيه gRPC حسب service/method | GRPCRoute |
| مرور TCP الخام | TCPRoute |
| TLS passthrough / التوجيه المبني على SNI | TLSRoute |
هذا الجدول مهم لأن كثيرًا من الناس يكتبون HTTPRoute تلقائيًا لكل شيء. لكن إذا كنت تتعامل فعليًا مع gRPC أو TCP، فإن إجبار ذلك على الدخول في HTTPRoute سيجعل الـ YAML أكثر awkward مع الوقت.
لماذا التفكير في Routes أسهل من Ingress
كانت إعدادات Ingress القديمة غالبًا تضغط الكثير من المسؤوليات داخل مورد واحد، مما سبّب بعض نقاط الألم المستمرة:
- خلط إعدادات المنصة مع توجيه التطبيق
- التعبير عن الميزات المتقدمة عبر annotations ضعيفة القراءة
- قدرة تعبيرية محدودة للبروتوكولات غير HTTP
ومقاربة Gateway API هي فصل المسؤوليات:
- فرق المنصة تدير
GatewayClassوGateway - فرق التطبيقات تدير
HTTPRouteالخاص بها
وهذا الفصل ممتاز للعمل التعاوني بين عدة أشخاص. فلا تحتاج إلى لمس طبقة ingress كاملة لمجرد تغيير path واحد، ومعدل تداخل الفرق على بعضها ينخفض بشكل واضح.
ابدأ بالانتباه إلى status
بعيدًا عن spec، ابنِ تدريجيًا عادة التحقق من status. وخصوصًا في HTTPRoute و Gateway:
kubectl get gateway eg -o yaml
kubectl get httproute backend -o yamlابدأ بالتحقق من:
- هل تم
Acceptedللـ route - هل الـ gateway listener في حالة Ready
- هل تم تعيين عنوان بنجاح
الأمر أشبه بالتحقق من نتيجة الامتحان. لا تكتفِ بأنك قدّمت الورقة، بل تحقّق أنها صُحّحت وتم النجاح.
الخلاصة في سطر واحد
تعامل مع GatewayClass و Gateway و Listener و Route و Envoy Proxy على أنها: "من يدير؟ كيف يُفتح ingress؟ كيف ترتبط كل فتحة؟ كيف ينقسم المرور؟ ومن ينفّذ؟" وستكون قد فهمت بالفعل 80% من المفاهيم الأساسية.
💡 كثير من المبتدئين يندفعون مباشرة إلى تفاصيل CRD. لا تستعجل، رتّب هذه الأدوار في ذهنك أولًا، وسيتوقف YAML عن الشعور وكأنك تقابل غرباء في كل مرة.
الخطوة التالية
الآن وبعد أن ترسخت المفاهيم، تتعمق المقالة التالية في أكثر سيناريوهات توجيه HTTP شيوعًا، مثل host و path و header وتقسيم المرور: 👉 التوجيه العملي لـ HTTP