Skip to content

فصل ۷ — کشف سرویس

Kubernetes سیستمی بسیار پویاست. سیستم در قرار دادن Podها روی nodeها، اطمینان از up و running بودن آن‌ها و reschedule کردن در صورت نیاز درگیر است. راه‌هایی برای تغییر خودکار تعداد Podها بر اساس بار وجود دارد (مانند horizontal Pod autoscaling [«Autoscaling یک ReplicaSet» در صفحه ۱۱۰ را ببینید]). ماهیت API-driven سیستم دیگران را تشویق می‌کند تا سطوح بالاتر و بالاتری از automation بسازند.

در حالی که ماهیت پویا Kubernetes اجرای زیاد چیزها را آسان می‌کند، هنگام پیدا کردن آن‌ها مشکل ایجاد می‌کند. بیشتر infrastructure شبکهٔ سنتی برای سطح dynamism که Kubernetes ارائه می‌دهد ساخته نشده است.

Service Discovery چیست؟

نام عمومی این دسته از مشکلات و راه‌حل‌ها service discovery است. ابزارهای service-discovery به حل مشکل پیدا کردن اینکه کدام processها روی کدام آدرس‌ها برای کدام serviceها گوش می‌دهند کمک می‌کنند. سیستم service-discovery خوب به کاربران اجازه می‌دهد این اطلاعات را سریع و قابل اعتماد resolve کنند. سیستم خوب همچنین latency پایینی دارد؛ clientها به‌زودی پس از تغییر اطلاعات مرتبط با یک service به‌روز می‌شوند. در نهایت، سیستم service-discovery خوب می‌تواند تعریف غنی‌تری از آن service ذخیره کند. مثلاً شاید چند port با service مرتبط باشد.

Domain Name System (DNS) سیستم سنتی service discovery در اینترنت است. DNS برای name resolution نسبتاً پایدار با caching گسترده و کارآمد طراحی شده. سیستم عالی برای اینترنت است اما در دنیای پویای Kubernetes کوتاه می‌آید.

متأسفانه بسیاری از سیستم‌ها (مثلاً Java، به‌طور پیش‌فرض) مستقیماً نام را در DNS جستجو می‌کنند و هرگز دوباره resolve نمی‌کنند. این می‌تواند منجر به cache کردن mappingهای کهنه توسط clientها و صحبت با IP اشتباه شود. حتی با TTLهای کوتاه و clientهای خوش‌رفتار، تأخیر طبیعی بین تغییر name resolution و متوجه شدن client وجود دارد.

محدودیت‌های طبیعی هم در مقدار و نوع اطلاعاتی که در query معمولی DNS برگردانده می‌شود وجود دارد. چیزها پس از ۲۰–۳۰ رکورد A برای یک نام شروع به شکستن می‌کنند. رکوردهای SRV برخی مشکلات را حل می‌کنند اما اغلب استفاده از آن‌ها بسیار سخت است. در نهایت، نحوهٔ برخورد clientها با چند IP در رکورد DNS معمولاً گرفتن اولین IP و تکیه بر DNS server برای randomize یا round-robin کردن ترتیب رکوردهاست. این جایگزین load balancing هدفمندتر نیست.

شیء Service

service discovery واقعی در Kubernetes با شیء Service شروع می‌شود.

شیء Service راهی برای ایجاد یک label selector نام‌دار است. همان‌طور که خواهیم دید، شیء Service کارهای خوب دیگری هم برای ما انجام می‌دهد.

همان‌طور که دستور kubectl run راه آسان ایجاد deployment Kubernetes است، می‌توانیم از kubectl expose برای ایجاد service استفاده کنیم. بیایید چند deployment و service بسازیم تا ببینیم چگونه کار می‌کنند:

bash
$ kubectl run alpaca-prod \
  --image=gcr.io/kuar-demo/kuard-amd64:blue \
  --replicas=3 \
  --port=8080 \
  --labels="ver=1,app=alpaca,env=prod"
$ kubectl expose deployment alpaca-prod
$ kubectl run bandicoot-prod \
  --image=gcr.io/kuar-demo/kuard-amd64:green \
  --replicas=2 \
  --port=8080 \
  --labels="ver=2,app=bandicoot,env=prod"
$ kubectl expose deployment bandicoot-prod
$ kubectl get services -o wide

NAME                   CLUSTER-IP    ... PORT(S) ... SELECTOR
alpaca-prod            10.115.245.13 ... 8080/TCP ... app=alpaca,env=prod,ver=1
bandicoot-prod         10.115.242.3 ... 8080/TCP ... app=bandicoot,env=prod,ver=2
kubernetes             10.115.240.1 ... 443/TCP ... <none>

پس از اجرای این دستورات، سه service داریم. آن‌هایی که تازه ساختیم alpaca-prod و bandicoot-prod هستند. service kubernetes به‌طور خودکار برای شما ساخته می‌شود تا بتوانید API Kubernetes را از داخل app پیدا کرده و با آن صحبت کنید.

اگر به ستون SELECTOR نگاه کنیم، می‌بینیم service alpaca-prod صرفاً نامی به selector می‌دهد و مشخص می‌کند برای آن service با کدام portها صحبت شود. دستور kubectl expose به‌راحتی هم label selector و هم portهای مرتبط (در این مثال ۸۰۸۰) را از تعریف deployment می‌کشد.

علاوه بر این، آن service یک نوع IP مجازی جدید به نام cluster IP دریافت می‌کند. این آدرس IP ویژه‌ای است که سیستم ترافیک را بین همهٔ Podهایی که selector شناسایی می‌کند load-balance می‌کند.

برای تعامل با serviceها، به یکی از Podهای alpaca port forward می‌کنیم. این دستور را در پنجرهٔ ترمینال اجرا و باز نگه دارید. می‌توانید port forward را با دسترسی به Pod alpaca در http://localhost:48858 ببینید:

bash
$ ALPACA_POD=$(kubectl get pods -l app=alpaca \
    -o jsonpath='{.items[0].metadata.name}')
$ kubectl port-forward $ALPACA_POD 48858:8080

DNS سرویس

چون cluster IP مجازی است، پایدار است و مناسب است به آن آدرس DNS بدهیم. همهٔ مسائل cache کردن نتایج DNS توسط clientها دیگر اعمال نمی‌شود. در یک namespace، به‌سادگی استفاده از نام service برای اتصال به یکی از Podهایی که service شناسایی می‌کند.

Kubernetes سرویس DNS را در اختیار Podهای در حال اجرا در cluster قرار می‌دهد. این سرویس DNS Kubernetes هنگام ایجاد اولیه cluster به‌عنوان جزء سیستم نصب شد. سرویس DNS خودش توسط Kubernetes مدیریت می‌شود و نمونهٔ عالی از Kubernetes که روی Kubernetes ساخته می‌شود است. سرویس DNS Kubernetes نام‌های DNS برای cluster IPها فراهم می‌کند.

می‌توانید با گسترش بخش «DNS Query» در صفحهٔ وضعیت سرور kuard امتحان کنید. رکورد A برای alpaca-prod را query کنید. خروجی باید چیزی شبیه این باشد:

;; opcode: QUERY, status: NOERROR, id: 12071
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;alpaca-prod.default.svc.cluster.local. IN          A

;; ANSWER SECTION:
alpaca-prod.default.svc.cluster.local.    30       IN      A        10.115.245.13

نام DNS کامل اینجا alpaca-prod.default.svc.cluster.local. است. بیایید تجزیه کنیم:

alpaca-prod نام service مورد نظر.

default namespaceای که این service در آن است.

svc شناسایی اینکه این یک service است. این به Kubernetes اجازه می‌دهد انواع دیگر چیزها را در آینده به‌صورت DNS expose کند.

cluster.local. نام دامنهٔ پایه برای cluster. این پیش‌فرض است و در بیشتر clusterها می‌بینید. مدیران ممکن است این را تغییر دهند تا نام‌های DNS یکتا در چند cluster داشته باشند.

وقتی به service در namespace خودتان اشاره می‌کنید می‌توانید فقط از نام service (alpaca-prod) استفاده کنید. همچنین می‌توانید به service در namespace دیگر با alpaca-prod.default اشاره کنید. و البته می‌توانید از نام service کاملاً qualified (alpaca-prod.default.svc.cluster.local.) استفاده کنید. هر کدام را در بخش «DNS Query» kuard امتحان کنید.

Readiness Checkها

اغلب وقتی برنامه تازه بالا می‌آید آمادهٔ handle کردن requestها نیست. معمولاً مقداری initialization وجود دارد که از کمتر از یک ثانیه تا چند دقیقه طول می‌کشد. یکی از کارهای خوب شیء Service ردیابی این است که کدام Podهای شما از طریق readiness check آماده‌اند. بیایید deployment را تغییر دهیم تا readiness check متصل به Pod اضافه کنیم، همان‌طور که در فصل ۵ بحث کردیم:

bash
$ kubectl edit deployment/alpaca-prod

این دستور نسخهٔ فعلی deployment alpaca-prod را می‌گیرد و در ویرایشگر باز می‌کند. پس از ذخیره و خروج از ویرایشگر، شیء را به Kubernetes برمی‌گرداند. راه سریعی برای ویرایش شیء بدون ذخیره در فایل YAML است.

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

yaml
spec:
  ...
  template:
    ...
    spec:
      containers:
        ...
        name: alpaca-prod
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          periodSeconds: 2
          initialDelaySeconds: 0
          failureThreshold: 3
          successThreshold: 1

این Podهایی را که این deployment می‌سازد طوری تنظیم می‌کند که readiness آن‌ها از طریق HTTP GET به /ready روی port 8080 بررسی شود. این بررسی هر ۲ ثانیه از لحظهٔ بالا آمدن Pod شروع می‌شود. اگر سه بررسی متوالی fail شود، Pod آماده در نظر گرفته نمی‌شود. اما اگر فقط یک بررسی موفق شود، Pod دوباره آماده در نظر گرفته می‌شود.

فقط Podهای آماده ترافیک دریافت می‌کنند.

به‌روزرسانی تعریف deployment این‌طور Podهای alpaca را حذف و دوباره می‌سازد. بنابراین باید دستور port-forward قبلی را دوباره راه بیندازیم:

bash
$ ALPACA_POD=$(kubectl get pods -l app=alpaca \
    -o jsonpath='{.items[0].metadata.name}')
$ kubectl port-forward $ALPACA_POD 48858:8080

مرورگر را به http://localhost:48858 ببرید و باید صفحهٔ debug آن نمونه kuard را ببینید. بخش «Readiness Probe» را گسترش دهید. باید ببینید این صفحه هر بار که readiness check جدیدی از سیستم می‌آید به‌روز می‌شود، که باید هر ۲ ثانیه باشد.

در پنجرهٔ ترمینال دیگر، دستور watch روی endpointهای service alpaca-prod را شروع کنید. Endpoint راه سطح پایین‌تری برای پیدا کردن اینکه service ترافیک را به کجا می‌فرستد است و بعداً در این فصل پوشش داده می‌شود. گزینهٔ --watch اینجا باعث می‌شود دستور kubectl بماند و هر به‌روزرسانی را خروجی دهد. راه آسان دیدن تغییر یک شیء Kubernetes در طول زمان است:

bash
$ kubectl get endpoints alpaca-prod --watch

به مرورگر برگردید و لینک «Fail» برای readiness check را بزنید. باید ببینید سرور اکنون 500 برمی‌گرداند. پس از سه مورد، این سرور از لیست endpointهای service حذف می‌شود. لینک «Succeed» را بزنید و ببینید پس از یک readiness check endpoint دوباره اضافه می‌شود.

این readiness check راهی است که سرور overload یا بیمار به سیستم سیگنال می‌دهد دیگر ترافیک نمی‌خواهد. راه عالی پیاده‌سازی graceful shutdown است. سرور می‌تواند سیگنال دهد دیگر ترافیک نمی‌خواهد، تا بسته شدن اتصال‌های موجود صبر کند و سپس به‌تمیزی خارج شود.

Ctrl-C را بزنید تا از هر دو دستور port-forward و watch در ترمینال‌ها خارج شوید.

فراتر از Cluster

تا اینجا همهٔ آنچه در این فصل پوشش دادیم دربارهٔ expose کردن serviceها داخل cluster بود. اغلب IPهای Podها فقط از داخل cluster قابل دسترسی‌اند. در نقطه‌ای باید ترافیک جدید را راه دهیم!

قابل‌حمل‌ترین راه استفاده از ویژگی NodePort است که service را بیشتر تقویت می‌کند. علاوه بر cluster IP، سیستم یک port انتخاب می‌کند (یا کاربر می‌تواند مشخص کند) و هر node در cluster سپس ترافیک به آن port را به service forward می‌کند.

با این ویژگی، اگر به هر node در cluster دسترسی داشته باشید می‌توانید با service تماس بگیرید. NodePort را بدون دانستن اینکه Podهای آن service کجا اجرا می‌شوند استفاده می‌کنید. این می‌تواند با hardware یا software load balancer یکپارچه شود تا service بیشتر expose شود.

با تغییر service alpaca-prod امتحان کنید:

bash
$ kubectl edit service alpaca-prod

فیلد spec.type را به NodePort تغییر دهید. هنگام ایجاد service با kubectl expose هم می‌توانید با --type=NodePort این کار را انجام دهید. سیستم NodePort جدید اختصاص می‌دهد:

bash
$ kubectl describe service alpaca-prod

Name:                            alpaca-prod
Namespace:                       default
Labels:                          app=alpaca
                                 env=prod
                                 ver=1
Annotations:                     <none>
Selector:                        app=alpaca,env=prod,ver=1
Type:                            NodePort
IP:                              10.115.245.13
Port:                            <unset> 8080/TCP
NodePort:                        <unset> 32711/TCP
Endpoints:                       10.112.1.66:8080,10.112.2.104:8080,10.112.2.105:8080
Session Affinity:                None
No events.

اینجا می‌بینیم سیستم port 32711 را به این service اختصاص داده. اکنون می‌توانیم هر node cluster را روی آن port بزنیم تا به service دسترسی داشته باشیم. اگر روی همان شبکه هستید، مستقیماً دسترسی دارید. اگر cluster در cloud جایی است، می‌توانید از SSH tunneling چیزی شبیه این استفاده کنید:

bash
$ ssh <node> -L 8080:localhost:32711

اکنون اگر مرورگر را به http://localhost:8080 ببرید به آن service متصل می‌شوید. هر request که به service می‌فرستید به‌طور تصادفی به یکی از Podهایی که service را پیاده‌سازی می‌کنند هدایت می‌شود. صفحه را چند بار reload کنید و می‌بینید به‌طور تصادفی به Podهای مختلف assign می‌شوید.

وقتی تمام شد، از session SSH خارج شوید.

یکپارچه‌سازی Cloud

در نهایت، اگر از cloudی که روی آن اجرا می‌کنید پشتیبانی دارید (و cluster برای بهره‌برداری پیکربندی شده)، می‌توانید از نوع LoadBalancer استفاده کنید. این روی نوع NodePort می‌سازد و علاوه بر آن cloud را پیکربندی می‌کند تا load balancer جدید بسازد و آن را به nodeهای cluster هدایت کند.

دوباره service alpaca-prod را ویرایش کنید (kubectl edit service alpaca-prod) و spec.type را به LoadBalancer تغییر دهید.

اگر بلافاصله kubectl get services بزنید می‌بینید ستون EXTERNAL-IP برای alpaca-prod می‌گوید <pending>. کمی صبر کنید و باید آدرس عمومی اختصاص‌یافته توسط cloud را ببینید. در console حساب cloud خود نگاه کنید و کار پیکربندی که Kubernetes برای شما انجام داد را ببینید:

bash
$ kubectl describe service alpaca-prod

Name:                       alpaca-prod
Namespace:                  default
Labels:                     app=alpaca
                            env=prod
                            ver=1
Selector:                   app=alpaca,env=prod,ver=1
Type:                       LoadBalancer
IP:                         10.115.245.13
LoadBalancer Ingress:       104.196.248.204
Port:                       <unset> 8080/TCP
NodePort:                   <unset> 32711/TCP
Endpoints:                  10.112.1.66:8080,10.112.2.104:8080,10.112.2.105:8080
Session Affinity:           None
Events:
  FirstSeen ... Reason                       Message
  --------- ... ------                       -------
  3m        ... Type                         NodePort -> LoadBalancer
  3m        ... CreatingLoadBalancer         Creating load balancer
  2m        ... CreatedLoadBalancer          Created load balancer

اینجا می‌بینیم آدرس 104.196.248.204 اکنون به service alpaca-prod اختصاص یافته. مرورگر را باز کنید و امتحان کنید!

این مثال از clusterی است که روی Google Cloud Platform از طریق GKE راه‌اندازی و مدیریت شده. با این حال، نحوهٔ پیکربندی load balancer به cloud بستگی دارد. علاوه بر این، برخی cloudها load balancer مبتنی بر DNS دارند (مثلاً AWS ELB). در این صورت hostname به‌جای IP می‌بینید. همچنین بسته به cloud provider ممکن است هنوز کمی طول بکشد تا load balancer کاملاً operational شود.

ایجاد load balancer مبتنی بر cloud ممکن است کمی زمان ببرد. اگر روی بیشتر cloud providerها چند دقیقه طول بکشد تعجب نکنید.

جزئیات پیشرفته

Kubernetes برای extensible بودن ساخته شده. بنابراین لایه‌هایی برای یکپارچه‌سازی‌های پیشرفته‌تر وجود دارد. درک جزئیات نحوهٔ پیاده‌سازی مفهومی پیچیده مانند serviceها ممکن است در troubleshooting یا ایجاد یکپارچه‌سازی‌های پیشرفته‌تر کمک کند. این بخش کمی زیر سطح می‌رود.

Endpointها

برخی برنامه‌ها (و خود سیستم) می‌خواهند بدون استفاده از cluster IP از serviceها استفاده کنند. این با نوع دیگری از شیء به نام Endpoints انجام می‌شود. برای هر شیء Service، Kubernetes یک Endpoints همراه می‌سازد که آدرس‌های IP آن service را دارد:

bash
$ kubectl describe endpoints alpaca-prod

Name:                  alpaca-prod
Namespace:             default
Labels:                app=alpaca
                       env=prod
                       ver=1
Subsets:
  Addresses:                       10.112.1.54,10.112.2.84,10.112.2.85
  NotReadyAddresses:               <none>
  Ports:
    Name        Port               Protocol
    ----        ----               --------
    <unset>     8080               TCP

No events.

برای استفاده از service، برنامهٔ پیشرفته می‌تواند مستقیماً با API Kubernetes صحبت کند تا endpointها را پیدا کرده و آن‌ها را فراخوانی کند. API Kubernetes حتی قابلیت «watch» اشیاء و اطلاع‌رسانی به‌محض تغییر را دارد. به این ترتیب client بلافاصله پس از تغییر IPهای مرتبط با service واکنش نشان می‌دهد.

بیایید نشان دهیم. در پنجرهٔ ترمینال، دستور زیر را شروع و باز نگه دارید:

bash
$ kubectl get endpoints alpaca-prod --watch

وضعیت فعلی endpoint را خروجی می‌دهد و سپس «hang» می‌کند:

NAME                ENDPOINTS                                            AGE
alpaca-prod         10.112.1.54:8080,10.112.2.84:8080,10.112.2.85:8080   1m

پنجرهٔ ترمینال دیگر را باز کنید و deployment پشتیبان alpaca-prod را حذف و دوباره بسازید:

bash
$ kubectl delete deployment alpaca-prod
$ kubectl run alpaca-prod \
  --image=gcr.io/kuar-demo/kuard-amd64:blue \
  --replicas=3 \
  --port=8080 \
  --labels="ver=1,app=alpaca,env=prod"

اگر به خروجی endpoint watched نگاه کنید، می‌بینید هنگام حذف و بازسازی این Podها، خروجی دستور جدیدترین مجموعهٔ آدرس‌های IP مرتبط با service را نشان داد. خروجی شما چیزی شبیه این خواهد بود:

NAME          ENDPOINTS                                               AGE
alpaca-prod   10.112.1.54:8080,10.112.2.84:8080,10.112.2.85:8080      1m
alpaca-prod   10.112.1.54:8080,10.112.2.84:8080   1m
alpaca-prod   <none>    1m
alpaca-prod   10.112.2.90:8080   1m
alpaca-prod   10.112.1.57:8080,10.112.2.90:8080   1m
alpaca-prod   10.112.0.28:8080,10.112.1.57:8080,10.112.2.90:8080      1m

شیء Endpoints عالی است اگر کد جدیدی می‌نویسید که از ابتدا برای اجرا روی Kubernetes ساخته شده. اما بیشتر پروژه‌ها در این موقعیت نیستند! بیشتر سیستم‌های موجود برای کار با آدرس‌های IP معمولی که زیاد عوض نمی‌شوند ساخته شده‌اند.

Service Discovery دستی

serviceهای Kubernetes روی label selectorها روی Podها ساخته شده‌اند. یعنی می‌توانید از API Kubernetes برای service discovery ابتدایی بدون استفاده از شیء Service اصلاً استفاده کنید! بیایید نشان دهیم.

با kubectl (و از طریق API) به‌راحتی می‌بینیم چه IPهایی به هر Pod در deploymentهای مثال ما اختصاص یافته:

bash
$ kubectl get pods -o wide --show-labels

NAME                             ... IP          ... LABELS
alpaca-prod-12334-87f8h     ... 10.112.1.54 ... app=alpaca,env=prod,ver=1
alpaca-prod-12334-jssmh     ... 10.112.2.84 ... app=alpaca,env=prod,ver=1
alpaca-prod-12334-tjp56     ... 10.112.2.85 ... app=alpaca,env=prod,ver=1
bandicoot-prod-5678-sbxzl   ... 10.112.1.55 ... app=bandicoot,env=prod,ver=2
bandicoot-prod-5678-x0dh8   ... 10.112.2.86 ... app=bandicoot,env=prod,ver=2

عالی است، اما اگر Pod زیاد دارید؟ احتمالاً می‌خواهید بر اساس labelهای اعمال‌شده در deployment فیلتر کنید. بیایید فقط برای app alpaca این کار را انجام دهیم:

bash
$ kubectl get pods -o wide --selector=app=alpaca,env=prod

NAME                         ... IP          ...
alpaca-prod-3408831585-bpzdz ... 10.112.1.54 ...
alpaca-prod-3408831585-kncwt ... 10.112.2.84 ...
alpaca-prod-3408831585-l9fsq ... 10.112.2.85 ...

در این نقطه اصول service discovery را دارید! همیشه می‌توانید از labelها برای شناسایی مجموعهٔ Podهای مورد نظر استفاده کنید، همهٔ Podها را برای آن labelها بگیرید و آدرس IP را استخراج کنید. اما همگام نگه داشتن مجموعهٔ صحیح labelها برای استفاده می‌تواند دشوار باشد. به همین دلیل شیء Service ساخته شد.

kube-proxy و Cluster IPها

Cluster IPها IPهای مجازی پایداری هستند که ترافیک را بین همهٔ endpointهای یک service load-balance می‌کنند. این جادو توسط جزئی به نام kube-proxy که روی هر node در cluster اجرا می‌شود انجام می‌شود (شکل ۷-۱).

شکل ۷-۱. پیکربندی و استفاده از cluster IP

در شکل ۷-۱، kube-proxy از طریق API server serviceهای جدید در cluster را watch می‌کند. سپس مجموعه‌ای از قوانین iptables را در kernel آن host برنامه‌ریزی می‌کند تا مقصد packetها را بازنویسی کند تا به یکی از endpointهای آن service هدایت شوند. اگر مجموعهٔ endpointهای یک service تغییر کند (به‌خاطر آمدن و رفتن Podها یا readiness check ناموفق)، مجموعهٔ قوانین iptables بازنویسی می‌شود.

خود cluster IP معمولاً هنگام ایجاد service توسط API server اختصاص می‌یابد. اما هنگام ایجاد service، کاربر می‌تواند cluster IP مشخصی تعیین کند. پس از تنظیم، cluster IP بدون حذف و بازسازی شیء Service قابل تغییر نیست.

محدودهٔ آدرس service Kubernetes با flag --service-cluster-ip-range روی باینری kube-apiserver پیکربندی می‌شود. محدودهٔ آدرس service نباید با subnetها و محدوده‌های IP اختصاص‌یافته به هر Docker bridge یا node Kubernetes همپوشانی داشته باشد.

علاوه بر این، هر cluster IP صریح درخواستی باید از آن محدوده باشد و قبلاً استفاده نشده باشد.

متغیرهای محیطی Cluster IP

در حالی که بیشتر کاربران باید از سرویس‌های DNS برای پیدا کردن cluster IPها استفاده کنند، مکانیزم‌های قدیمی‌تری ممکن است هنوز در استفاده باشند. یکی از آن‌ها تزریق مجموعه‌ای از متغیرهای محیطی به Podها هنگام بالا آمدن است.

برای دیدن این در عمل، console نمونه bandicoot kuard را ببینید. دستورات زیر را در ترمینال اجرا کنید:

bash
$ BANDICOOT_POD=$(kubectl get pods -l app=bandicoot \
    -o jsonpath='{.items[0].metadata.name}')
$ kubectl port-forward $BANDICOOT_POD 48858:8080

مرورگر را به http://localhost:48858 ببرید تا صفحهٔ وضعیت این سرور را ببینید. بخش «Server Env» را گسترش دهید و مجموعهٔ متغیرهای محیطی برای service alpaca را ببینید. صفحهٔ وضعیت باید جدولی شبیه جدول ۷-۱ نشان دهد.

جدول ۷-۱. متغیرهای محیطی service

KeyValue
ALPACA_PROD_PORTtcp://10.115.245.13:8080
ALPACA_PROD_PORT_8080_TCPtcp://10.115.245.13:8080
ALPACA_PROD_PORT_8080_TCP_ADDR10.115.245.13
ALPACA_PROD_PORT_8080_TCP_PORT8080
ALPACA_PROD_PORT_8080_TCP_PROTOtcp
ALPACA_PROD_SERVICE_HOST10.115.245.13
ALPACA_PROD_SERVICE_PORT8080

دو متغیر محیطی اصلی برای استفاده ALPACA_PROD_SERVICE_HOST و ALPACA_PROD_SERVICE_PORT هستند. متغیرهای محیطی دیگر برای سازگاری با متغیرهای Docker link (اکنون deprecated) ساخته شده‌اند.

مشکل رویکرد متغیر محیطی این است که منابع باید به ترتیب خاصی ایجاد شوند. serviceها باید قبل از Podهایی که به آن‌ها اشاره می‌کنند ایجاد شوند. این می‌تواند پیچیدگی زیادی هنگام deploy مجموعه‌ای از serviceها که برنامهٔ بزرگ‌تری را می‌سازند معرفی کند. علاوه بر این، استفادهٔ صرف از متغیرهای محیطی برای بسیاری از کاربران عجیب به نظر می‌رسد. به همین دلیل DNS احتمالاً گزینهٔ بهتری است.

اتصال با محیط‌های دیگر

عالی است که service discovery در cluster خودتان دارید، اما بسیاری از برنامه‌های دنیای واقعی نیاز دارند برنامه‌های cloud-native مستقر در Kubernetes را با برنامه‌های مستقر در محیط‌های legacy یکپارچه کنید. علاوه بر این، ممکن است نیاز باشید cluster Kubernetes در cloud را با infrastructure مستقر on-premise یکپارچه کنید.

این حوزه‌ای از Kubernetes است که هنوز اکتشاف و توسعهٔ راه‌حل‌ها در آن جریان دارد. وقتی Kubernetes را به منابع legacy خارج از cluster وصل می‌کنید، می‌توانید از serviceهای بدون selector برای اعلام service Kubernetes با آدرس IP دستی اختصاص‌یافته خارج از cluster استفاده کنید. به این ترتیب service discovery Kubernetes از طریق DNS همان‌طور که انتظار می‌رود کار می‌کند، اما خود ترافیک شبکه به منبع خارجی می‌رود.

اتصال منابع خارجی به serviceهای Kubernetes کمی دشوارتر است. اگر cloud provider شما پشتیبانی می‌کند، ساده‌ترین کار ایجاد load balancer «داخلی» است که در virtual private network شما زندگی می‌کند و ترافیک را از IP ثابت به داخل cluster می‌رساند. سپس می‌توانید از DNS سنتی برای در دسترس قرار دادن این IP به منبع خارجی استفاده کنید. گزینهٔ دیگر اجرای kube-proxy کامل روی منبع خارجی و برنامه‌ریزی آن ماشین برای استفاده از DNS server در cluster Kubernetes است. چنین setupی به‌طور قابل توجهی سخت‌تر درست می‌شود و واقعاً فقط باید در محیط‌های on-premise استفاده شود. پروژه‌های open source متنوعی هم وجود دارد (مثلاً Consul شرکت Hashicorp) که می‌توانند برای مدیریت اتصال بین منابع in-cluster و out-of-cluster استفاده شوند.

پاک‌سازی

دستور زیر را اجرا کنید تا همهٔ اشیائی که در این فصل ساخته شدند پاک شوند:

bash
$ kubectl delete services,deployments -l app

خلاصه

Kubernetes سیستمی پویاست که روش‌های سنتی نام‌گذاری و اتصال serviceها روی شبکه را به چالش می‌کشد. شیء Service راهی انعطاف‌پذیر و قدرتمند برای expose کردن serviceها هم درون cluster و هم فراتر از آن فراهم می‌کند. با تکنیک‌های پوشش‌داده‌شده در اینجا می‌توانید serviceها را به یکدیگر وصل کنید و خارج از cluster expose کنید.

استفاده از مکانیزم‌های service discovery پویا در Kubernetes مفاهیم جدیدی معرفی می‌کند و در ابتدا ممکن است پیچیده به نظر برسد، اما درک و سازگاری با این تکنیک‌ها کلید آزاد کردن قدرت Kubernetes است. وقتی برنامه‌تان بتواند به‌صورت پویا serviceها را پیدا کند و به قرارگیری پویای آن برنامه‌ها واکنش نشان دهد، دیگر لازم نیست نگران این باشید چیزها کجا اجرا می‌شوند و چه زمانی جابه‌جا می‌شوند. این قطعهٔ حیاتی پازل است تا شروع به تفکر دربارهٔ serviceها به‌صورت منطقی کنید و بگذارید Kubernetes جزئیات قرارگیری container را بر عهده بگیرد.