Kubernetes Ingress-NGINX در مارس 2026 بازنشسته می‌شود و اگر هنوز در خوشه‌تان از آن استفاده می‌کنید، خوب است از رفتارهای پیش‌فرض عجیب و تأثیرات جانبی‌اش آگاه باشید تا هنگام مهاجرت به Gateway API یا کنترل‌کننده‌های دیگر دچار قطعی نشوید. در ادامه پنج رفتار مهم را با توضیح و نمونه می‌بینید و نحوهٔ حفظ همان رفتارها در Gateway API را هم نشان می‌دهم. 😊

الگوی ریسک تکرارشونده ساده است: ترجمهٔ ظاهراً درست از پیکربندی Ingress-NGINX ممکن است به قطع منجر شود اگر خصوصیات واقعی Ingress-NGINX را در نظر نگیرید. فرض می‌کنم شما با Ingress-NGINX و Ingress API آشنا هستید و اکثر نمونه‌ها backend را httpbin نشان می‌دهند.

نکتهٔ مهم: Ingress-NGINX و NGINX Ingress دو پروژهٔ جدا هستند — اولی توسط جامعهٔ Kubernetes نگهداری می‌شود و دومی توسط F5. این نوشته فقط دربارهٔ Ingress-NGINX است. 🔎

1) Regex در Ingress-NGINX مبتنی بر پیشوند است و به حروف بزرگ/کوچک حساس نیست — یعنی الگوی ظاهراً محدود می‌تواند ترافیک بیشتری بگیرد و باعث قطع شود. مثال Ingress با annotation use-regex:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: regex-match-ingress
  annotations:
    nginx.ingress.kubernetes.io/use-regex: "true"
spec:
  ingressClassName: nginx
  rules:
  - host: regex-match.example.com
    http:
      paths:
      - path: "/[A-Z]{3}"
        pathType: ImplementationSpecific
        backend:
          service:
            name: httpbin
            port:
              number: 8000

با این پیکربندی، Ingress-NGINX مسیرها را به عنوان regex پیشوندی و بدون حساسیت به حروف بزرگ/کوچک تفسیر می‌کند؛ یعنی درخواست‌هایی مثل /uuid/ هم می‌توانند به httpbin بروند. وقتی Gateway API تعریف می‌کنید، به پیاده‌سازی‌تان دقت کنید: برخی پیاده‌سازی‌های مبتنی بر Envoy (مثل Istio، Envoy Gateway و Kgateway) تطابق RegularExpression را به‌صورت case-sensitive یا full-match پیاده‌سازی می‌کنند، پس ممکن است تبدیل مستقیم باعث شود مسیرهایی که قبلاً کار می‌کردند اکنون 404 بدهند.

مثال تحول به HTTPRoute با RegularExpression (پیاده‌سازی‌ها متفاوت هستند؛ قبل از تبدیل بررسی کنید):

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: regex-match-route
spec:
  hostnames:
  - "regex-match.example.com"
  parentRefs:
  - name: gateway-name
  rules:
  - matches:
    - path:
        type: RegularExpression
        value: "/[a-zA-Z]{3}.*"
    backendRefs:
    - name: httpbin
      port: 8000

اگر پیاده‌سازی Gateway API شما تطابق case-sensitive و full-match انجام دهد، الگوی بالا را باید به شکلی بنویسید که رفتار Ingress-NGINX (پیشوندی و case-insensitive) را شبیه‌سازی کند یا از regexهای مربوط به پیاده‌سازی استفاده کنید (مثلاً (?i) برای case-insensitive اگر پشتیبانی شود). ✅

2) annotation nginx.ingress.kubernetes.io/use-regex وقتی برای یک Ingress روی یک Host فعال شود، روی همهٔ مسیرهای همان Host در همهٔ Ingressها تأثیر می‌گذارد — بنابراین یک اشتباه تایپی در یکی از مسیرها می‌تواند باعث شود مسیرهای دیگر هم به عنوان regex تفسیر شوند و ترافیک غیرمنتظره گرفته شود. مثالی از این وضعیت:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: regex-host-enable
  annotations:
    nginx.ingress.kubernetes.io/use-regex: "true"
spec:
  rules:
  - host: regex-match.example.com
    http:
      paths:
      - path: "/"
        pathType: ImplementationSpecific
        backend:
          service:
            name: httpbin
            port:
              number: 8000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: regex-host-spelling-mistake
spec:
  rules:
  - host: regex-match.example.com
    http:
      paths:
      - path: "/Header"   # اشتباه تایپی؛ انتظار می‌رفت /headers
        pathType: ImplementationSpecific
        backend:
          service:
            name: httpbin
            port:
              number: 8000

در این سناریو، چون اولین Ingress برای همان host use-regex را روشن کرده، مسیر “/Header” به صورت regex و پیشوندی و case-insensitive تفسیر می‌شود و درخواست‌های واقعی به “/headers” هم ممکن است به httpbin هدایت شوند. اگر این را هنگام تبدیل به HTTPRoute نادیده بگیرید و مسیرها را به صورت exact تعریف کنید، ترافیک ممکن است 404 بگیرید. 🚨

برای حفظ رفتار پیشوندی و case-insensitive در Gateway API، دو راه دارید: یا از RegularExpression با الگوهای case-insensitive استفاده کنید، یا اشتباهات املایی را اصلاح و از exact match استفاده کنید. نمونهٔ جایگزین با RegularExpression:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: regex-preserve-route
spec:
  hostnames:
  - "regex-match.example.com"
  parentRefs:
  - name: gateway-name
  rules:
  - matches:
    - path:
        type: RegularExpression
        value: "(?i)/headers.*"
    backendRefs:
    - name: httpbin
      port: 8000

3) annotation nginx.ingress.kubernetes.io/rewrite-target به‌طور ناخودآگاه nginx.ingress.kubernetes.io/use-regex را فعال می‌کند — یعنی اگر برای یک Ingress از rewrite-target استفاده کنید، همهٔ مسیرهای آن host به عنوان regex تفسیر می‌شوند (و اثرات مورد بحث بالا را دارند). مثال:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: rewrite-target-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: "/uuid"
spec:
  rules:
  - host: rewrite-target.example.com
    http:
      paths:
      - path: "/IP"
        pathType: ImplementationSpecific
        backend:
          service:
            name: httpbin
            port:
              number: 8000
      - path: "/Header"
        pathType: ImplementationSpecific
        backend:
          service:
            name: httpbin
            port:
              number: 8000

این annotation باعث می‌شود مسیرهایی مثل /ip یا /headers هم (به‌دلیل رفتار پیشفرض regex و بی‌حساس به حروف) بازنویسی و هدایت شوند. اگر این اثر را نشناسید و معادلش را با HTTPRouteِ exact تعریف کنید، باز هم به 404 خواهید رسید.

نحوهٔ تبدیل صحیح در Gateway API: یا از فیلترهای URLRewrite در کنار RegularExpression استفاده کنید یا مسیرها را تصحیح کنید تا exact match واقعی باشند. مثال HTTPRoute اشتباه که منجر به 404 می‌شود (exact برای “/IP”) و نمونهٔ درست با RegularExpression:

# مثال HTTPRoute اشتباه (ممکن است /ip را match نکند)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: rewrite-target-wrong
spec:
  hostnames:
  - "rewrite-target.example.com"
  parentRefs:
  - name: gateway-name
  rules:
  - matches:
    - path:
        type: Path
        value: "/IP"
    filters:
    - type: URLRewrite
      urlRewrite:
        path:
          type: ReplaceFullPath
          replaceFullPath: "/uuid"
    backendRefs:
    - name: httpbin
      port: 8000
---
# تبدیل صحیح: استفاده از RegularExpression (case-insensitive)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: rewrite-target-correct
spec:
  hostnames:
  - "rewrite-target.example.com"
  parentRefs:
  - name: gateway-name
  rules:
  - matches:
    - path:
        type: RegularExpression
        value: "(?i)/IP.*"
    filters:
    - type: URLRewrite
      urlRewrite:
        path:
          type: ReplaceFullPath
          replaceFullPath: "/uuid"
    backendRefs:
    - name: httpbin
      port: 8000

4) درخواست‌هایی که بدون اسلش انتهایی می‌آیند ممکن است در Ingress-NGINX به /with-trailing/ با 301 redirect هدایت شوند — یعنی Ingress-NGINX خودش redirect می‌سازد تا مسیر با trailing slash مطابقت پیدا کند. اگر به تبدیل این رفتار در Gateway API فکر می‌کنید، دقت کنید که Gateway API و پیاده‌سازی‌های مختلف ممکن است این redirect را خودکار انجام ندهند و لازم باشد صریحاً آن را پیاده‌سازی کنید (مثلاً با rewrite یا redirect rule در gateway implementation). 🔁

5) در مجموع: هنگام مهاجرت از Ingress-NGINX به Gateway API یا کنترل‌کنندهٔ دیگر، حتماً این موارد را بررسی کنید:

• آیا از nginx.ingress.kubernetes.io/use-regex یا nginx.ingress.kubernetes.io/rewrite-target استفاده شده؟ اینها می‌توانند رفتار مسیرها را به‌کل تغییر دهند. 🧭

• الگوهای regex در Ingress-NGINX پیشوندی و بی‌حساس به حروف بزرگ/کوچک هستند — اما در Gateway API ممکن است full-match و case-sensitive باشند؛ الگوها را مطابق پیاده‌سازی مقصد بازنویسی کنید. ✍️

• یک annotation در یک Ingress می‌تواند بر همهٔ Ingressهای آن host اثر بگذارد — پس همهٔ ingressها و مسیرهای مربوط به یک host را با دقت بررسی کنید. 🔎

• اگر از rewrite استفاده می‌کنید، انتظار نداشته باشید که رفتار معادل به‌صورت پیش‌فرض در Gateway API حفظ شود؛ نیاز به تعریف explicit URLRewrite یا regex دارید. 🛠️

• تست گسترده با نمونه‌های واقعی (مثلاً curl با Host header و مسیرهای با حالات مختلف حروف و trailing slash) را فراموش نکنید تا قبل از برش ترافیک زنده مشکلات را پیدا کنید. 🧪

خلاصهٔ عملی: هنگام تبدیل، اول inventory کامل از annotationها و مسیرها بگیرید، رفتار regex/case-sensitivity و rewrite را مشخص کنید، و سپس یا الگوهای RegularExpression مناسب (با گزینهٔ case-insensitive اگر لازم است) در HTTPRouteها بنویسید یا مسیرهای exact را اصلاح کنید تا همان رفتار قبلی حفظ شود. اگر دوست دارید می‌توانم روی یک manifest واقعی شما بررسی کنم و پیشنهاد تبدیل دقیق بدهم. 🚀