Skip to content

فصل ۶ — برچسب‌ها و حاشیه‌نویسی‌ها

Kubernetes برای رشد همراه با شما و با افزایش اندازه و پیچیدگی برنامه‌تان ساخته شده است. با این هدف، labelها و annotationها به‌عنوان مفاهیم بنیادی اضافه شدند. labelها و annotationها به شما اجازه می‌دهند با مجموعه‌هایی از چیزها کار کنید که با نحوهٔ تفکر شما دربارهٔ برنامه‌تان هم‌خوان است. می‌توانید همهٔ منابع خود را سازمان‌دهی، علامت‌گذاری و cross-index کنید تا گروه‌هایی را نشان دهید که برای برنامه‌تان بیشترین معنا را دارند.

labelها جفت‌های key/value هستند که می‌توانند به اشیای Kubernetes مانند Podها و ReplicaSetها متصل شوند. می‌توانند دلخواه باشند و برای چسباندن اطلاعات شناسایی به اشیای Kubernetes مفیدند. labelها پایهٔ گروه‌بندی اشیاء را فراهم می‌کنند.

annotationها از سوی دیگر، مکانیزم ذخیره‌سازی‌ای فراهم می‌کنند که شبیه labelهاست: annotationها جفت‌های key/value هستند که برای نگه‌داشتن اطلاعات غیرشناسایی طراحی شده‌اند و ابزارها و کتابخانه‌ها می‌توانند از آن‌ها بهره ببرند.

Labelها

labelها metadata شناسایی برای اشیاء فراهم می‌کنند. این‌ها ویژگی‌های بنیادی شیء هستند که برای گروه‌بندی، مشاهده و عملیات استفاده می‌شوند.

انگیزه‌های labelها از تجربهٔ Google در اجرای برنامه‌های بزرگ و پیچیده برخاست. چند درس از این تجربه به دست آمد. برای پیش‌زمینهٔ عمیق‌تر دربارهٔ نحوهٔ رویکرد Google به سیستم‌های production، کتاب عالی Site Reliability Engineering اثر Betsy Beyer و همکاران (O'Reilly) را ببینید.

اولین درس این است که production از singleton بیزار است. هنگام deploy نرم‌افزار، کاربران اغلب با یک نمونهٔ واحد شروع می‌کنند. اما با بلوغ برنامه، این singletonها اغلب چندبرابر می‌شوند و به مجموعه‌ای از اشیاء تبدیل می‌شوند. با این در نظر، Kubernetes از labelها برای کار با مجموعه‌های اشیاء به‌جای نمونه‌های منفرد استفاده می‌کند.

دومین درس این است که هر سلسله‌مراتبی که سیستم تحمیل کند برای بسیاری از کاربران کوتاه می‌آید. علاوه بر این، گروه‌بندی‌ها و سلسله‌مراتب کاربر در طول زمان تغییر می‌کنند. مثلاً کاربر ممکن است با این ایده شروع کند که همهٔ appها از چندین service تشکیل شده‌اند. اما با گذشت زمان، یک service ممکن است بین چند app به اشتراک گذاشته شود. labelهای Kubernetes به‌قدری انعطاف‌پذیرند که با این موقعیت‌ها و موارد بیشتر سازگار شوند.

labelها syntax ساده‌ای دارند. جفت‌های key/value هستند که هم key و هم value با رشته نمایش داده می‌شوند. keyهای label را می‌توان به دو بخش تقسیم کرد: یک prefix اختیاری و یک name، جدا شده با slash. prefix، اگر مشخص شود، باید یک DNS subdomain با محدودیت ۲۵۳ کاراکتر باشد. name کلید الزامی است و باید کوتاه‌تر از ۶۳ کاراکتر باشد. nameها همچنین باید با کاراکتر alphanumeric شروع و پایان یابند و استفاده از dash (-)، underscore (_) و dot (.) بین کاراکترها مجاز است. valueهای label رشته‌هایی با حداکثر طول ۶۳ کاراکتر هستند. محتوای valueهای label همان قوانین keyهای label را دنبال می‌کند.

جدول ۶-۱ چند نمونهٔ معتبر از key و valueهای label را نشان می‌دهد.

جدول ۶-۱. نمونه‌های label

KeyValue
acme.com/app-version1.0.0
appVersion1.0.0
app.version1.0.0
kubernetes.io/cluster-servicetrue

وقتی نام دامنه در labelها و annotationها استفاده می‌شود، انتظار می‌رود به‌نوعی با آن موجودیت خاص هم‌راستا باشد. مثلاً یک پروژه ممکن است مجموعهٔ canonicalی از labelها را برای شناسایی مراحل مختلف deploy برنامه تعریف کند (مثلاً staging، canary، production).

یا یک cloud provider ممکن است annotationهای مختص provider را تعریف کند که اشیای Kubernetes را گسترش می‌دهند تا ویژگی‌های مختص سرویس خود را فعال کنند.

اعمال labelها

اینجا چند deployment (راهی برای ایجاد آرایه‌ای از Podها) با labelهای جالب می‌سازیم. دو app (به نام alpaca و bandicoot) و برای هر کدام دو environment داریم. همچنین دو نسخهٔ مختلف:

  1. ابتدا deployment alpaca-prod را بسازید و labelهای ver، app و env را تنظیم کنید:
bash
$ kubectl run alpaca-prod \
  --image=gcr.io/kuar-demo/kuard-amd64:blue \
  --replicas=2 \
  --labels="ver=1,app=alpaca,env=prod"
  1. سپس deployment alpaca-test را بسازید و labelهای ver، app و env را با مقادیر مناسب تنظیم کنید:
bash
$ kubectl run alpaca-test \
  --image=gcr.io/kuar-demo/kuard-amd64:green \
  --replicas=1 \
  --labels="ver=2,app=alpaca,env=test"
  1. در نهایت دو deployment برای bandicoot بسازید. اینجا environmentها را prod و staging می‌نامیم:
bash
$ kubectl run bandicoot-prod \
  --image=gcr.io/kuar-demo/kuard-amd64:green \
  --replicas=2 \
  --labels="ver=2,app=bandicoot,env=prod"
$ kubectl run bandicoot-staging \
  --image=gcr.io/kuar-demo/kuard-amd64:green \
  --replicas=1 \
  --labels="ver=2,app=bandicoot,env=staging"

در این نقطه باید چهار deployment داشته باشید — alpaca-prod، alpaca-test، bandicoot-prod و bandicoot-staging:

bash
$ kubectl get deployments --show-labels

NAME                ... LABELS
alpaca-prod         ... app=alpaca,env=prod,ver=1
alpaca-test         ... app=alpaca,env=test,ver=2
bandicoot-prod      ... app=bandicoot,env=prod,ver=2
bandicoot-staging   ... app=bandicoot,env=staging,ver=2

می‌توانیم این را بر اساس labelها به‌صورت نمودار Venn تصویر کنیم (شکل ۶-۱).

شکل ۶-۱. تصویرسازی labelهای اعمال‌شده روی deploymentهای ما

تغییر labelها

labelها همچنین می‌توانند پس از ایجاد اشیاء اعمال (یا به‌روزرسانی) شوند:

bash
$ kubectl label deployments alpaca-test "canary=true"

نکته‌ای که باید آگاه باشید: در این مثال، دستور kubectl label فقط label روی خود deployment را تغییر می‌دهد؛ روی اشیائی که deployment می‌سازد (ReplicaSetها و Podها) اثری ندارد. برای تغییر آن‌ها باید template تعبیه‌شده در deployment را تغییر دهید (فصل ۱۰ را ببینید).

همچنین می‌توانید از گزینهٔ -L در kubectl get استفاده کنید تا مقدار یک label را به‌عنوان ستون نشان دهد:

bash
$ kubectl get deployments -L canary

NAME                        DESIRED     CURRENT   ... CANARY
alpaca-prod                 2           2         ... <none>
alpaca-test                 1           1         ... true
bandicoot-prod              2           2         ... <none>
bandicoot-staging           1           1         ... <none>

می‌توانید با اعمال suffix خط تیره label را حذف کنید:

bash
$ kubectl label deployments alpaca-test "canary-"

Label Selectorها

label selectorها برای فیلتر کردن اشیای Kubernetes بر اساس مجموعه‌ای از labelها استفاده می‌شوند. selectorها از یک زبان Boolean ساده استفاده می‌کنند. هم توسط کاربران نهایی (از طریق ابزارهایی مثل kubectl) و هم توسط انواع مختلف اشیاء (مثلاً نحوهٔ ارتباط ReplicaSet با Podهایش) به کار می‌روند.

هر deployment (از طریق ReplicaSet) مجموعه‌ای از Podها را با labelهای مشخص‌شده در template تعبیه‌شده در deployment می‌سازد. این با دستور kubectl run پیکربندی می‌شود.

اجرای دستور kubectl get pods باید همهٔ Podهای در حال اجرا در cluster را برگرداند. باید در مجموع شش Pod kuard در سه environment داشته باشیم:

bash
$ kubectl get pods --show-labels

NAME                              ... LABELS
alpaca-prod-3408831585-4nzfb      ... app=alpaca,env=prod,ver=1,...
alpaca-prod-3408831585-kga0a      ... app=alpaca,env=prod,ver=1,...
alpaca-test-1004512375-3r1m5      ... app=alpaca,env=test,ver=2,...
bandicoot-prod-373860099-0t1gp    ... app=bandicoot,env=prod,ver=2,...
bandicoot-prod-373860099-k2wcf    ... app=bandicoot,env=prod,ver=2,...
bandicoot-staging-1839769971-3ndv  ... app=bandicoot,env=staging,ver=2,...

ممکن است label جدیدی ببینید که هنوز ندیده‌ایم: pod-template-hash. این label توسط deployment اعمال می‌شود تا بتواند ردیابی کند کدام Podها از کدام نسخه‌های template تولید شده‌اند. این به deployment اجازه می‌دهد به‌روزرسانی‌ها را به‌صورت تمیز مدیریت کند، همان‌طور که در فصل ۱۰ به‌طور عمیق پوشش داده می‌شود.

اگر فقط بخواهیم Podهایی را که label ver روی ۲ تنظیم شده فهرست کنیم، می‌توانیم از flag --selector استفاده کنیم:

bash
$ kubectl get pods --selector="ver=2"

NAME                                    READY      STATUS     RESTARTS     AGE
alpaca-test-1004512375-3r1m5            1/1        Running    0            3m
bandicoot-prod-373860099-0t1gp          1/1        Running    0            3m
bandicoot-prod-373860099-k2wcf          1/1        Running    0            3m
bandicoot-staging-1839769971-3ndv5      1/1        Running    0            3m

اگر دو selector را با کاما جدا کنیم، فقط اشیائی که هر دو را برآورده کنند برگردانده می‌شوند. این عملیات AND منطقی است:

bash
$ kubectl get pods --selector="app=bandicoot,ver=2"

NAME                                    READY      STATUS     RESTARTS     AGE
bandicoot-prod-373860099-0t1gp          1/1        Running    0            4m
bandicoot-prod-373860099-k2wcf          1/1        Running    0            4m
bandicoot-staging-1839769971-3ndv5      1/1        Running    0            4m

همچنین می‌توانیم بپرسیم آیا label یکی از مجموعه‌ای از مقادیر است. اینجا همهٔ Podهایی را می‌خواهیم که label app روی alpaca یا bandicoot تنظیم شده (که هر شش Pod خواهد بود):

bash
$ kubectl get pods --selector="app in (alpaca,bandicoot)"

NAME                                              READY      STATUS      RESTARTS   AGE
alpaca-prod-3408831585-4nzfb                      1/1        Running     0          6m
alpaca-prod-3408831585-kga0a                      1/1        Running     0          6m
alpaca-test-1004512375-3r1m5                      1/1        Running     0          6m
bandicoot-prod-373860099-0t1gp                    1/1        Running     0          6m
bandicoot-prod-373860099-k2wcf                    1/1        Running     0          6m
bandicoot-staging-1839769971-3ndv5                1/1        Running     0          6m

در نهایت می‌توانیم بپرسیم آیا label اصلاً تنظیم شده است. اینجا همهٔ deploymentهایی را می‌خواهیم که label canary روی هر مقداری تنظیم شده:

bash
$ kubectl get deployments --selector="canary"

NAME               DESIRED      CURRENT        UP-TO-DATE    AVAILABLE    AGE
alpaca-test        1            1              1             1            7m

نسخه‌های «منفی» هر کدام از این‌ها هم وجود دارد، همان‌طور که در جدول ۶-۲ نشان داده شده.

جدول ۶-۲. عملگرهای selector

OperatorDescription
key=valuekey روی value تنظیم شده
key!=valuekey روی value تنظیم نشده
key in (value1, value2)key یکی از value1 یا value2 است
key notin (value1, value2)key یکی از value1 یا value2 نیست
keykey تنظیم شده
!keykey تنظیم نشده

مثلاً پرسیدن اینکه آیا یک key، در این مثال canary، تنظیم نشده می‌تواند این‌طور باشد:

bash
$ kubectl get deployments --selector='!canary'

به‌طور مشابه، می‌توانید selectorهای مثبت و منفی را با هم ترکیب کنید:

bash
$ kubectl get pods -l 'ver=2,!canary'

Label Selectorها در اشیای API

وقتی یک شیء Kubernetes به مجموعه‌ای از اشیای Kubernetes دیگر اشاره می‌کند، از label selector استفاده می‌شود. به‌جای رشتهٔ ساده‌ای که در بخش قبل توضیح داده شد، از ساختار parse‌شده استفاده می‌کنیم.

به دلایل تاریخی (Kubernetes سازگاری API را نمی‌شکند!)، دو شکل وجود دارد. بیشتر اشیاء از مجموعهٔ جدیدتر و قدرتمندتر عملگرهای selector پشتیبانی می‌کنند.

selector app=alpaca,ver in (1, 2) به این تبدیل می‌شود:

yaml
selector:
  matchLabels:
    app: alpaca
  matchExpressions:
    - {key: ver, operator: In, values: [1, 2]}

syntax فشردهٔ YAML. این یک آیتم در لیست (matchExpressions) است که یک map با سه entry دارد. آخرین entry (values) مقداری دارد که لیستی با دو آیتم است.

همهٔ عبارات به‌صورت AND منطقی ارزیابی می‌شوند. تنها راه نمایش عملگر != تبدیل آن به عبارت NotIn با یک مقدار است.

شکل قدیمی‌تر مشخص‌کردن selectorها (در ReplicationControllerها و serviceها) فقط از عملگر = پشتیبانی می‌کند. این مجموعهٔ ساده‌ای از جفت‌های key/value است که همه باید با شیء هدف مطابقت داشته باشند تا انتخاب شوند.

selector app=alpaca,ver=1 این‌طور نمایش داده می‌شود:

yaml
selector:
  app: alpaca
  ver: 1

Labelها در معماری Kubernetes

علاوه بر اینکه به کاربران اجازه می‌دهند infrastructure خود را سازمان‌دهی کنند، labelها نقش حیاتی در پیوند دادن اشیای مرتبط Kubernetes دارند. Kubernetes سیستمی عمداً decoupled است. سلسله‌مراتبی وجود ندارد و همهٔ اجزا مستقل عمل می‌کنند. با این حال، در بسیاری از موارد اشیاء باید به یکدیگر مرتبط باشند و این روابط با labelها و label selectorها تعریف می‌شوند.

مثلاً ReplicaSetها که چندین replica از یک Pod می‌سازند و نگه می‌دارند، Podهایی را که مدیریت می‌کنند از طریق selector پیدا می‌کنند. به‌طور مشابه، service load balancer Podهایی را که باید ترافیک به آن‌ها برود از طریق query selector پیدا می‌کند. وقتی Pod ساخته می‌شود، می‌تواند از node selector برای شناسایی مجموعهٔ خاصی از nodeها که می‌تواند روی آن‌ها schedule شود استفاده کند. وقتی کاربران می‌خواهند ترافیک شبکه را در cluster محدود کنند، از NetworkPolicy همراه با labelهای خاص برای شناسایی Podهایی که باید یا نباید با یکدیگر ارتباط داشته باشند استفاده می‌کنند. labelها چسب قدرتمند و همه‌جا هستند که برنامهٔ Kubernetes را به هم می‌چسباند. اگرچه برنامه‌تان احتمالاً با مجموعهٔ ساده‌ای از labelها و queryها شروع می‌شود، باید انتظار داشته باشید با گذشت زمان در اندازه و پیچیدگی رشد کند.

Annotationها

annotationها مکانی برای ذخیرهٔ metadata اضافی برای اشیای Kubernetes با هدف واحد کمک به ابزارها و کتابخانه‌ها فراهم می‌کنند. راهی برای برنامه‌های دیگر که Kubernetes را از طریق API هدایت می‌کنند تا دادهٔ opaque با یک شیء ذخیره کنند. annotationها می‌توانند برای خود ابزار یا برای عبور دادن اطلاعات پیکربندی بین سیستم‌های خارجی استفاده شوند.

در حالی که labelها برای شناسایی و گروه‌بندی اشیاء به کار می‌روند، annotationها برای ارائهٔ اطلاعات اضافی دربارهٔ منشأ شیء، نحوهٔ استفاده از آن یا policy اطراف آن استفاده می‌شوند. همپوشانی وجود دارد و سلیقه است که چه زمانی annotation یا label استفاده شود. وقتی شک دارید، اطلاعات را به‌عنوان annotation به شیء اضافه کنید و اگر خواستید در selector استفاده کنید آن را به label ارتقا دهید.

annotationها برای موارد زیر استفاده می‌شوند:

  • ردیابی «دلیل» آخرین به‌روزرسانی یک شیء.
  • ارتباط policy زمان‌بندی تخصصی به scheduler تخصصی.
  • گسترش داده دربارهٔ آخرین ابزاری که resource را به‌روزرسانی کرده و چگونه (برای تشخیص تغییرات توسط ابزارهای دیگر و انجام merge هوشمند).
  • چسباندن اطلاعات build، release یا image که برای label مناسب نیست (ممکن است شامل Git hash، timestamp، شماره PR و غیره باشد).
  • فعال‌کردن شیء Deployment (فصل ۱۰) برای ردیابی ReplicaSetهایی که برای rolloutها مدیریت می‌کند.
  • ارائهٔ دادهٔ اضافی برای بهبود کیفیت بصری یا قابلیت استفاده UI. مثلاً اشیاء می‌توانند لینکی به آیکون (یا نسخهٔ base64-encoded آیکون) داشته باشند.
  • نمونه‌سازی اولیهٔ قابلیت alpha در Kubernetes (به‌جای ایجاد فیلد API درجه یک، پارامترهای آن قابلیت در annotation رمزگذاری می‌شوند).

annotationها در جاهای مختلف Kubernetes استفاده می‌شوند و مورد استفادهٔ اصلی rolling deploymentهاست. در rolling deploymentها، annotationها برای ردیابی وضعیت rollout و ارائهٔ اطلاعات لازم برای rollback deployment به حالت قبلی به کار می‌روند.

کاربران باید از استفاده از API server Kubernetes به‌عنوان پایگاه دادهٔ عمومی اجتناب کنند. annotationها برای داده‌های کوچک که ارتباط بالایی با resource خاص دارند مناسب‌اند. اگر می‌خواهید داده در Kubernetes ذخیره کنید اما شیء واضحی برای ارتباط ندارید، آن داده را در پایگاه دادهٔ مناسب‌تر دیگری ذخیره کنید.

تعریف annotationها

keyهای annotation همان قالب keyهای label را استفاده می‌کنند. اما چون اغلب برای ارتباط بین ابزارها به کار می‌روند، بخش «namespace» key مهم‌تر است. نمونه keyها شامل deployment.kubernetes.io/revision یا kubernetes.io/change-cause هستند.

بخش value یک annotation فیلد رشتهٔ آزاد است. اگرچه این انعطاف حداکثری می‌دهد، چون متن دلخواه است هیچ اعتبارسنجی قالبی وجود ندارد. مثلاً رایج است که سند JSON به‌صورت رشته رمزگذاری و در annotation ذخیره شود. مهم است توجه کنید سرور Kubernetes از قالب مورد نیاز valueهای annotation بی‌اطلاع است. اگر annotationها برای عبور یا ذخیرهٔ داده استفاده شوند، تضمینی نیست داده معتبر باشد. این می‌تواند ردیابی خطاها را دشوارتر کند.

annotationها در بخش metadata مشترک هر شیء Kubernetes تعریف می‌شوند:

yaml
...
metadata:
  annotations:
    example.com/icon-url: "https://example.com/icon.png"
...

annotationها بسیار راحت و loose coupling قدرتمندی فراهم می‌کنند. اما باید با احتیاط استفاده شوند تا از انبوهی دادهٔ بدون type جلوگیری شود.

پاک‌سازی

پاک‌سازی همهٔ deploymentهایی که در این فصل شروع کردیم آسان است:

bash
$ kubectl delete deployments --all

اگر می‌خواهید انتخابی‌تر باشید، می‌توانید از flag --selector برای انتخاب deploymentهایی که حذف می‌شوند استفاده کنید.

خلاصه

labelها برای شناسایی و اختیاراً گروه‌بندی اشیاء در cluster Kubernetes استفاده می‌شوند. labelها همچنین در queryهای selector برای گروه‌بندی runtime انعطاف‌پذیر اشیاء مانند Podها به کار می‌روند.

annotationها ذخیرهٔ key/value در محدودهٔ شیء metadata را فراهم می‌کنند که ابزارهای automation و client libraryها می‌توانند از آن استفاده کنند. annotationها همچنین می‌توانند دادهٔ پیکربندی برای ابزارهای خارجی مانند schedulerهای شخص ثالث و ابزارهای monitoring نگه دارند.

labelها و annotationها برای درک نحوهٔ کار اجزای کلیدی در cluster Kubernetes با هم برای تضمین وضعیت مطلوب cluster حیاتی‌اند. استفادهٔ صحیح از labelها و annotationها قدرت واقعی انعطاف Kubernetes را آزاد می‌کند و نقطهٔ شروع ساخت ابزارهای automation و workflowهای deploy است.