برنامه نویسی

Kubernetes-101: خدمات – انجمن DEV

ما با Pods مواجه شده‌ایم که پایین‌ترین سطح جسمی است که کانتینرهای ما در آن زندگی می‌کنند. ما با Deployments مواجه شده‌ایم که انتزاعی‌هایی در بالای ReplicaSets هستند که به نوبه خود تعدادی کپی از Pods ما ایجاد می‌کند. این منابع در دسته بندی قرار می گیرند منابع حجم کار. امروز با آن مواجه خواهیم شد خدمات، که در دسته بندی قرار می گیرند منابع شبکه.

به هر Pod که در کلاستر خود ایجاد می کنیم یک آدرس IP اختصاص داده می شود که به صورت داخلی در کلاستر ما موجود است. اگر یک Deployment را با سه کپی از یک Pod راه اندازی کنیم، به هر Pod آدرس IP اختصاص داده می شود. چگونه می توانیم ترافیک تعادلی را بین سه پاد خود بارگذاری کنیم؟ یکی از راه ها استفاده از ابزار متعادل کننده بار شخص ثالث مورد علاقه ما است1، و آدرس های IP Pods خود را به متعادل کننده بار اضافه کنید. سپس بار متعادل کننده را در معرض اینترنت قرار می دهیم. اگر یکی از پادهای ما با یک پاد جدید جایگزین شود چه اتفاقی می‌افتد؟ Pod جدید یک آدرس IP جدید خواهد داشت و ما باید این آدرس IP جدید را به متعادل کننده بار خود ارائه دهیم تا مطمئن شویم که Pod جدید نیز ترافیک دریافت می کند. این خسته کننده به نظر می رسد!

اینجاست که منبع Service به کمک می آید. بیایید عمیق تر به این بپردازیم که یک سرویس چیست و چگونه می تواند در این شرایط به ما کمک کند!

خدمات

سرویس در Kubernetes چیست؟ برای شروع پاسخ به این سوال، به اسناد رسمی در مورد این موضوع اشاره می کنم2:

روشی انتزاعی برای نمایش یک برنامه در حال اجرا بر روی مجموعه ای از Pods به عنوان یک سرویس شبکه.

این تعریف دو چیز را به ما می گوید

  1. هدف یک سرویس چیست و
  2. جایی که نام سرویس می آید از

هنگامی که برای اولین بار با نوع منبع سرویس در Kubernetes روبرو می شوید، به راحتی می توانید آن را با این اصطلاح مخلوط کنید سرویس از جانب میکروسرویس ها یا سرویس لاجوردی یا چیزی مشابه در اینجا ما در مورد یک سرویس شبکه صحبت می کنیم.3

در مقدمه اشاره کردم که پیگیری تمام آدرس‌های IP برای Pods ما می‌تواند به سرعت خسته‌کننده شود. هر بار که یک Pod راه‌اندازی یا خاتمه می‌یابد، باید مطمئن شویم که آن را به بار متعادل کننده اضافه یا حذف می‌کنیم. منبع سرویس این کار را برای ما ساده می‌کند زیرا کسی است که آدرس‌های IP پادهای ما را ردیابی می‌کند. تصویری از معنای این مطلب در زیر نشان داده شده است:

خدمات 1

بنابراین سرویس اساسا یک لیست به روز از آدرس های IP Pods را نگه می دارد. کدام غلاف؟ پاسخ این سوال را در بخش بعدی خواهیم گرفت.

به طور اعلامی ایجاد یک سرویس ساده

بدون هیچ مقدمه ای، در اینجا یک مانیفست اولیه Kubernetes برای یک سرویس آمده است:

# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    tier: web
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در این مانیفست باید به چند نکته اشاره کرد:

  • مانند تمام مانیفست‌هایی که تاکنون دیده‌ایم، این یکی نیز دارای یک ویژگی است .apiVersion، آ .kind، یک نام در .metadata.name، و مشخصات در .spec
  • که در .spec دو بخش وجود دارد که باعث می شود سرویس کار کند
    • .spec.selector را مشخص می کند برچسب ها (جفت های کلید-مقدار) که سرویس برای دانستن اینکه به کدام پادها باید ترافیک ارسال کند، استفاده می کند، در این مورد یک برچسب وجود دارد tier: web
    • .spec.ports جزئیات شنونده را برای این سرویس مشخص می کند، یعنی به آن گوش می دهد protocol: TCP، port: 80، و این ترافیک را به پادهای مورد نظر ارسال می کند targetPort: 80 (اگر targetPort همان است port، فقط می توانید مشخص کنید port و کنار گذاشتن targetPort)

بنابراین اکنون ما یک سرویس داریم، چگونه بفهمیم که به کدام پادها ترافیک ارسال می کند؟

هر Pod که دارای برچسب (the جفت های کلید-مقدار) مشخص شده در .spec.selector در سرویس هدفی برای ترافیک ورودی به سرویس خواهد بود. این در تصویر زیر نشان داده شده است:

خدمات 2

در این مثال ما یک برچسب واحد داریم، اما در صورت تمایل می‌توانیم از چندین برچسب برای مطابقت با آنها استفاده کنیم.

در بخش بعدی یک سرویس با Deployment و Pods مربوطه ایجاد خواهیم کرد، اما در اینجا یک سرویس را به صورت مجزا ایجاد می کنیم تا ببینیم چگونه می توان اطلاعات مربوط به آن را با استفاده از آن مشاهده کرد. kubectl. ما با ایجاد سرویس شروع می کنیم kubectl apply:

$ kubectl apply -f service.yaml

service/nginx-service created
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در مرحله بعد همه خدمات خود را فهرست می کنیم:

$ kubectl get services

NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes      ClusterIP   10.96.0.1       <none>        443/TCP   5d20h
nginx-service   ClusterIP   10.105.138.93   <none>        80/TCP    15s
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ما می توانیم جدید خود را ببینیم nginx-service در لیست، اما یک سرویس نیز به نام وجود دارد kubernetes. تعداد سرویس هایی که در این لیست می بینید ممکن است بسته به نوع خوشه Kubernetes که استفاده می کنید متفاوت باشد. من در حال حاضر از یک خوشه محلی Minikube استفاده می کنم4.

مانند سایر اشیاء Kubernetes می توانیم از یک فرم کوتاه برای آن استفاده کنیم services که هست svc، بنابراین دستور قبلی را می توان کوتاه کرد kubectl get svc5.

ما همچنین می توانیم یک سرویس داده شده را با استفاده از آن توصیف کنیم kubectl describe:

$ kubectl describe service nginx-service

Name:              nginx-service
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          tier=web
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.105.138.93
IPs:               10.105.138.93
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         <none>
Session Affinity:  None
Events:            <none>
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ما لیست نسبتاً کمی از ویژگی‌های سرویس خود را می‌بینیم، اما می‌توانیم بخش‌های مهمی را که در مانیفست خود مشخص کرده‌ایم تشخیص دهیم. ملک به نام Type جالب است در حال حاضر مقدار آن بر روی تنظیم شده است ClusterIP – معنی آن چیست؟ در بخش بعدی به بررسی این موضوع خواهیم پرداخت.

خدمات انتشاراتی

یک سرویس دارای یک Type (یا ServiceType). چند نوع مختلف موجود است. سه موردی که می خواهم در این مقاله به آنها اشاره کنم به شرح زیر است:

  • ClusterIP: سرویس شما را با یک آدرس IP داخلی قابل دسترسی از داخل خوشه شما نشان می دهد. اگر چیز دیگری را مشخص نکنید، این نوع پیش‌فرض است. اگر برنامه ای دارید که فقط باید از درون خود خوشه در دسترس باشد، این انتخاب خوبی است. برای این نوع سرویس یک IP ثابت در داخل خوشه دریافت می کند.
  • LoadBalancer: سرویس شما را به صورت خارجی با استفاده از یک متعادل کننده بار ارائه دهنده ابر سازگار نمایش می دهد. را LoadBalancer نوع پیشرفته تر است زیرا منابعی را در یک محیط ابری ایجاد می کند (AWS، لاجوردی، GCPو غیره)، و برای راه اندازی به کمی کار اضافی نیاز دارد. اگر خوشه Kubernetes خود را در یک ارائه دهنده ابری اجرا می کنید، ممکن است این گزینه برای شما جالب باشد. توجه داشته باشید که اگر 20 سرویس مختلف را راه اندازی کنید، هر یک از آنها LoadBalancer نوع، ممکن است در نهایت با 20 متعادل کننده بار در محیط ابری خود مواجه شوید و هر بار متعادل کننده هزینه ای دارد. بنابراین، در یک راه‌اندازی تولید واقعی، می‌توانید به‌جای آن، یک بار متعادل کننده واحد را برای خوشه خود تنظیم کنید و سپس ترافیک را به روشی متفاوت توزیع کنید. این یک موضوع پیشرفته است و چیزی نیست که در این مورد به آن بپردازیم Kubernetes-101 سلسله.
  • NodePort: سرویس شما را در یک پورت ثابت در هر یک از گره های خوشه شما (ماشین های مجازی یا فیزیکی که خوشه شما را تشکیل می دهند) نشان می دهد. تمام ترافیکی که در هر گره به این پورت می رسد به سرویس شما ارسال می شود.

در این بخش ما بر روی NodePort نوع خدمات اجازه دهید مانیفست خود را از قبل تغییر دهیم و یک نوع صریح به آن اضافه کنیم:

# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: NodePort # we added this!
  selector:
    tier: web
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برای اینکه سرویس ما مفید باشد، یک Deployment نیز اضافه می کنیم که چند پاد برای ما ایجاد می کند. این پادها توسط سرویس هدف قرار خواهند گرفت. برای تکرار، بخش مهم برای کار اتصال بین یک سرویس و یک پاد این است که پادها با برچسب tier: web، زیرا این همان چیزی است که ما در آن مشخص کردیم .spec.selector خدمات ما مانیفست منبع Deployment به شکل زیر است:

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    tier: web
spec:
  replicas: 3
  selector:
    matchLabels:
      tier: web
  template:
    metadata:
      labels:
        tier: web # important!
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این مانیفست از قسمت های قبلی درباره Deployments آشنا به نظر می رسد.


اکنون زمان یک وقفه کوتاه است که در آن به چند نکته در مورد ساختار فایل مانیفست اشاره خواهم کرد. در بالا دو فایل تعریف کردم service.yaml و deployment.yaml.

وقتی میخوام بدوم kubectl apply در این فایل‌ها، من می‌توانم این کار را به هر ترتیبی انجام دهم، زیرا هیچ وابستگی ذاتی بین آنها وجود ندارد. خوب، اگر Deployment وجود نداشته باشد، سرویس جایی برای ارسال ترافیک نخواهد داشت، و اگر Deployment وجود داشته باشد اما سرویس وجود نداشته باشد، هیچ راه (آسان) برای ارسال ترافیک به Pods وجود نخواهد داشت. اما Kubernetes در هیچ یک از این شرایط شکایت نخواهد کرد. با این حال، راه بهتری برای اعمال مانیفست ها وجود دارد. در واقع دو راه:

  1. همه مانیفست های مرتبط را در یک فهرست قرار دهید، به عنوان مثال ./application، و سپس اجرا کنید kubectl apply -f ./application، سپس همه مانیفست های موجود در ./application دایرکتوری اعمال خواهد شد. این بهترین رویکرد برای برنامه های بزرگتر با چندین مانیفست در فایل های جداگانه است.
  2. همه مانیفست های مرتبط را در یک فایل قرار دهید و مانیفست های مختلف را با یک خط فقط از یکدیگر جدا کنید ---. این می تواند بهترین رویکرد برای برنامه های کوچک با حداکثر 2-3 نمایش (شاید با یک Deployment و یک Service) باشد.

الان اینتراکت تمام شد! من از روش 1 از لیست بالا استفاده می کنم و من را قرار می دهم service.yaml و deployment.yaml در یک دایرکتوری ./application. بعد استفاده میکنم kubectl apply برای ایجاد سرویس و استقرار من در یک حرکت:

$ tree

.
└── application
    ├── deployment.yaml
    └── service.yaml

1 directory, 2 files

$ kubectl apply -f ./application

deployment.apps/nginx-deployment created
service/nginx-service created
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

آیا من اکنون یک برنامه کاربردی دارم؟ نه کاملا. به دلیل یک مشکل فنی با Minikube در مک (من از مک استفاده می کنم!) باید یک مرحله دیگر را انجام دهم. توجه داشته باشید که این صرفاً به دلیل محدودیت های Minikube در مک است. Minikube یک خوشه درجه تولید نیست، بنابراین باید انتظار داشته باشیم که چند محدودیت وجود داشته باشد. به هر حال، کاری که باید انجام دهم این است که دستور زیر را اجرا کنم:

$ minikube service nginx-service --url

http://127.0.0.1:53904
! Because you are using a Docker driver on darwin, the terminal needs to be open to run it.
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همانطور که خروجی نشان می دهد باید اجازه دهم این پنجره ترمینال باز باشد تا این کار کند. اگر بازدید کنم http://127.0.0.1:53904 در مرورگرم صفحه خوش آمدگویی Nginx را می بینم.

در مقاله آینده ما دوباره از نوع سرویس بازدید خواهیم کرد NodePort در یک خوشه واقعی Kubernetes مستقر شده است، و خواهیم دید که بهتر از Minikube کار می کند.

قبل از پایان دادن به این بخش، اگر ما بود با استفاده از یک خوشه Kubernetes بهتر، چگونه می‌توانیم بفهمیم کدام پورت ما است NodePort خدمات استفاده می کند؟ می توانیم بدویم kubectl describe برای کشف کردن:

$ kubectl describe service nginx-service

Name:                     nginx-service
Namespace:                default
Labels:                   <none>
Annotations:              <none>
Selector:                 tier=web
Type:                     NodePort
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.104.193.42
IPs:                      10.104.193.42
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  32732/TCP  # <----------- here we can see it!
Endpoints:                172.17.0.3:80,172.17.0.4:80,172.17.0.5:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

انگار پورت هست 32732 مورد استفاده است. می بینیم که این همان پورتی نیست که Minikube از آن استفاده کرده است، اما باز هم به دلیل مشکلات فنی Minikube است.

استفاده از پورت نامگذاری شده

یک ویژگی راحت در Pods وجود دارد که قبلاً آن را ندیده بودیم. گفتم هر وقت دلیلی داشتیم دوباره به پادس برمی گردم، نه؟

ما می توانیم به یک پورت در معرض یک نام نام بگذاریم. سپس می توانیم به این نام در شیء Service خود اشاره کنیم. نمونه ای از آنچه به نظر می رسد این است:

# pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    tier: web
spec:
  containers:
    - name: nginx
      image: nginx:latest
      ports:
        - containerPort: 80
          name: web-port # here we give our port a name
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در اینجا ما یک پورت بر روی کانتینر خود تعریف کرده ایم .spec.containers[].ports و نام آن را گذاشته ایم web-port. مانیفست سرویسی که از این پورت نامگذاری شده استفاده می کند در زیر نشان داده شده است:

# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    tier: web
  ports:
    - protocol: TCP
      port: 80
      targetPort: web-port # here we use the named port
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سرویس از web-port به عنوان targetPort ارزش. این راحت است زیرا اگر ما نیاز به به روز رسانی پورتی که در Pod خود داریم، فقط خود Pod را به روز می کنیم، نیازی نیست که هیچ شی دیگری را که به این پورت نامگذاری شده ارجاع می دهد، به روز کنیم.

نمایش چندین پورت در سرویس شما

در مانیفست های سرویس که در بالا دیده ایم .spec.ports قسمت همیشه لیستی با یک عنصر بوده است. از آنجایی که این یک لیست است، به طور مستقیم می‌توانیم بفهمیم که می‌توانیم چندین پورت را در معرض دید قرار دهیم، نه فقط یک پورت را. اگر Pods شما چندین پورت را به دلایل مختلف در معرض دید قرار دهد، مفید است. من نمونه ای از این را وارد نمی کنم، اما به خاطر داشته باشید که این واقعاً ممکن است.

خلاصه

ما در این مقاله چیزهای زیادی در مورد خدمات Kubernetes یاد گرفتیم. ما اکنون هدف یک سرویس را می دانیم. ما می دانیم که چگونه با استفاده از مانیفست Kubernetes یک سرویس ایجاد کنیم. ما متوجه شدیم که چند نوع مختلف از خدمات وجود دارد، و ما به آنها نگاه دقیق تری کردیم NodePort نوع به طور خلاصه دیدیم که می‌توانیم یک پورت در معرض دید را روی یک Pod نام بگذاریم و به این نام از یک سرویس اشاره کنیم. در نهایت ما همچنین متوجه شدیم که در صورت نیاز، یک سرویس می تواند در بیش از یک پورت گوش دهد.

در مقاله بعدی به معرفی مفهوم a می پردازیم فضای نام. تاکنون اشاره نکرده ایم که چیزی به نام فضای نام وجود دارد، اما بدون اینکه بدانیم از آن استفاده کرده ایم پیش فرض فضای نام در خوشه Kubernetes ما. فضاهای نام برای جداسازی منابع و برنامه ها از یکدیگر در بخش های منطقی استفاده می شوند. اگر فضاهای نام وجود نداشتند، زمانی که تعداد هر نوع منبع افزایش می‌یابد، به سختی می‌توانستیم پادها، استقرارها، سرویس‌ها و غیره خود را پیگیری کنیم.


  1. من هرگز از چیزی استفاده نکرده ام که بتوان آن را به عنوان یک طبقه بندی کرد ابزار متعادل کننده بار شخص ثالث، بنابراین من کاملاً مطمئن نیستم که اینجا در مورد چه چیزی صحبت می کنم! ↩

  2. در 19 دسامبر از https://kubernetes.io/docs/concepts/services-networking/service/ دریافت شده است. ↩

  3. شاید یک سرویس شبکه و یک سرویس در معماری میکروسرویس یکسان باشد؟ من فکر می کنم که آنها می توانند باشند، اما در ذهن من آنها موجودات متفاوتی هستند. ↩

  4. در مورد نحوه شروع کار با Minikube در اسناد در https://minikube.sigs.k8s.io/docs/ بخوانید ↩

  5. همانطور که قبلاً گفتم، تنظیم نام مستعار مختلف برای کوتاه کردن بیشتر این دستورات معمول است. چرا این رایج است؟ زیرا وقتی با Kubernetes کار می کنید از آن استفاده خواهید کرد kubectl زیاد، و سپس خواهید دید که نام مستعار زندگی شما را ساده می کند. هنگام کار با Kubernetes Services یک نام مستعار مفید می تواند باشد alias kgs="kubectl get services". ↩

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا