نقل Ingress إلى Kubernetes Gateway API: دليل
١٠ مايو ٢٠٢٦
ملخص
لترحيل Ingress إلى Gateway API في عام 2026، ستقوم بتثبيت CRDs الخاصة بـ Standard channel الإصدار v1.5.1، وتشغيل متحكم Gateway متوافق، وتحويل كل Ingress موجود باستخدام واجهة سطر الأوامر ingress2gateway الإصدار v1.0.0 قبل تحويل حركة المرور باستخدام قواعد HTTPRoute الموزونة. يستعرض هذا الدليل هذا التسلسل بدقة. ستقوم بترحيل نشر ingress-nginx يعمل بالفعل إلى Kubernetes Gateway API v1.5.1 بالكامل على عنقود kind v0.31.0 محلي. يتضمن الشرح تثبيت CRDs الخاصة بـ Standard channel، وتشغيل Envoy Gateway v1.7.2 كمتحكم متوافق، وتحويل ملفات YAML الخاصة بـ Ingress الحالية باستخدام ingress2gateway v1.0.0، وتطبيق موارد Gateway و HTTPRoute الجديدة، وتنفيذ weighted canary split بين إصدارين من التطبيق، والانتهاء بمسار تراجع (rollback) مؤكد. كل إصدار محدد بدقة، وكل أمر قابل للنسخ والتشغيل، ونفس النمط ينتقل بسلاسة إلى GKE أو EKS أو AKS أو أي عنقود متوافق.123
هذا الدليل موجود لأن ingress-nginx وصل إلى نهاية عمره الافتراضي في مارس 2026 — لا توجد إصدارات أخرى، ولا إصلاحات للأخطاء، ولا تحديثات أمنية، وتمت أرشفة مستودع GitHub في 24 مارس 2026.4 كان متحكم ingress-nginx الخاص بالمجتمع هو مسار ingress الافتراضي لشريحة كبيرة من العناقيد السحابية الأصلية، ومسار الاستبدال الرسمي هو Gateway API. معظم الشروحات الموجودة تسبق إصدار ingress2gateway 1.0 (الذي صدر في 20 مارس 2026، مع دعم لأكثر من 30 من annotations الخاصة بـ ingress-nginx2)، والدليل الرسمي من sigs.k8s.io هو بأسلوب مرجعي وليس دليلاً قابلاً للتطبيق المباشر. هذا المنشور يسد تلك الفجوة.
ما ستتعلمه
- كيفية إعداد عنقود kind محلي يحاكي تخطيط الإنتاج الحقيقي لترحيل ingress-to-gateway
- كيفية تثبيت Gateway API v1.5.1 CRDs من Standard channel
- كيفية تثبيت Envoy Gateway v1.7.2 كمتحكم Gateway متوافق عبر Helm
- كيفية نشر تطبيق تجريبي خلف ingress-nginx بالطريقة التي كان يعمل بها عنقود نموذجي من حقبة 2024
- كيفية استخدام
ingress2gatewayv1.0.0 لتحويل Ingress هذا إلىGateway+HTTPRouteتلقائيًا - كيفية تشغيل كلا المتحكمين بالتوازي مع عناوين IP خارجية منفصلة بحيث يكون التحويل خاليًا من المخاطر
- كيفية إجراء weighted canary deployment باستخدام
HTTPRoutebackendRefs(لا يتطلب annotations) - كيفية التراجع (roll back) بأمان عند تراجع أداء الـ canary، وكيفية تنظيف Ingress القديم فقط بعد أن يصبح
Gatewayفي حالةProgrammed=True - قائمة مرجعية للترحيل بالإضافة إلى أكثر خمسة أخطاء شائعة تقع فيها الفرق أثناء عمليات التحويل الحقيقية
المتطلبات الأساسية
| الأداة | الإصدار المحدد في هذا الشرح | لماذا هذا الإصدار |
|---|---|---|
| Docker (أو Podman مع shim الخاص بـ Docker) | 25.x أو أحدث | مطلوب بواسطة kind v0.31.0 |
kind | v0.31.0 | صورة العقدة الافتراضية هي kindest/node:v1.35.0 (Kubernetes 1.35)، صدرت في 18 ديسمبر 202556 |
kubectl | متوافق مع v1.35.x | مطابقة الإصدار الفرعي للعنقود |
helm | v3.18.0 أو أحدث (يوصى بـ 3.20.2) | مخطط Envoy Gateway Helm يستهدف Helm 3.x؛ كان 3.20.2 هو أحدث إصدار 3.x وقت الكتابة7 |
go (فقط في حالة تثبيت ingress2gateway من المصدر) | 1.22+ | مطلوب لـ go install |
ingress2gateway | v1.0.0 | أول إصدار مع تغطية واسعة لـ annotations الخاصة بـ ingress-nginx2 |
| Gateway API CRDs | v1.5.1 (Standard channel) | أحدث تصحيح وقت الكتابة؛ صدر v1.5.0 في 27 فبراير 2026؛ تصحيح v1.5.1 في 14 مارس 202618 |
| Envoy Gateway | v1.7.2 | صدر في 17 أبريل 2026؛ متوافق مع Gateway API v1.53 |
تحتاج أيضًا إلى حوالي 4 جيجابايت من ذاكرة الوصول العشوائي (RAM) الخالية لعنقود kind، والتطبيق التجريبي، و Envoy Gateway، بالإضافة إلى خلو المنفذين 80/443 على localhost.
الخطوة 1: إنشاء عنقود kind مع تعيين المنافذ
احفظ هذا كـ kind-config.yaml. تتيح كتلة extraPortMappings للمضيف الوصول إلى خدمات LoadBalancer بدون cloud-provider-kind ليبقى الشرح مكتفيًا ذاتيًا.
# kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
image: kindest/node:v1.35.0
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
extraPortMappings:
- containerPort: 80
hostPort: 8080
protocol: TCP
- containerPort: 443
hostPort: 8443
protocol: TCP
- role: worker
image: kindest/node:v1.35.0
تسمية ingress-ready=true على عقدة control-plane إلزامية: يقوم بيان ingress-nginx الخاص بـ kind بجدولة pod المتحكم باستخدام nodeSelector يتطلب هذه التسمية، لذا بدونها سيظل pod المتحكم في حالة Pending إلى أجل غير مسمى.9
أنشئ العنقود:
kind create cluster --name gw-migration --config kind-config.yaml
kubectl cluster-info --context kind-gw-migration
المخرجات المتوقعة تنتهي بـ:
Kubernetes control plane is running at https://127.0.0.1:<port>
CoreDNS is running at https://127.0.0.1:<port>/API/v1/namespaces/kube-system/services/kube-dns:dns/proxy
إذا توقف أمر kind create cluster عند "Creating control plane"، فتأكد من أن Docker لديه على الأقل 4 وحدات معالجة مركزية (CPUs) و 6 جيجابايت من ذاكرة الوصول العشوائي في إعدادات الموارد الخاصة به — فالـ 2 جيجابايت الافتراضية لا تكفي لعنقود من عقدتين بالإضافة إلى أعباء العمل التي سنضيفها لاحقًا.
الخطوة 2: نشر إعداد ingress-nginx القديم
هذه هي حالة "ما قبل" — ما يبدو عليه عنقودك الحالي على الأرجح. نحن نستخدم المتحكم المهجور عمدًا حتى يكون لخطوة الترحيل شيء حقيقي لتحويله.
kubectl apply -f https://raw.githubusercontent.com/Kubernetes/ingress-nginx/controller-v1.13.7/deploy/static/provider/kind/deploy.yaml
kubectl wait --namespace ingress-nginx \
--for=condition=ready pod \
--selector=app.Kubernetes.io/component=controller \
--timeout=180s
الآن قم بنشر تطبيق تجريبي — إصداران من HTTP "echo" حتى نتمكن من تجربة تقسيم الـ canary لاحقًا:
# echo-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo-v1
labels: { app: echo, version: v1 spec:
replicas: 2
selector:
matchLabels: { app: echo, version: v1 template:
metadata:
labels: { app: echo, version: v1 spec:
containers:
- name: echo
image: ghcr.io/mendhak/http-https-echo:40
ports: [{ containerPort: 8080 ]
env:
- name: HTTP_PORT
value: "8080"
- name: ECHO_INCLUDE_ENV_VARS
value: "1"
- name: VERSION
value: "v1"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo-v2
labels: { app: echo, version: v2 spec:
replicas: 2
selector:
matchLabels: { app: echo, version: v2 template:
metadata:
labels: { app: echo, version: v2 spec:
containers:
- name: echo
image: ghcr.io/mendhak/http-https-echo:40
ports: [{ containerPort: 8080 ]
env:
- name: HTTP_PORT
value: "8080"
- name: ECHO_INCLUDE_ENV_VARS
value: "1"
- name: VERSION
value: "v2"
---
apiVersion: v1
kind: Service
metadata: { name: echo-v1 spec:
selector: { app: echo, version: v1 ports: [{ port: 80, targetPort: 8080 ]
---
apiVersion: v1
kind: Service
metadata: { name: echo-v2 spec:
selector: { app: echo, version: v2 ports: [{ port: 80, targetPort: 8080 ]
kubectl apply -f echo-app.yaml
و Ingress "ما قبل" الذي سيقوم الترحيل بتحويله. لاحظ annotations الخاصة بـ ingress-nginx — هذه هي بالضبط النوعية التي تحفز الانتقال إلى Gateway API:
# legacy-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: echo-ingress
annotations:
nginx.ingress.Kubernetes.io/rewrite-target: /
nginx.ingress.Kubernetes.io/enable-cors: "true"
nginx.ingress.Kubernetes.io/cors-allow-methods: "GET, POST, OPTIONS"
spec:
ingressClassName: nginx
rules:
- host: echo.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: echo-v1
port:
number: 80
kubectl apply -f legacy-ingress.yaml
تحقق من أنه يعمل:
curl -H "Host: echo.local" http://localhost:8080/ | head -20
يجب أن ترى تفريغ JSON يتضمن "VERSION": "v1". إذا رأيت بدلاً من ذلك default backend - 404، فامنح متحكم ingress 30 ثانية أخرى — حيث يقوم extraPortMappings بتوجيه الطلب فقط بمجرد قيام خدمة LoadBalancer بتعيين المنفذ لـ pod المتحكم.
الخطوة 3: تثبيت Gateway API v1.5.1 CRDs
يتم شحن Gateway API مع CRDs الخاصة به بشكل منفصل عن أي متحكم. قم بتثبيت Standard channel (واجهات برمجة تطبيقات مستقرة و GA):110
kubectl apply -f https://GitHub.com/Kubernetes-sigs/gateway-API/releases/download/v1.5.1/standard-install.yaml
تأكيد التثبيت:
kubectl get crd | grep gateway.networking.k8s.io
المخرجات المتوقعة (بأي ترتيب):
backendtlspolicies.gateway.networking.k8s.io 2026-05-10T12:00:00Z
gatewayclasses.gateway.networking.k8s.io 2026-05-10T12:00:00Z
gateways.gateway.networking.k8s.io 2026-05-10T12:00:00Z
grpcroutes.gateway.networking.k8s.io 2026-05-10T12:00:00Z
httproutes.gateway.networking.k8s.io 2026-05-10T12:00:00Z
referencegrants.gateway.networking.k8s.io 2026-05-10T12:00:00Z
tlsroutes.gateway.networking.k8s.io 2026-05-10T12:00:00Z
TLSRoute هو الوافد الجديد في الإصدار v1.5 — حيث تمت ترقيته من Experimental إلى Standard جنباً إلى جنب مع ListenerSet، وفلتر CORS الخاص بـ HTTPRoute، والتحقق من شهادة العميل (Client Certificate Validation)، واختيار الشهادة لـ Gateway TLS Origination، مع انتقال ReferenceGrant أيضاً إلى v1 في هذا الإصدار.11 أما BackendTLSPolicy فقد تخرجت في وقت سابق (v1.4). إذا رأيت ستة CRDs فقط، فهذا يعني أنك قمت بتثبيت ملف manifest قديم من الإصدار 1.4.
إذا كنت بحاجة أيضاً إلى واجهات برمجة التطبيقات التجريبية (مثل XBackendTrafficPolicy)، فإن kubectl apply سيرفض الـ manifest لأن الـ CRDs التجريبية تتجاوز حجم الطلب القياسي — استخدم kubectl apply --server-side=true بدلاً من ذلك.12 لا نحتاج إلى واجهات برمجة تطبيقات تجريبية لهذا البرنامج التعليمي.
الخطوة 4: تثبيت Envoy Gateway v1.7.2 كمتحكم (Controller)
Gateway API هي مواصفة CRD؛ ويعتمد السلوك على المتحكم. يعد Envoy Gateway أحد الخيارات المتوافقة العديدة (مثل NGINX Gateway Fabric و Cilium و Istio و Kong و Traefik). إنه محايد للبائعين، ويتم توزيعه كـ OCI Helm chart، وله بصمة صغيرة من الأجزاء المتحركة بالنسبة لبرنامج تعليمي.313
قم بتثبيت لوحة التحكم (control plane) باستخدام --skip-crds لأننا قمنا بالفعل بتثبيت CRDs القناة القياسية (Standard channel) للإصدار v1.5.1 في الخطوة 3. لا يزال Helm chart الافتراضي لـ Envoy Gateway يتضمن نسخة من CRDs القناة التجريبية (Experimental channel) لـ Gateway API (وهي عملية انتقال جارية حالياً في المشروع الأساسي)، لذا فإن حذف --skip-crds سيؤدي إلى الكتابة فوق الـ CRDs القياسية التي طبقتها للتو:14
helm install eg oci://Docker.io/envoyproxy/gateway-helm \
--version v1.7.2 \
-n envoy-gateway-system \
--create-namespace \
--skip-crds
kubectl wait --timeout=5m \
-n envoy-gateway-system \
deployment/envoy-gateway \
--for=condition=Available
لا يقوم Helm chart بإنشاء GatewayClass لك — يترك ذلك للمستخدم بحيث يمكن إعادة استخدام نفس المتحكم تحت أسماء فئات مختلفة. قم بتطبيق واحدة بشكل صريح:
# gatewayclass.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: eg
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
kubectl apply -f gatewayclass.yaml
kubectl get gatewayclass
المتوقع:
NAME CONTROLLER ACCEPTED AGE
eg gateway.envoyproxy.io/gatewayclass-controller True 10s
ملاحظة: لديك الآن مساران للدخول (ingress) في العنقود:
- متحكم
ingress-nginxالقديم المرتبط بـIngressClass: nginx، والذي يوجه لـecho-v1عبر الـIngressالحالي. - الـ
GatewayClass: egالجديد الذي ينتظرGatewayوHTTPRouteللإشارة إليه.
يحصل كل منهما على نقطة نهاية خارجية خاصة به. هذا هو نمط الأمان الذي يوصي به دليل الهجرة الرسمي صراحةً — قم بتشغيل كليهما، وتحقق من المسار الجديد بحركة مرور معزولة، ثم قم بالتحويل الكامل.15
الخطوة 5: تحويل Ingress باستخدام ingress2gateway 1.0
قم بتثبيت أداة التحويل. أي من الطريقتين تعمل:
# الخيار أ — تثبيت Go (يتطلب Go 1.22+)
go install GitHub.com/Kubernetes-sigs/ingress2gateway@v1.0.0
# الخيار ب — Homebrew (macOS / Linuxbrew)
brew install ingress2gateway
ingress2gateway --version
قم بتحويل Ingress المباشر إلى موارد Gateway API. تقرأ الأداة من سياق kubeconfig الخاص بك وتترجم تعليقات ingress-nginx التوضيحية (annotations) باستخدام أكثر من 30 تعييناً مدعوماً (CORS، و rewrite-target، ومطابقة regex، و backend TLS، والمزيد):2
ingress2gateway print \
--providers=ingress-nginx \
--namespace=default \
> gwapi.yaml
افتح gwapi.yaml وسترى شيئاً كهذا (تم تنظيفه لسهولة القراءة):
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: echo-ingress
namespace: default
spec:
gatewayClassName: nginx # <-- يجب عليك تغيير هذا
listeners:
- name: http
port: 80
protocol: HTTP
hostname: echo.local
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: echo-ingress
namespace: default
spec:
parentRefs:
- name: echo-ingress
hostnames:
- echo.local
rules:
- matches:
- path:
type: PathPrefix
value: /
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplaceFullPath
replaceFullPath: /
- type: CORS
cors:
allowMethods: ["GET", "POST", "OPTIONS"]
backendRefs:
- name: echo-v1
port: 80
weight: 100
أمران يجب معرفتهما عن المخرجات:
gatewayClassName: nginxغير صحيح — تقوم أداة التحويل بنسخingressClassNameحرفياً. يجب عليك تغييره إلىeg(أو أي GatewayClass قام المتحكم الخاص بك بتثبيته) قبل التطبيق. هذا أحد أسهل الأخطاء التي يمكن ارتكابها أثناء عمليات الهجرة الحقيقية لأن التحويل يبدو مكتملاً.2- فلتر
URLRewriteوفلترCORSيأتيان مباشرة من تعليقات ingress-nginx التوضيحية الأصلية. تخرج فلتر CORS إلى القناة القياسية (Standard) في Gateway API v1.5، لذا فهو الآن مستقر عبر المتحكمات المتوافقة.11
قم بتحرير الملف وتطبيقه:
sed -i.bak 's/gatewayClassName: nginx/gatewayClassName: eg/' gwapi.yaml
kubectl apply -f gwapi.yaml
انتظر حتى تصبح الـ Gateway في حالة Programmed=True — هذه هي الإشارة التي تخبرك بأن المتحكم قد قام بالفعل ببرمجة Envoy للاستماع على المنفذ المطلوب. لا تحذف Ingress القديم حتى تصبح هذه الحالة True:15
kubectl wait --timeout=2m \
gateway/echo-ingress \
--for=condition=Programmed
المتوقع:
gateway.gateway.networking.k8s.io/echo-ingress condition met
الخطوة 6: اختبار مسار Gateway الجديد بالتوازي مع Ingress القديم
خدمة Envoy Gateway هي LoadBalancer في مساحة الاسم envoy-gateway-system. ابحث عن المنفذ المخصص لها على المضيف (يقوم kind بإعداد نطاقات NodePort، ويمكن الوصول إلى خدمة المتحكم داخل العنقود):
kubectl get svc -n envoy-gateway-system
الخدمة المسماة envoy-default-echo-ingress-... هي لوحة البيانات (data plane). سنصل إليها مباشرة باستخدام kubectl port-forward حتى لا نحتاج إلى تكامل kind LoadBalancer:
GW_SVC=$(kubectl get svc -n envoy-gateway-system \
-l gateway.envoyproxy.io/owning-gateway-name=echo-ingress \
-o jsonpath='{.items[0].metadata.name}')
kubectl port-forward -n envoy-gateway-system "svc/$GW_SVC" 9080:80 &
اختبر مسار Gateway الجديد:
curl -H "Host: echo.local" http://localhost:9080/ | grep VERSION
المتوقع:
"VERSION": "v1",
الآن قم بالوصول إلى Ingress القديم في نفس الوقت — منفذ مختلف، نفس عنوان المضيف (host header):
curl -H "Host: echo.local" http://localhost:8080/ | grep VERSION
كلاهما يعيد "VERSION": "v1". لديك الآن مساران مستقلان للدخول إلى نفس الواجهة الخلفية، مع نقاط نهاية خارجية منفصلة. هذه هي اللحظة المناسبة لتوجيه نسبة مئوية صغيرة من حركة المرور الحقيقية (عبر DNS round-robin، أو موازن حمل خارجي، أو رأس canary داخلي) إلى المسار الجديد ومراقبة المقاييس لمدة ساعة أو يوم قبل المتابعة.15
الخطوة 7: إضافة تقسيم canary موزون باستخدام HTTPRoute
هنا تظهر قيمة Gateway API. مع ingress-nginx، ستحتاج إما إلى Ingress منفصل لكل إصدار بالإضافة إلى التعليق التوضيحي nginx.ingress.Kubernetes.io/canary-weight، أو شبكة خدمات (service mesh). مع Gateway API، يقبل حقل backendRefs في HTTPRoute الأوزان بشكل أصلي كـ API من الدرجة الأولى.16
قم بتحرير gwapi.yaml واستبدل backendRef الواحد بتقسيم موزون:
# gwapi.yaml — قسم HTTPRoute فقط
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: echo-ingress
namespace: default
spec:
parentRefs:
- name: echo-ingress
hostnames:
- echo.local
rules:
- matches:
- path:
type: PathPrefix
value: /
filters:
- type: CORS
cors:
allowMethods: ["GET", "POST", "OPTIONS"]
backendRefs:
- name: echo-v1
port: 80
weight: 90
- name: echo-v2
port: 80
weight: 10
قم بالتطبيق والتحقق من التقسيم:
kubectl apply -f gwapi.yaml
for i in $(seq 1 100); do
curl -s -H "Host: echo.local" http://localhost:9080/ \
| grep -oE '"VERSION": *"v[12]"'
done | sort | uniq -c
المتوقع (تقريبياً — العينات الصغيرة تحتوي على ضوضاء):
90 "VERSION": "v1"
10 "VERSION": "v2"
يتم فرض التقسيم بواسطة Envoy في كل طلب. لا يوجد تعليق توضيحي، ولا Ingress ثانٍ، ولا sidecar لشبكة خدمات — مجرد HTTPRoute واحد حيث تجمع أوزان backendRefs الخاصة به لتصل إلى أي نسبة تريدها. رفع v2 إلى 50/50، ثم 10/90، ثم التحويل النهائي إلى 100/0 هو مجرد ثلاث عمليات kubectl apply على نفس الملف.
للترقية الآلية، يتكامل Flagger بشكل أصلي مع موارد Gateway API HTTPRoute ويعمل مع أي متحكم متوافق.17 هذا خارج نطاق دليل الهجرة هذا ولكنه الخطوة التالية الصحيحة بمجرد نجاح التحويل اليدوي.
الخطوة 8: التحقق والتراجع
الـ canary الذي يتراجع يحتاج إلى أمر واحد للإلغاء. ولأن الهجرة أبقت على Ingress الأصلي في مكانه، فإن تراجعك هو انسحاب من خطوتين:
# الخطوة 1 — أعد توجيه HTTPRoute إلى v1 فقط
kubectl patch httproute echo-ingress \
--type='merge' \
-p '{"spec":{"rules":[{"matches":[{"path":{"type":"PathPrefix","value":"/"}}],"backendRefs":[{"name":"echo-v1","port":80,"weight":100}]}]}}'
# الخطوة 2 — إذا كان الـ Gateway نفسه لا يعمل بشكل صحيح، وجه حركة المرور الخارجية
# مرة أخرى إلى نقطة نهاية ingress القديمة (المنفذ 8080 في إعداد kind هذا،
# أو ingress-nginx LoadBalancer في بيئة الإنتاج)
إن بقاء "الـ Ingress القديم موجوداً" هو السبب الكامل لنمط النشر المتوازي. لا تحذف الـ Ingress القديم حتى يتم تحويل حركة المرور بالكامل، ويكون الـ Gateway في حالة Programmed=True، وتكون قد راقبت مقاييس الإنتاج لدورة حركة مرور كاملة واحدة على الأقل (عادةً 24 ساعة). يشير دليل الهجرة الرسمي صراحةً إلى ذلك: احذف موارد Ingress بشكل تدريجي، واحداً تلو الآخر، مع التحقق بعد كل عملية حذف.15
الخطوة 9: إيقاف تشغيل ingress-nginx
بمجرد أن يحمل الـ Gateway الجديد 100% من حركة مرور الإنتاج لفترة زمنية تمثيلية، قم بالتنظيف:
# 1. حذف الـ Ingress القديم
kubectl delete ingress echo-ingress
# 2. التأكد من عدم بقاء أي كائنات Ingress أخرى في العنقود (cluster)
kubectl get ingress -A
# 3. بمجرد أن تظهر نتيجة "No resources found"، قم بإلغاء تثبيت ingress-nginx
kubectl delete -f https://raw.githubusercontent.com/Kubernetes/ingress-nginx/controller-v1.13.7/deploy/static/provider/kind/deploy.yaml
إذا كان أمر kubectl get ingress -A لا يزال يعرض كائنات في مساحات أسماء (namespaces) أخرى، توقف. كرر عملية الهجرة لكل منها قبل إزالة المتحكم (controller) — فتعطل ingress-nginx بينما يشير Ingress قديم واحد إليه سيؤدي إلى ضياع حركة المرور تلك تماماً.
قائمة مراجعة الهجرة
استخدم قائمة المراجعة هذه في كل مرة تقوم فيها بهجرة Ingress إلى Gateway API في بيئة الإنتاج، وليس فقط على kind:
| الخطوة | الأمر / الإجراء | تم؟ |
|---|---|---|
| 1 | جرد جميع موارد Ingress: kubectl get ingress -A -o yaml > all-ingresses.yaml | |
| 2 | مراجعة تعليقات (annotations) ingress-nginx: grep nginx.ingress.Kubernetes.io all-ingresses.yaml | sort -u | |
| 3 | التأكد من أن كل تعليق موجود في قائمة ingress2gateway 1.0 المدعومة، أو لديه خطة ترجمة يدوية2 | |
| 4 | تثبيت Gateway API v1.5.1 Standard channel CRDs1 | |
| 5 | تثبيت متحكم متوافق (Envoy Gateway، NGINX Gateway Fabric، Cilium، Istio، إلخ) إلى جانب ingress-nginx | |
| 6 | تشغيل ingress2gateway print --all-namespaces --providers=ingress-nginx > gwapi.yaml2 | |
| 7 | إصلاح gatewayClassName يدوياً (دائماً ما يكون خاطئاً بشكل افتراضي) | |
| 8 | التطبيق، ثم kubectl wait --for=condition=Programmed gateway/<name>15 | |
| 9 | إرسال حركة مرور تجريبية (canary) عبر DNS، أو LB خارجي، أو قاعدة رأس (header rule) | |
| 10 | المراقبة لدورة حركة مرور كاملة واحدة على الأقل | |
| 11 | تحويل حركة المرور المتبقية مع تغييرات أوزان (weight) HTTPRoute | |
| 12 | حذف كل Ingress واحداً تلو الآخر؛ والتحقق من التوفر بين عمليات الحذف15 | |
| 13 | إلغاء تثبيت ingress-nginx فقط بعد أن يعيد kubectl get ingress -A نتيجة فارغة |
استكشاف الأخطاء وإصلاحها: أخطاء حقيقية من متتبع مشكلات GitHub
خطأ: Forbidden: estimated rule cost exceeds budget عند تطبيق CRDs.
هذا عرض لمحاولة تثبيت ملف بيان القناة التجريبية (experimental) باستخدام kubectl apply عادي. تشحن CRDs التجريبية قواعد تحقق أكثر مما تسمح به ميزانية الطلب الافتراضية. إما أن تقوم بتثبيت القناة القياسية (standard) (مسار هذا البرنامج التعليمي) أو استخدم kubectl apply --server-side=true.12
خطأ: HTTPRoute هو Accepted=True ولكن ResolvedRefs=False.
الـ Service المشار إليها في backendRefs غير موجودة أو موجودة في مساحة أسماء مختلفة بدون ReferenceGrant. قم بتشغيل kubectl describe httproute <name> واقرأ رسالة حالة ResolvedRefs. السببان الشائعان هما الأخطاء المطبعية في اسم الـ Service والمراجع عبر مساحات الأسماء التي تحتاج إلى ReferenceGrant صريح (المورد الذي يأذن بالمراجع عبر مساحات الأسماء — والذي انتقل إلى v1 / GA في Gateway API v1.5).11
خطأ: Gateway هو Accepted=True ولكنه لا يصل أبداً إلى Programmed=True.
لا يمكن للمتحكم تخصيص المستمع (listener) المطلوب — عادةً بسبب تعارض في المنفذ على خدمة LoadBalancer الخاصة بمستوى البيانات أو فقدان سر (secret) TLS لمستمع HTTPS. تحقق من kubectl get svc -n envoy-gateway-system للبحث عن عناوين IP خارجية عالقة في حالة <pending>، و kubectl logs -n envoy-gateway-system deployment/envoy-gateway لرؤية وجهة نظر المتحكم.
خطأ: gatewayClassName: nginx غير موجود بعد تحويل ingress2gateway.
لقد نسيت خطوة sed في الخطوة 5. يقوم المحول بنسخ ingressClassName المصدر حرفياً لأنه لا يمكنه معرفة متحكم Gateway الذي تقوم بتشغيله بالفعل. افتح gwapi.yaml، وقم بتغييره إلى اسم GatewayClass من kubectl get gatewayclass، ثم أعد التطبيق.
تحذير: حقل weight يقرب الطلبات بشكل غير متساوٍ عند أحجام العينات الصغيرة.
هذا متوقع — الأوزان احتمالية لكل طلب، وليست توزيعاً دورياً (round-robin) صارماً. مع أوزان 90/10، لن تنتج عشرة طلبات بشكل حتمي تسعة v1 + واحد v2؛ قد ترى عشرة v1 متتالية. حجم العينة مهم؛ عبر أكثر من 1000 طلب تتقارب النسبة. إذا كنت بحاجة إلى توجيه حتمي، فاستخدم القواعد المطابقة للرأس (header-matched rules) بدلاً من الأوزان.16
الخطوات التالية
الآن بعد أن تمت عملية الهجرة من البداية إلى النهاية على kind، فإن قائمة مراجعة الإنتاج هي:
- ربط Flagger أو Argo Rollouts لأتمتة ترقية النسخة التجريبية (canary) مقابل نفس الـ
HTTPRoute.17 - إضافة قابلية الملاحظة (observability) إلى مستوى البيانات: يوفر Envoy Gateway مقاييس Prometheus بشكل جاهز؛ وتوسع موارد v1.5 المستقرة (
BackendTLSPolicy،Client Certificate Validation) نفس النموذج ليشمل mTLS بين الـ Gateway والـ pods.11 - اقرأ سياق تصميم gateway API الأعمق في دليل أنماط gateway API قبل التوسع إلى ما بعد عنقود واحد.
- بالنسبة للفرق التي لا تزال في مرحلة التعرف على Kubernetes نفسه، يغطي دليلنا العملي لـ Kubernetes مفاهيم مستوى العنقود التي يبني عليها Gateway API.
- إذا كنت قادماً من سير عمل يركز على Docker أولاً، فإن نظرة عامة على Docker مقابل Kubernetes تشرح موقع طبقة المتحكم هذه في المكدس التقني.
الفرق التي تهاجر من Ingress إلى Gateway API الآن ستكون سباقة عندما تنتهي صلاحية آخر إصلاح أمني لـ ingress-nginx؛ أما الفرق التي تنتظر فستقوم بترقيع متحكم ميت. لم يعد Gateway API هو مستقبل شبكات Kubernetes — اعتباراً من عام 2026، أصبح هو الحاضر. لقد تقاعد ingress-nginx، وأصبح نظام التوافق ناضجاً، وأداة ingress2gateway 1.0 تجعل التحويل آلياً للحالات الشائعة. العمل المتبقي هو المناورة التشغيلية الدقيقة: النشر المتوازي، التحويل التدريجي، وحذف Ingress واحداً تلو الآخر.
Footnotes
-
Kubernetes SIG Network، "Gateway API v1.5: نقل الميزات إلى الحالة المستقرة"، 21 أبريل 2026 (تم تعديل المنشور لتصحيح تاريخ إصدار v1.5.0 إلى 27 فبراير 2026). https://Kubernetes.io/blog/2026/04/21/gateway-API-v1-5/ ↩ ↩2 ↩3 ↩4
-
Kubernetes SIG Network، "الإعلان عن Ingress2Gateway 1.0: طريقك إلى Gateway API"، 20 مارس 2026. https://Kubernetes.io/blog/2026/03/20/ingress2gateway-1-0-release/ ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7
-
إصدارات Envoy Gateway (تم نشر v1.7.2 في 17 أبريل 2026). https://GitHub.com/envoyproxy/gateway/releases ↩ ↩2 ↩3
-
Kubernetes SIG Network، "تقاعد Ingress NGINX: ما تحتاج إلى معرفته"، 11 نوفمبر 2025. https://Kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/ ↩
-
صفحة إصدار kind v0.31.0 (صورة العقدة الافتراضية
kindest/node:v1.35.0). https://GitHub.com/Kubernetes-sigs/kind/releases/tag/v0.31.0 ↩ -
دليل البدء السريع لـ kind. https://kind.sigs.k8s.io/docs/user/quick-start/ ↩
-
إصدارات Helm (v3.20.2، 8 أبريل 2026). https://GitHub.com/helm/helm/releases ↩
-
علامة إصدار Gateway API v1.5.1. https://GitHub.com/Kubernetes-sigs/gateway-API/releases/tag/v1.5.1 ↩
-
دليل تثبيت ingress لـ kind — ملصق
ingress-ready=trueمطلوب بواسطة manifest ingress-nginx الخاص بـ kind. https://kind.sigs.k8s.io/docs/user/ingress/ ↩ -
دليل البدء مع Gateway API — التثبيت. https://gateway-API.sigs.k8s.io/guides/getting-started/ ↩
-
ترقيات Gateway API v1.5 المستقرة: ListenerSet، TLSRoute، HTTPRoute CORS Filter، Client Certificate Validation، Certificate Selection for Gateway TLS Origination، و ReferenceGrant تنتقل إلى v1. https://Kubernetes.io/blog/2026/04/21/gateway-API-v1-5/ ↩ ↩2 ↩3 ↩4
-
مشكلة Gateway API رقم 3256 — "تتجاوز تكلفة القاعدة المقدرة الميزانية" مع التطبيق غير المعتمد على جانب الخادم (non-server-side apply). https://GitHub.com/Kubernetes-sigs/gateway-API/issues/3256 ↩ ↩2
-
قائمة تطبيقات Gateway API. https://gateway-API.sigs.k8s.io/implementations/ ↩
-
مشكلة Envoy Gateway رقم 7238 — "الابتعاد عن الإعداد الافتراضي من قناة Gateway API التجريبية إلى القناة القياسية لـ CRDs". https://GitHub.com/envoyproxy/gateway/issues/7238 ↩
-
دليل هجرة Gateway API — "الهجرة من Ingress-NGINX". https://gateway-API.sigs.k8s.io/guides/getting-started/migrating-from-ingress-nginx/ ↩ ↩2 ↩3 ↩4 ↩5 ↩6
دليل تقسيم حركة مرور Gateway API HTTP — مراجع الواجهة الخلفية الموزونة (weighted backendRefs). https://gateway-API.sigs.k8s.io/guides/traffic-splitting/ ↩ ↩2
"كيفية تكوين Flagger مع Gateway API HTTPRoute"، ١٣ مارس ٢٠٢٦. https://oneuptime.com/blog/post/2026-03-13-how-to-configure-flagger-with-gateway-API-httproute/view ↩ ↩2