أتِح خدمات HTTP للعالم
تستطيع كل مجموعة Kubernetes أن تخدم مواقعك وواجهاتك البرمجية عبر HTTPS من خلال بوابتها المُدارة. اربط بها مسارًا من نوع HTTPRoute أو قاعدة Ingress، وتتولّى المنصّة اسم المضيف والشهادة، دون موزّع حمل تُعدّه.
المواقع والواجهات البرمجية (HTTP وHTTPS) ← استخدم البوابة المُدارة، على اسم مضيف المجموعة أو على نطاقك الخاص عبر سجل CNAME. وكل ما عدا ذلك (قواعد البيانات وخدمات TCP أو UDP) ← خدمة من نوع LoadBalancer، على منفذ خاص بها.
لكل مجموعة بوابة مُدارة مفعّلة افتراضيًا. فإن لم يعرض قسم الخدمات والمسارات في المجموعة البوابة المُدارة، فقد أُوقفت لمساحة عملك: تواصل مع الدعم.
كيف تعمل
تُنشئ المنصّة بوابة (Gateway) اسمها sahabti في مساحة الأسماء sahabti-gateway داخل المجموعة وتحافظ عليها: أنت تربط مساراتك بها ولا تعدّلها. يتصل الزوّار عبر HTTPS بحافة المنصّة (edge) التي تحمل الشهادات، وتصل طلباتهم إلى البوابة بصيغة HTTP عادية، ثم ترسل البوابة كلًّا منها إلى الخدمة التي يحدّدها مسارك. ولا تستخدم البوابة أي موزّع حمل، ولا تستهلك شيئًا من حصة موزّعات الحمل في مساحة عملك.
البدء السريع
احفظ ما يلي باسم hello.yaml: خادم ويب صغير، وخدمته، ومسار إليه.
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello
spec:
replicas: 2
selector:
matchLabels:
app: hello
template:
metadata:
labels:
app: hello
spec:
containers:
- name: hello
image: nginx:1.27-alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: hello
spec:
selector:
app: hello
ports:
- port: 80
targetPort: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: hello
spec:
parentRefs:
- name: sahabti
namespace: sahabti-gateway
rules:
- backendRefs:
- name: hello
port: 80
kubectl apply -f hello.yaml
لا يحدّد المسار أي hostnames، فيجيب على اسم المضيف الخاص بالمجموعة، <cluster>.sahabti.app، الذي يعرضه قسم الخدمات والمسارات في المجموعة ضمن البوابة المُدارة. وحين تظهر حالة اسم المضيف يعمل، افتحه:
curl https://<cluster>.sahabti.app/
يمكن أن يقع المسار في أي مساحة أسماء، ما دام parentRefs فيه يحدّد البوابة مع مساحة أسمائها، كما هنا.
استخدم Ingress
تعمل قواعد Ingress أيضًا، وهذا يناسب مخططات Helm والملفات التي تستخدمها أصلًا. أعطها الفئة sahabti:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop
spec:
ingressClassName: sahabti
rules:
- host: shop.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: hello
port:
number: 80
- الفئة
sahabtiهي فئة Ingress الافتراضية في المجموعة، إلا إذا كانت فئة أخرى هي الافتراضية من قبل. - تحوّل المنصّة كل قاعدة Ingress من هذه الفئة إلى مسارات HTTPRoute، وتُبقيها متزامنة معها.
- يُتجاهل قسم
tlsفيها لأن HTTPS يُعالَج عند الحافة، وتتلقّى قاعدة Ingress حدثًا يوضّح ذلك. - تعرض حالتها اسم المضيف الخاص بالمجموعة، ويسرده
kubectl get ingressعنوانًا لها.
يجب أن يكون host اسم مضيف تابعًا للمجموعة: انظر أسماء المضيفين.
أسماء المضيفين
لا تخدم المجموعة إلا أسماء المضيفين التابعة لها:
- اسم المضيف الخاص بها،
<cluster>.sahabti.app؛ - نطاقك الخاص، مثل
shop.example.com، تُثبَت ملكيته بسجل CNAME؛ - نطاق جذر، مثل
example.com، يُربط عبر نطاق مُوثَّق في مساحة العمل؛ - الأسماء الإضافية تحت
sahabti.app.
اسم المضيف الخاص بالمجموعة
لكل مجموعة اسم مضيف خاص بها، <cluster>.sahabti.app، يظهر في قسم الخدمات والمسارات منها، ولا يحتاج إلى أي إعداد. والمسار الذي لا يحدّد hostnames يجيب عليه، وعلى أي اسم مضيف تابع للمجموعة لا يطالب به مسار آخر.
نطاقك الخاص
تقديم shop.example.com من المجموعة خطوتان.
- أضف اسم المضيف. في قسم الخدمات والمسارات من المجموعة، ضمن البوابة المُدارة ← استخدام نطاقك الخاص، أدخل
shop.example.comواختر إضافة اسم المضيف. - وجّه سجل CNAME إلى المجموعة. أنشئ هذا السجل لدى مزوّد DNS. تعرضه لوحة التحكم وفيه اسم مضيف مجموعتك جاهزًا للنسخ.
| النوع | الاسم | القيمة |
|---|---|---|
| CNAME | shop.example.com | <cluster>.sahabti.app |
ثم اذكر اسم المضيف في مسار، كأي اسم مضيف آخر:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: shop
spec:
parentRefs:
- name: sahabti
namespace: sahabti-gateway
hostnames:
- shop.example.com
rules:
- backendRefs:
- name: hello
port: 80
تتحقق المنصّة من DNS كل دقيقة. وما إن يشير السجل إلى المجموعة حتى تُصدر الشهادة وتقدّم اسم المضيف؛ وتنتقل حالته في لوحة التحكم من بانتظار DNS إلى يجري إصدار الشهادة ثم إلى يعمل، وعادةً خلال دقائق. والخطوة الأولى اختيارية: اسم المضيف الذي يستخدمه أحد مسارات المجموعة يظهر في القائمة من تلقاء نفسه، مع السجل نفسه الذي عليك إنشاؤه.
من المفيد أن تعرف:
- لا حاجة إلى سجل TXT ولا إلى نطاق في مساحة العمل: سجل CNAME هو ما يثبت أن اسم المضيف ملكك.
- إن عرض عليك مزوّد DNS تمرير السجل عبر وسيطه (proxy)، فأبقِه سجل DNS فقط، كي يبقى سجل CNAME ظاهرًا.
- أبقِ السجل في مكانه. تواصل المنصّة التحقق منه؛ فإن توقّف عن الإشارة إلى المجموعة ظهرت حالة اسم المضيف سجل CNAME مفقود، وبعد ساعة يتوقف تقديمه. أعِد السجل فيعود تقديمه. أما اسم المضيف الذي لم يعد يستخدمه أي مسار فيُزال حينها.
- لا يخدم اسمَ المضيف الواحد على المنصّة كلها إلا تطبيق واحد أو نسخة واحدة أو مجموعة واحدة، ويكون لأول مساحة عمل تثبت ملكيته. واسم المضيف الذي أضافته مساحة عمل أخرى دون أن يشير سجله إليها لا يمنعك أبدًا.
- لا تُدعم أسماء المضيفين الشاملة (wildcard) مثل
*.example.com.
نطاق جذر
لا يمكن وضع سجل CNAME على نطاق جذر مثل example.com. لتقديمه من المجموعة:
- في صفحة النطاقات في مساحة عملك، أضف
example.comووثّقه بسجل TXT الذي تعرضه الصفحة. - في قسم الخدمات والمسارات من المجموعة، ضمن البوابة المُدارة ← طرق أخرى لإضافة اسم مضيف، اربط
example.comمن ربط نطاق مُوثَّق. - لدى مزوّد DNS، وجّه
example.comإلىapps.sahabti.appبسجل ALIAS أو ANAME أو CNAME مسطّح (flattened)، إن كان مزوّدك يتيح أحدها.
أبقِ سجل TXT في مكانه. تعيد المنصّة التحقق منه كل يوم. وما إن يغيب السجل حتى يصل بريد إلى مالكي مساحة العمل ومشرفيها، وتطلب منك صفحة النطاقات إعادته؛ فإن بقي غائبًا بعد ثلاثة أيام عُلِّقت أسماء المضيفين تحت النطاق، وصار بإمكان مساحة عمل أخرى توثيق النطاق. والنطاق الذي وُثِّق قبل بدء هذه الفحوص اليومية يحصل على 30 يومًا بدل 3 في المرة الأولى التي يغيب فيها سجله.
الأسماء الإضافية
لخدمة مواقع أخرى تحت sahabti.app، أضف أسماء إضافية في قسم الخدمات والمسارات من المجموعة، ضمن البوابة المُدارة ← طرق أخرى لإضافة اسم مضيف. يُخدَم كل اسم منها بالصيغة <name>--<cluster>.sahabti.app، فيصبح الاسم shop مثلًا shop--<cluster>.sahabti.app.
يتكوّن الاسم من 3 إلى 40 رمزًا: أحرف لاتينية صغيرة وأرقام وشرطات غير متتالية. ويجب ألا يزيد طول كل ما يسبق .sahabti.app على 63 رمزًا، فالمجموعة ذات الاسم الطويل تترك له مساحة أقل.
ولتوجيه اسم إضافي إلى خدمة بعينها، ضع اسم المضيف كاملًا في hostnames في المسار، أو في host في قاعدة Ingress.
HTTPS وعنوان العميل
لا يحتاج HTTPS إلى أي شيء منك. ينتهي تشفير TLS عند حافة HTTPS في المنصّة، التي تُصدر الشهادات وتجدّدها، وتصل الطلبات إلى المجموعة بصيغة HTTP عادية على البوابة، فتستقبل خدماتك HTTP عاديًا ولا تحتاج إلى شهادات خاصة بها. ويصل عنوان العميل في الترويسة X-Forwarded-For.
تحقّق من الحالة
في قسم الخدمات والمسارات من المجموعة، تسرد البوابة المُدارة كل اسم مضيف مع حالته، وتذكر ما عليك فعله تاليًا:
| الحالة | معناها |
|---|---|
| يعمل | يُخدَم عبر HTTPS |
| بلا مسار بعد | جاهز، لكن لا يذكره أي HTTPRoute أو Ingress بعد |
| بانتظار DNS | سجل CNAME الخاص به لا يشير إلى المجموعة بعد؛ ويظهر بجانبه السجل المطلوب إنشاؤه |
| يجري إصدار الشهادة | السجل موجود والشهادة في طريقها |
| سجل CNAME مفقود | توقّف سجله عن الإشارة إلى المجموعة؛ ويتوقف تقديمه بعد ساعة ما لم يُعَد السجل |
| قيد الانتظار | لا يُخدَم بعد، مع ذكر السبب، كانتظار أن تبدأ البوابة |
| غير مسموح | يستخدمه مسار، لكن المجموعة لا تستطيع امتلاكه، مع ذكر السبب |
| متوقّف | البوابة المُدارة متوقّفة |
| خطأ | فشل إعداده، مع ما عليك فعله |
لا يُخدَم المسار الذي يستخدم اسم مضيف غير تابع للمجموعة، ويتلقّى حدث HostnameNotRouted:
kubectl describe httproute shop
حل المشكلات
يبقى اسم المضيف على «بانتظار DNS»
تحقّق من السجل من جهازك:
dig +short CNAME shop.example.com
يجب أن يكون الجواب اسم مضيف المجموعة، <cluster>.sahabti.app.، أو أحد أسمائها الإضافية.
- السجل الذي يشير إلى
apps.sahabti.appلا يحدّد أي مجموعة تقصد: وجّهه إلى اسم مضيف المجموعة نفسه. - السجل الذي يمرّره مزوّد DNS عبر وسيطه يجيب بعناوين بدل سجل CNAME: اجعله سجل DNS فقط.
- قد يستغرق وصول سجل جديد أو معدَّل إلى كل المحلِّلات مدةً تصل إلى قيمة TTL الخاصة به.
يظهر اسم المضيف «غير مسموح»
تذكر الملاحظة بجانبه السبب:
- أثبتت مساحة عمل أخرى ملكيته أولًا. إن كان اسم المضيف لك، فوجّه سجل CNAME الخاص به إلى مجموعتك: تتوقف مساحة العمل الأخرى عن امتلاكه بعد ساعة من توقّف سجلها عن الإشارة إلى مجموعتها، أو بعد ثلاثة أيام من غياب سجل TXT لنطاقها المُوثَّق، فتتولّاه مجموعتك.
- نطاق جذر. اربطه عبر نطاق مُوثَّق.
- نطاق المنصّة نفسها. أضفه اسمًا إضافيًا بدلًا من ذلك.
- حدّ أسماء المضيفين. أزل اسم مضيف لم تعد المجموعة تحتاج إليه.
يبقى اسم المضيف على «بلا مسار بعد»
تقدّمه المنصّة، لكن لا يذكره أي مسار، فلا تجد البوابة وجهة للطلب. أضفه إلى hostnames في HTTPRoute أو إلى host في Ingress.
لا تصل الشهادة
قد يكون في نطاقك سجل CAA لا يسمح لجهة إصدار الشهادة. اسمح فيه بـletsencrypt.org وpki.goog وssl.com، أو احذف سجل CAA، ثم أزل اسم المضيف وأضفه من جديد.
تعرض البوابة مشكلة
تسمّيها لوحة التحكم. وأكثرها شيوعًا خدمة لديك تستخدم منفذ العقدة 30080 الذي تحتاج إليه البوابة المُدارة على كل عقدة: امنح تلك الخدمة منفذ عقدة آخر.
الحدود
| الخطة المجانية | الخطط المدفوعة | |
|---|---|---|
| أسماء المضيفين لكل مجموعة: نطاقاتك الخاصة والنطاقات المربوطة والأسماء الإضافية معًا | 20 | 100 |
لا تستخدم البوابة المُدارة نفسها أيًّا من موزّعات الحمل في مساحة عملك.
اترك منفذ العقدة 30080 شاغرًا: تستخدمه البوابة المُدارة على عُقد المجموعة، وأي خدمة لديك تأخذه تُوقف البوابة. وتعرض لوحة التحكم حينها خطأً يسمّي تلك الخدمة.
التحديثات
نُبقي البوابة المُدارة محدَّثة، بما في ذلك الإصلاحات الأمنية، دون أي إجراء من جهتك. يستبدل التحديث وكيل البوابة نسخةً تلو الأخرى، وتبدأ النسخة الجديدة باستقبال الطلبات قبل أن تتوقف القديمة، فتبقى أسماء المضيفين لديك متاحة. قد يحتاج اتصال يبقى مفتوحًا أثناء التحديث، مثل WebSocket أو تنزيل طويل، إلى إعادة الاتصال. بعد كل تحديث تتحقق المنصّة من المجموعة، وتعيد الإصدار السابق إن لم تعد المسارات التي كانت تقبلها مقبولة. كائنات البوابة نفسها في المجموعة تديرها المنصّة، وأي تغيير عليها يُعاد إلى ما كان عليه.
أوقِف البوابة المُدارة
في قسم الإعدادات من المجموعة، أوقِف البوابة المُدارة. يسحب الإيقاف كل أسماء المضيفين من الحافة، ويزيل كائنات البوابة من المجموعة. تبقى مسارات HTTPRoute وقواعد Ingress لديك، لكنها لا تعود تُخدَم. وأعِد تشغيلها لتعود.
شغّل بوابتك أو متحكّم Ingress الخاص بك
البوابة المُدارة خيار افتراضي، وليست إلزامية. لتقديم HTTP عبر متحكّم من اختيارك:
- في الإعدادات الخاصة بالمجموعة، أوقِف البوابة المُدارة حتى لا يجيب متحكّمان عن موارد Ingress نفسها. ويمكنك أيضًا إبقاؤها مفعّلة ومنح موارد Ingress لديك فئةً خاصة بك.
- ثبّت تطبيق Gateway API أو متحكّم Ingress الذي تفضّله، واعرضه عبر خدمة من نوع
LoadBalancer. يُحتسب من حصة موزّعات الحمل في مساحة عملك، ويجيب على منفذ عام في عنوان IP المشترك لمساحة عملك؛ ولا يمكن بعد منح موزّعات حمل المجموعة عنوان IP مخصّصًا، لذا لا يتاح لها المنفذان 80 و443. - لكي تستخدمه موارد Ingress التي لا تحدّد فئة، اجعل IngressClass الخاصة بك الافتراضية بالتعليق
ingressclass.kubernetes.io/is-default-class: "true". لا تُجعل فئة البوابة المُدارةsahabtiافتراضية إلا إذا لم تكن هناك فئة افتراضية أخرى. - وجّه نطاقك إلى عنوان موزّع الحمل وأدِر شهاداته بنفسك: حافة المنصّة وشهاداتها تخدم البوابة المُدارة فقط.
متى تستخدم موزّع حمل بدلًا منها
استخدم خدمة من نوع LoadBalancer لكل ما ليس موقعًا أو واجهة برمجية، كقواعد البيانات وخوادم الألعاب وحركة TCP أو UDP الخام، أو حين تحتاج إلى إنهاء TLS بنفسك. وتُحتسب كل خدمة منها من حصة موزّعات الحمل في مساحة عملك: انظر موزّع حمل لخدمة. وعلى عنوان IP المشترك لمساحة عملك يستجيب موزّع الحمل على منفذ عام خاص به، فيتصل العملاء باسم مضيفه مع ذلك المنفذ، مثل prod-default-db-e5f6a7b8-q2w7ze.lb.sahabti.app:40002؛ أما HTTPS بلا رقم منفذ فمن شأن البوابة المُدارة.
ولا تزال فئة البوابة sahabti متاحة لتشغيل بوابة خاصة بك خلف موزّع حمل، كما في توجيه HTTP حسب اسم المضيف. وانتبه إلى الأسماء: المسارات المرتبطة بالبوابة sahabti في sahabti-gateway، وقواعد Ingress من الفئة sahabti، تستخدم البوابة المُدارة؛ أما البوابة التي تنشئها أنت بـgatewayClassName: sahabti فتعمل خلف موزّع حمل.