Skip to content

فصل ۸ — توازن بار HTTP با Ingress

بخش حیاتی هر برنامه رساندن ترافیک شبکه به و از آن برنامه است. همان‌طور که در فصل ۷ توضیح داده شد، Kubernetes مجموعه‌ای از قابلیت‌ها برای expose کردن serviceها خارج از cluster دارد. برای بسیاری از کاربران و use caseهای ساده این قابلیت‌ها کافی است.

اما شیء Service در لایه ۴ (طبق مدل OSI¹) عمل می‌کند. یعنی فقط اتصال‌های TCP و UDP را forward می‌کند و داخل آن اتصال‌ها را نگاه نمی‌کند. به همین دلیل، میزبانی چندین برنامه روی یک cluster از serviceهای exposed مختلف استفاده می‌کند. اگر این serviceها از نوع NodePort باشند، clientها باید به port منحصربه‌فرد هر service وصل شوند. اگر از نوع LoadBalancer باشند، منابع cloud (اغلب گران یا کم‌یاب) برای هر service تخصیص می‌دهید. اما برای serviceهای مبتنی بر HTTP (لایه ۷) می‌توانیم بهتر عمل کنیم.

وقتی مشکل مشابهی در موقعیت‌های غیر Kubernetes حل می‌شود، کاربران اغلب به ایدهٔ «virtual hosting» روی می‌آورند. این مکانیزمی برای میزبانی چندین سایت HTTP روی یک آدرس IP است. معمولاً کاربر از load balancer یا reverse proxy برای پذیرش اتصال‌های ورودی روی portهای HTTP (80) و HTTPS (443) استفاده می‌کند. آن برنامه سپس اتصال HTTP را parse می‌کند و بر اساس header Host و مسیر URL درخواست‌شده، فراخوانی HTTP را به برنامهٔ دیگری proxy می‌کند. به این ترتیب آن load balancer یا reverse proxy نقش «گشت‌بان ترافیک» را برای decode و هدایت اتصال‌های ورودی به سرور «upstream» درست بازی می‌کند.

Kubernetes سیستم load balancing مبتنی بر HTTP خود را Ingress می‌نامد. Ingress راه Kubernetes-native پیاده‌سازی الگوی «virtual hosting» است که تازه بحث کردیم. یکی از پیچیده‌ترین جنبه‌های این الگو این است که کاربر باید فایل پیکربندی load balancer را مدیریت کند. در محیط پویا و با گسترش مجموعهٔ virtual hostها، این می‌تواند بسیار پیچیده شود. سیستم Ingress Kubernetes برای ساده‌سازی این کار (الف) آن پیکربندی را استاندارد می‌کند، (ب) آن را به شیء استاندارد Kubernetes منتقل می‌کند و (ج) چندین شیء Ingress را در یک config برای load balancer ادغام می‌کند.

پیاده‌سازی نرم‌افزاری معمولی چیزی شبیه شکل ۸-۱ است. Ingress controller سیستم نرم‌افزاری است که با service از نوع LoadBalancer خارج از cluster expose شده. سپس requestها را به سرورهای «upstream» proxy می‌کند. پیکربندی نحوهٔ انجام این کار نتیجهٔ خواندن و نظارت بر اشیای Ingress است.

شکل ۸-۱. پیکربندی معمول Ingress controller نرم‌افزاری

¹ مدل Open Systems Interconnection (OSI) راه استاندارد توصیف نحوهٔ ساخت لایه‌های مختلف شبکه روی یکدیگر است. TCP و UDP لایه ۴ در نظر گرفته می‌شوند، در حالی که HTTP لایه ۷ است.

Ingress Spec در برابر Ingress Controllerها

اگرچه از نظر مفهومی ساده است، در سطح پیاده‌سازی Ingress با تقریباً همهٔ اشیای resource معمول دیگر در Kubernetes بسیار متفاوت است. به‌طور خاص، به specification مشترک resource و پیاده‌سازی controller تقسیم شده. هیچ Ingress controller «استاندارد»ی در Kubernetes ساخته نشده، پس کاربر باید یکی از پیاده‌سازی‌های اختیاری متعدد را نصب و مدیریت کند.

کاربران می‌توانند اشیای Ingress را مثل هر شیء دیگر ایجاد و تغییر دهند. اما به‌طور پیش‌فرض کدی در حال اجرا نیست که واقعاً روی آن اشیاء عمل کند. به کاربر (یا distributionای که استفاده می‌کند) واگذار است controller خارجی را نصب و مدیریت کند. به این ترتیب controller قابل تعویض (pluggable) است.

دلایل متعددی وجود دارد که Ingress به این شکل شد. اولاً، هیچ HTTP load balancer واحدی وجود ندارد که به‌طور جهانی قابل استفاده باشد. علاوه بر load balancerهای نرم‌افزاری متعدد (هم open source و هم proprietary)، قابلیت‌های load balancing توسط cloud providerها هم وجود دارد (مثلاً ELB در AWS) و load balancerهای مبتنی بر hardware. دلیل دوم این است که شیء Ingress قبل از اضافه شدن قابلیت‌های extensibility رایج به Kubernetes اضافه شد (فصل ۱۶ را ببینید). با پیشرفت Ingress، احتمالاً از این مکانیزم‌ها استفاده خواهد کرد.

نصب Contour

اگرچه Ingress controllerهای زیادی موجودند، برای مثال‌های اینجا از Ingress controller به نام Contour استفاده می‌کنیم. این controller برای پیکربندی load balancer open source (و پروژه CNCF) به نام Envoy ساخته شده. Envoy برای پیکربندی پویا از طریق API ساخته شده. Ingress controller Contour ترجمهٔ اشیای Ingress به چیزی که Envoy بفهمد را بر عهده دارد.

پروژه Contour در https://github.com/heptio/contour میزبانی می‌شود. توسط Heptio² در همکاری با مشتریان دنیای واقعی ساخته شد و در محیط‌های production استفاده می‌شود.

می‌توانید Contour را با یک فراخوانی یک‌خطی نصب کنید:

bash
$ kubectl apply -f https://j.hept.io/contour-deployment-rbac

توجه کنید این نیاز به اجرا توسط کاربری با مجوز cluster-admin دارد.

این یک خط برای بیشتر پیکربندی‌ها کار می‌کند. namespaceای به نام heptio-contour می‌سازد. داخل آن namespace یک deployment (با دو replica) و service خارج‌رو از نوع LoadBalancer می‌سازد. علاوه بر این، مجوزهای صحیح را از طریق service account تنظیم می‌کند و CustomResourceDefinition (فصل ۱۶ را ببینید) برای قابلیت‌های گسترش‌یافته‌ای که در «آینده Ingress» در صفحه ۱۰۰ بحث می‌شود نصب می‌کند.

چون نصب سراسری است، باید مجوز admin گسترده روی clusterای که نصب می‌کنید داشته باشید.

پس از نصب، آدرس خارجی Contour را این‌طور بگیرید:

bash
$ kubectl get -n heptio-contour service contour -o wide
NAME      CLUSTER-IP     EXTERNAL-IP          PORT(S)      ...
contour   10.106.53.14   a477...amazonaws.com 80:30274/TCP ...

ستون EXTERNAL-IP را ببینید. می‌تواند IP (برای GCP و Azure) یا hostname (برای AWS) باشد. cloudها و محیط‌های دیگر ممکن است متفاوت باشند. اگر cluster Kubernetes شما از serviceهای نوع LoadBalancer پشتیبانی نمی‌کند، باید YAML نصب Contour را تغییر دهید تا ساده از نوع NodePort استفاده کند و ترافیک را به ماشین‌های cluster از مکانیزمی که در پیکربندی شما کار می‌کند هدایت کند.

اگر از minikube استفاده می‌کنید، احتمالاً چیزی برای EXTERNAL-IP نمی‌بینید. برای رفع این، باید پنجرهٔ ترمینال جداگانه باز کنید و minikube tunnel را اجرا کنید.

² Heptio اخیراً توسط VMware خریداری شد، پس احتمال تغییر این URL وجود دارد. با این حال GitHub به مقصد جدید forward می‌کند.

این مسیرهای شبکه را طوری پیکربندی می‌کند که آدرس IP یکتا به هر service از نوع LoadBalancer اختصاص یابد.

پیکربندی DNS

برای کار خوب Ingress باید entryهای DNS را به آدرس خارجی load balancer خود پیکربندی کنید. می‌توانید چند hostname را به یک endpoint خارجی map کنید و Ingress controller نقش گشت‌بان ترافیک را بازی کرده و requestهای ورودی را بر اساس آن hostname به service upstream مناسب هدایت کند.

در این فصل فرض می‌کنیم دامنه‌ای به نام example.com دارید. باید دو entry DNS پیکربندی کنید: alpaca.example.com و bandicoot.example.com. اگر IP برای load balancer خارجی دارید، رکورد A بسازید. اگر hostname دارید، رکورد CNAME پیکربندی کنید.

پیکربندی فایل hosts محلی

اگر دامنه ندارید یا از راه‌حل محلی مانند minikube استفاده می‌کنید، می‌توانید با ویرایش فایل /etc/hosts پیکربندی محلی تنظیم کنید. به مجوز admin/root روی workstation نیاز دارید. محل فایل ممکن است روی platform شما متفاوت باشد و اعمال آن ممکن است مراحل اضافی بخواهد. مثلاً در Windows فایل معمولاً در C:\Windows\System32\drivers\etc\hosts است و در نسخه‌های اخیر macOS باید پس از تغییر فایل sudo killall -HUP mDNSResponder را اجرا کنید.

فایل را ویرایش کنید و خطی شبیه زیر اضافه کنید:

<ip-address> alpaca.example.com bandicoot.example.com

برای <ip-address>، IP خارجی Contour را وارد کنید. اگر فقط hostname دارید (مثل AWS)، می‌توانید IP (که ممکن است در آینده عوض شود) با اجرای host -t a <address> بگیرید.

وقتی تمام شد این تغییرات را برگردانید!

استفاده از Ingress

اکنون که Ingress controller پیکربندی شده، بیایید آن را امتحان کنیم. ابتدا چند service upstream (گاهی «backend» هم گفته می‌شود) برای آزمایش با دستورات زیر می‌سازیم:

bash
$ kubectl run be-default \
  --image=gcr.io/kuar-demo/kuard-amd64:blue \
  --replicas=3 \
  --port=8080
$ kubectl expose deployment be-default
$ kubectl run alpaca \
  --image=gcr.io/kuar-demo/kuard-amd64:green \
  --replicas=3 \
  --port=8080
$ kubectl expose deployment alpaca
$ kubectl run bandicoot \
  --image=gcr.io/kuar-demo/kuard-amd64:purple \
  --replicas=3 \
  --port=8080
$ kubectl expose deployment bandicoot
$ kubectl get services -o wide

NAME             CLUSTER-IP    ... PORT(S) ... SELECTOR
alpaca-prod      10.115.245.13 ... 8080/TCP ... run=alpaca
bandicoot-prod   10.115.242.3 ... 8080/TCP ... run=bandicoot
be-default       10.115.246.6 ... 8080/TCP ... run=be-default
kubernetes       10.115.240.1 ... 443/TCP ... <none>

ساده‌ترین استفاده

ساده‌ترین راه استفاده از Ingress این است که همهٔ چیزی که می‌بیند را کورکورانه به service upstream عبور دهد. پشتیبانی محدودی از دستورات imperative برای کار با Ingress در kubectl وجود دارد، پس با فایل YAML شروع می‌کنیم (مثال ۸-۱ را ببینید).

مثال ۸-۱. simple-ingress.yaml

yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: simple-ingress
spec:
  backend:
    serviceName: alpaca
    servicePort: 8080

این Ingress را با kubectl apply بسازید:

bash
$ kubectl apply -f simple-ingress.yaml
ingress.extensions/simple-ingress created

می‌توانید با kubectl get و kubectl describe تأیید کنید درست تنظیم شده:

bash
$ kubectl get ingress
NAME             HOSTS   ADDRESS    PORTS   AGE
simple-ingress   *                  80      13m

$ kubectl describe ingress simple-ingress
Name:             simple-ingress
Namespace:        default
Address:
Default backend: be-default:8080
(172.17.0.6:8080,172.17.0.7:8080,172.17.0.8:8080)

Rules:
  Host Path         Backends
  ---- ----         --------
  *     *           be-default:8080 (172.17.0.6:8080,172.17.0.7:8080,172.17.0.8:8080)
Annotations:
  ...

Events:      <none>

این طوری تنظیم می‌شود که هر request HTTP که به Ingress controller برسد به service alpaca forward شود. اکنون می‌توانید به نمونه alpaca kuard از هر IP/CNAME خام service دسترسی داشته باشید؛ در این مثال alpaca.example.com یا bandicoot.example.com.

در این نقطه ارزش زیادی بالاتر از service سادهٔ نوع LoadBalancer اضافه نمی‌کند. در بخش‌های بعد پیکربندی‌های پیچیده‌تر را امتحان می‌کنیم.

استفاده از Hostnameها

وقتی ترافیک را بر اساس ویژگی‌های request هدایت کنیم جالب می‌شود. رایج‌ترین مثال این است که سیستم Ingress به header host HTTP (که روی دامنه DNS در URL اصلی تنظیم شده) نگاه کند و بر اساس آن header ترافیک را هدایت کند. بیایید شیء Ingress دیگری برای هدایت ترافیک به service alpaca برای هر ترافیکی که به alpaca.example.com می‌آید اضافه کنیم (مثال ۸-۲ را ببینید).

مثال ۸-۲. host-ingress.yaml

yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: host-ingress
spec:
  rules:
  - host: alpaca.example.com
    http:
      paths:
      - backend:
          serviceName: alpaca
          servicePort: 8080

این Ingress را با kubectl apply بسازید:

bash
$ kubectl apply -f host-ingress.yaml
ingress.extensions/host-ingress created

می‌توانیم تأیید کنیم همه‌چیز درست تنظیم شده:

bash
$ kubectl get ingress
NAME             HOSTS                   ADDRESS   PORTS   AGE
host-ingress     alpaca.example.com                80      54s
simple-ingress   *                                 80      13m

$ kubectl describe ingress host-ingress
Name:             host-ingress
Namespace:        default
Address:
Default backend: default-http-backend:80 (<none>)
Rules:
  Host                Path Backends
  ----                ---- --------
  alpaca.example.com
                      /   alpaca:8080 (<none>)
Annotations:
  ...

Events:   <none>

چند نکته کمی گیج‌کننده است. اولاً، اشاره‌ای به default-http-backend هست. این conventionای است که فقط برخی Ingress controllerها برای handle کردن requestهایی که به شکل دیگری handle نشده‌اند استفاده می‌کنند. این controllerها آن requestها را به service به نام default-http-backend در namespace kube-system می‌فرستند. این convention در سمت client در kubectl نمایان می‌شود.

بعد، endpointی برای service backend alpaca فهرست نشده. این باگ در kubectl است که در Kubernetes v1.14 رفع شده.

به هر حال، اکنون باید بتوانید به service alpaca از طریق http://alpaca.example.com دسترسی داشته باشید. اگر از روش‌های دیگر به endpoint service برسید، باید service پیش‌فرض را بگیرید.

استفاده از Pathها

سناریوی جالب بعدی هدایت ترافیک بر اساس نه فقط hostname بلکه path در request HTTP است. این را به‌راحتی با مشخص کردن path در entry paths انجام می‌دهیم (مثال ۸-۳ را ببینید). در این مثال همهٔ چیزی که به http://bandicoot.example.com می‌آید به service bandicoot می‌رود، اما http://bandicoot.example.com/a را هم به service alpaca می‌فرستیم. این نوع سناریو برای میزبانی چند service روی pathهای مختلف یک دامنه استفاده می‌شود.

مثال ۸-۳. path-ingress.yaml

yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: path-ingress
spec:
  rules:
  - host: bandicoot.example.com
    http:
      paths:
      - path: "/"
         backend:
           serviceName: bandicoot
           servicePort: 8080
      - path: "/a/"
         backend:
           serviceName: alpaca
           servicePort: 8080

وقتی چند path روی همان host در سیستم Ingress فهرست می‌شود، طولانی‌ترین prefix match می‌شود. پس در این مثال ترافیکی که با /a/ شروع می‌شود به service alpaca forward می‌شود، در حالی که بقیهٔ ترافیک (شروع با /) به service bandicoot هدایت می‌شود.

وقتی requestها به service upstream proxy می‌شوند، path تغییر نمی‌کند. یعنی request به bandicoot.example.com/a/ به سرور upstreamی که برای آن hostname و path پیکربندی شده همان‌طور می‌رسد. service upstream باید آماده سرو ترافیک روی آن subpath باشد. در این مثال kuard کد ویژه برای تست دارد که روی path ریشه (/) همراه با مجموعهٔ از پیش تعریف‌شده subpathها (/a/، /b/ و /c/) پاسخ می‌دهد.

پاک‌سازی

برای پاک‌سازی، دستورات زیر را اجرا کنید:

bash
$ kubectl delete ingress host-ingress path-ingress simple-ingress
$ kubectl delete service alpaca bandicoot be-default
$ kubectl delete deployment alpaca bandicoot be-default

موضوعات پیشرفته Ingress و نکات

ویژگی‌های fancy دیگری هم توسط Ingress پشتیبانی می‌شوند. سطح پشتیبانی از این ویژگی‌ها بسته به پیاده‌سازی Ingress controller متفاوت است و دو controller ممکن است یک ویژگی را کمی متفاوت پیاده‌سازی کنند.

بسیاری از ویژگی‌های گسترش‌یافته از طریق annotation روی شیء Ingress expose می‌شوند. مراقب باشید، چون این annotationها سخت validate می‌شوند و راحت اشتباه می‌شوند. بسیاری از این annotationها به کل شیء Ingress اعمال می‌شوند و می‌توانند عمومی‌تر از آنچه می‌خواهید باشند. برای محدود کردن scope annotationها همیشه می‌توانید یک شیء Ingress را به چند شیء Ingress تقسیم کنید. Ingress controller باید آن‌ها را بخواند و با هم merge کند.

اجرای چند Ingress Controller

اغلب ممکن است بخواهید چند Ingress controller روی یک cluster اجرا کنید. در آن صورت با annotation kubernetes.io/ingress.class مشخص می‌کنید کدام شیء Ingress برای کدام Ingress controller است. مقدار باید رشته‌ای باشد که مشخص کند کدام Ingress controller باید به این شیء نگاه کند. خود Ingress controllerها باید با همان رشته پیکربندی شوند و فقط اشیای Ingress با annotation صحیح را رعایت کنند.

اگر annotation kubernetes.io/ingress.class نباشد، رفتار تعریف‌نشده است. احتمالاً چند controller برای برآورده کردن Ingress می‌جنگند و فیلد status اشیای Ingress را می‌نویسند.

چند شیء Ingress

اگر چند شیء Ingress مشخص کنید، Ingress controllerها باید همه را بخوانند و سعی کنند در config منسجم ادغام کنند. اما اگر پیکربندی‌های تکراری و متضاد مشخص کنید، رفتار تعریف‌نشده است. احتمالاً Ingress controllerهای مختلف متفاوت رفتار می‌کنند. حتی یک پیاده‌سازی ممکن است بسته به عوامل غیرواضح کارهای مختلف انجام دهد.

Ingress و Namespaceها

Ingress با namespaceها به شکل‌های غیرواضحی تعامل دارد.

اولاً، به‌خاطر احتیاط امنیتی زیاد، شیء Ingress فقط می‌تواند به service upstream در همان namespace اشاره کند. یعنی نمی‌توانید با شیء Ingress یک subpath را به service در namespace دیگر اشاره دهید.

با این حال، چند شیء Ingress در namespaceهای مختلف می‌توانند subpath برای همان host مشخص کنند. این اشیای Ingress سپس برای config نهایی Ingress controller با هم merge می‌شوند.

این رفتار cross-namespace یعنی Ingress باید به‌صورت سراسری در cluster هماهنگ شود. اگر با دقت هماهنگ نشود، شیء Ingress در یک namespace می‌تواند در namespaceهای دیگر مشکل (و رفتار تعریف‌نشده) ایجاد کند.

معمولاً محدودیتی در Ingress controller برای اینکه کدام namespaceها چه hostname و pathهایی را مشخص کنند ساخته نشده. کاربران پیشرفته ممکن است با custom admission controller policy برای این موضوع را enforce کنند. تکامل‌های Ingress هم در «آینده Ingress» در صفحه ۱۰۰ توضیح داده شده که این مشکل را حل می‌کنند.

Path Rewriting

برخی پیاده‌سازی‌های Ingress controller اختیاراً path rewriting را پشتیبانی می‌کنند. این برای تغییر path در request HTTP هنگام proxy استفاده می‌شود. معمولاً با annotation روی شیء Ingress مشخص می‌شود و به همهٔ requestهایی که آن شیء مشخص می‌کند اعمال می‌شود. مثلاً اگر از NGINX Ingress controller استفاده می‌کردیم، می‌توانستیم annotation nginx.ingress.kubernetes.io/rewrite-target: / مشخص کنیم. این گاهی باعث می‌شود serviceهای upstream روی subpath کار کنند حتی اگر برای آن ساخته نشده باشند.

چند پیاده‌سازی نه فقط path rewriting بلکه پشتیبانی از regular expression هنگام مشخص کردن path را هم دارند. مثلاً NGINX controller اجازه می‌دهد regular expression بخش‌هایی از path را capture کند و سپس از آن محتوا هنگام rewriting استفاده کند. نحوهٔ انجام (و چه variantی از regular expression استفاده می‌شود) به پیاده‌سازی بستگی دارد.

path rewriting نقره‌گلوله نیست و اغلب باگ ایجاد می‌کند. بسیاری از برنامه‌های وب فرض می‌کنند می‌توانند درون خود با absolute path لینک بدهند. در آن صورت app ممکن است روی /subpath میزبانی شود اما requestها روی / به آن برسند. سپس کاربر را به /app-path می‌فرستد. سؤال این است آیا این لینک «داخلی» app است (که باید /subpath/app-path باشد) یا لینک به app دیگر. به همین دلیل اگر می‌توانید از subpath برای برنامه‌های پیچیده اجتناب کنید.

سرو TLS

وقتی وب‌سایت سرو می‌کنید، استفادهٔ امن با TLS و HTTPS روزبه‌روز ضروری‌تر می‌شود. Ingress این را پشتیبانی می‌کند (و بیشتر Ingress controllerها هم).

اول کاربران باید secret با گواهی TLS و کلیدها مشخص کنند — چیزی شبیه مثال ۸-۴. همچنین می‌توانید secret را imperative با kubectl create secret tls <secret-name> --cert <certificate-pem-file> --key <private-key-pem-file> بسازید.

مثال ۸-۴. tls-secret.yaml

yaml
apiVersion: v1
kind: Secret
metadata:
  creationTimestamp: null
  name: tls-secret-name
type: kubernetes.io/tls
data:
  tls.crt: <base64 encoded certificate>
  tls.key: <base64 encoded private key>

پس از آپلود گواهی، می‌توانید در شیء Ingress به آن اشاره کنید. این لیستی از گواهی‌ها همراه hostnameهایی که آن گواهی‌ها باید برایشان استفاده شوند مشخص می‌کند (مثال ۸-۵ را ببینید). باز هم اگر چند شیء Ingress گواهی برای همان hostname مشخص کنند، رفتار تعریف‌نشده است.

مثال ۸-۵. tls-ingress.yaml

yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: tls-ingress
spec:
  tls:
  - hosts:
    - alpaca.example.com
    secretName: tls-secret-name
  rules:
  - host: alpaca.example.com
    http:
       paths:
       - backend:
           serviceName: alpaca
           servicePort: 8080

آپلود و مدیریت secretهای TLS می‌تواند دشوار باشد. علاوه بر این، گواهی‌ها اغلب هزینهٔ قابل توجهی دارند. برای کمک به حل این مشکل، سازمان غیرانتفاعی «Let's Encrypt» Certificate Authority رایگان API-driven اجرا می‌کند. چون API-driven است، می‌توان cluster Kubernetes تنظیم کرد که خودکار گواهی TLS را برای شما بگیرد و نصب کند. راه‌اندازی می‌تواند دشوار باشد، اما وقتی کار کند استفاده بسیار ساده است. قطعهٔ گم‌شده پروژهٔ open source به نام cert-manager است که توسط Jetstack، استارتاپ بریتانیایی، آغاز و پشتیبانی می‌شود. برای دستورالعمل نصب و استفاده به صفحه GitHub آن مراجعه کنید.

پیاده‌سازی‌های جایگزین Ingress

پیاده‌سازی‌های زیادی از Ingress controller وجود دارد که هر کدام روی شیء پایه Ingress با ویژگی‌های منحصربه‌فرد می‌سازند. اکوسیستم پویاست.

اولاً، هر cloud provider پیاده‌سازی Ingress دارد که L7 load balancer مختص آن cloud را expose می‌کند. به‌جای پیکربندی load balancer نرم‌افزاری در حال اجرا در Pod، این controllerها اشیای Ingress را می‌گیرند و از طریق API load balancerهای مبتنی بر cloud را پیکربندی می‌کنند. این بار روی cluster و بار مدیریت برای اپراتورها را کم می‌کند، اما اغلب هزینه دارد.

محبوب‌ترین Ingress controller عمومی احتمالاً NGINX ingress controller open source است. توجه کنید controller تجاری مبتنی بر NGINX Plus proprietary هم وجود دارد. controller open source اساساً اشیای Ingress را می‌خواند و در فایل پیکربندی NGINX merge می‌کند. سپس به process NGINX سیگنال می‌دهد با پیکربندی جدید restart کند (در حالی که مسئولانه به اتصال‌های in-flight موجود سرو می‌دهد). NGINX controller open source تعداد enormousی ویژگی و گزینه از طریق annotation دارد.

Ambassador و Gloo دو Ingress controller دیگر مبتنی بر Envoy هستند که روی API gateway بودن تمرکز دارند.

Traefik reverse proxy پیاده‌سازی‌شده در Go است که هم می‌تواند Ingress controller باشد. مجموعه‌ای از ویژگی‌ها و dashboardهای developer-friendly دارد.

این فقط سطحی است. اکوسیستم Ingress بسیار فعال است و پروژه‌ها و پیشنهادهای تجاری زیادی روی شیء ساده Ingress به شکل‌های منحصربه‌فرد می‌سازند.

آینده Ingress

همان‌طور که دیدید، شیء Ingress abstraction بسیار مفیدی برای پیکربندی L7 load balancerها فراهم می‌کند — اما به همهٔ ویژگی‌هایی که کاربران می‌خواهند و پیاده‌سازی‌های مختلف می‌خواهند ارائه دهند scale نکرده.

بسیاری از ویژگی‌های Ingress کم‌تعریف هستند. پیاده‌سازی‌ها می‌توانند این ویژگی‌ها را به شکل‌های مختلف نمایان کنند و portability پیکربندی بین پیاده‌سازی‌ها را کم کنند.

مشکل دیگر این است که misconfigure کردن Ingress آسان است. نحوهٔ ترکیب چند شیء در را برای تضادهایی باز می‌کند که توسط پیاده‌سازی‌های مختلف متفاوت حل می‌شوند. علاوه بر این، نحوهٔ merge شدن آن‌ها در namespaceها ایدهٔ isolation namespace را می‌شکند.

Ingress هم قبل از شناخته شدن ایدهٔ Service Mesh (نمادین‌شده توسط پروژه‌هایی مانند Istio و Linkerd) ساخته شد. تقاطع Ingress و Service Mesh هنوز در حال تعریف است.

ایده‌های عالی زیادی در جامعه شناور است. مثلاً Istio ایدهٔ gateway را پیاده‌سازی می‌کند که در برخی جنبه‌ها با Ingress همپوشانی دارد. Contour نوع جدیدی به نام IngressRoute معرفی می‌کند که نسخهٔ بهتر تعریف‌شده و صریح‌تر Ingress است و از پروتکل‌های شبکهٔ دیگر مانند DNS الهام گرفته. تعریف گام بعدی Ingress مشکل سختی است. شامل ایجاد زبان مشترکی است که به بیشتر load balancerها اعمال شود، در عین حال فضا برای نوآوری ویژگی‌های جدید و اجازهٔ تخصصی‌سازی پیاده‌سازی‌های مختلف در جهات دیگر بماند.

این حوزهٔ فعال نوآوری در جامعه Kubernetes از طریق Network Special Interest Group است.

خلاصه

Ingress سیستمی منحصربه‌فرد در Kubernetes است. صرفاً یک schema است و پیاده‌سازی controller برای آن schema باید جداگانه نصب و مدیریت شود. اما همچنین سیستمی حیاتی برای expose کردن serviceها به کاربران به‌صورت عملی و مقرون‌به‌صرفه است. با بلوغ Kubernetes، انتظار داشته باشید Ingress بیشتر و بیشتر مرتبط شود.