بعد از apiVersion و kind، تقریباً همیشه بلوک سوم میآید:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: production
labels:
app: webاین بلوک تصادفی نیست. طبق ObjectMeta، هر منبع پایدار در Kubernetes باید metadata داشته باشد — هویت شیء، محدوده نام، برچسبها، مالکیت، قفل حذف، و نسخههای داخلی برای concurrency.
این مقاله هر فیلد مهم metadata را deep dive میکند و نشان میدهد کجا کاربر مینویسد و کجا سیستم پر میکند.
نقشه ذهنی ObjectMeta
metadata
├── هویت و محدوده
│ ├── name / generateName
│ ├── namespace
│ └── uid (سیستم)
├── سازماندهی
│ ├── labels (قابل select)
│ └── annotations (غیرقابل query)
├── مالکیت و حذف
│ ├── ownerReferences
│ ├── finalizers
│ ├── deletionTimestamp (سیستم)
│ └── deletionGracePeriodSeconds (سیستم)
├── نسخهگذاری داخلی
│ ├── resourceVersion (سیستم، opaque)
│ ├── generation (سیستم)
│ └── creationTimestamp (سیستم)
└── apply / SSA
└── managedFields (سیستم)selfLink قدیمی است و دیگر populate نمیشود — نادیده بگیرید.
۱. name — نام پایدار در محدوده
| ویژگی | توضیح |
|---|---|
| الزام | معمولاً هنگام create لازم است (مگر generateName) |
| یکتایی | داخل همان namespace برای همان نوع resource |
| بهروزرسانی | قابل تغییر نیست بعد از ساخت |
| هدف | idempotency پیکربندی و آدرسدهی انسانی |
قواعد نام (خلاصه DNS):
- طول محدود (برای بسیاری منابع حداکثر ۶۳ کاراکتر برای نامهای DNS label)
- حروف کوچک، عدد،
- - باید با حرف/عدد شروع و تمام شود
metadata:
name: payment-apiنام Pod ساختهشده توسط Deployment معمولاً payment-api-7d4f8b6c9f-xk2pq است — ترکیب نام ReplicaSet + suffix تصادفی.
۲. generateName — پیشوند + پسوند یکتا
اگر name ندهید و generateName بگذارید، سرور نام یکتا میسازد:
metadata:
generateName: batch-job-
# نتیجه مثلاً: batch-job-a1b2c- فقط وقتی
nameخالی است اعمال میشود - ممکن است truncate شود تا جا برای suffix باشد
- اگر نام تولیدشده collision کند → 409 Conflict
مفید برای Job/Podهای یکبارمصرف که نام ثابت لازم ندارند.
۳. namespace — محدوده منطقی
| موضوع | توضیح |
|---|---|
| معنی | فضای نام؛ یکتایی name داخل آن |
| خالی | معادل default (canonical: صریحاً default بنویسید) |
| Cluster-scoped | برای Node، PV، Namespace، ClusterRole، … این فیلد خالی میماند |
| تغییر | بعد از create نمیتوان namespace را عوض کرد (باید recreate) |
metadata:
name: web
namespace: productionNamespace خودش یک شیء است با metadata خودش — و finalizer معروف kubernetes برای پاکسازی محتوا قبل از حذف ns.
۴. uid — هویت یکتای زمانی–مکانی
- توسط سرور هنگام create پر میشود
- Read-only؛ در PUT عوض نمیشود
- اگر شیئی را delete و دوباره با همان
nameبسازید، uid جدید میگیرید
این دقیقاً برای تمایز «همین نام، نسل جدید» است — ownerReference و eventها به uid وابستهاند نه فقط به name.
kubectl get deploy web -o jsonpath='{.metadata.uid}{"\n"}'۵. labels — سازماندهی و انتخاب
Labels نقشهٔ کلید → مقدار برای دستهبندی و select هستند.
قواعد کلید
- اختیاریاً با prefix دامنه:
example.com/tier - بدون prefix برای کلیدهای خصوصی تیم
- کلید روی یک شیء باید یکتا باشد
- مقدار و کلید محدودیت طول/کاراکتر DNS دارند
Labels استاندارد پیشنهادی Kubernetes
metadata:
labels:
app.kubernetes.io/name: payment
app.kubernetes.io/instance: payment-prod
app.kubernetes.io/version: "1.4.2"
app.kubernetes.io/component: api
app.kubernetes.io/part-of: checkout
app.kubernetes.io/managed-by: helmاینها convention هستند نه اجبار — اما برای Observability، Helm، و GitOps بسیار مفیدند.
Labels قابل query هستند
kubectl get pods -l app=web
kubectl get pods -l 'tier in (frontend,api)'
kubectl get pods -l 'environment!=dev'Labels کجا مصرف میشوند؟
| مصرفکننده | نقش |
|---|---|
Service spec.selector | ترافیک به Podهایی با label مطابق |
Deployment / RS spec.selector | مالکیت Podهای template |
| NetworkPolicy | انتخاب podها |
| PodDisruptionBudget | |
| Scheduler / topology | گاهی با labelهای node |
| خودتان | فیلتر عملیاتی |
تله کلاسیک: label روی metadata خود Deployment با selector سرویس یکی نیست — Service باید labelهای Pod template را بگیرد، نه لزوماً labelهای Deployment.
# Service به Podها وصل میشود
spec:
selector:
app: web # باید روی pod template باشدLabels در برابر Annotations (خلاصه زود)
| Labels | Annotations | |
|---|---|---|
| Query / select | ✅ | ❌ |
| برای کنترلرهای built-in | رایج | گاه (tooling) |
| حجم داده | کوچک، شناسایی | میتواند بزرگتر / JSON |
| مثال | app=web | checksum، build-id، last-applied |
۶. annotations — فرادادهٔ ابزاری
Annotations هم key-valueاند اما برای اطلاعات غیرشناسایی که ابزارها مینویسند/میخوانند — نه برای selector.
metadata:
annotations:
kubernetes.io/change-cause: "bump image to 1.4.2"
description: "پرداخت — منطقه tehran"
checksum/config: "a1b2c3..."
prometheus.io/scrape: "true"
prometheus.io/port: "9090"ویژگیها طبق docs:
- unstructured
- قابل query با selector نیستند
- هنگام modify باید حفظ شوند (ابزارها به آنها وابستهاند)
کاربردهای رایج:
| حوزه | مثال |
|---|---|
| rollout history | kubernetes.io/change-cause |
| Ingress / Controller | annotationهای nginx، traefik، … |
| GitOps / SSA | tracking فیلدها |
| build CI | commit SHA، pipeline id |
| cert-manager / mesh | تنظیمات روی Ingress یا Service — مقالات cert-manager، Istio |
اشتباه رایج: گذاشتن چیزی که باید select شود داخل annotation — Service آن را پیدا نمیکند.
۷. creationTimestamp
- زمان UTC ساخت روی سرور (RFC3339)
- کلاینت نمیتواند set کند
- ترتیب happens-before بین عملیات جدا تضمین مطلق نیست
- برای listها null است
مفید برای دیباگ «کی ساخته شد؟» نه برای منطق کسبوکار حساس به ترتیب سراسری.
۸. resourceVersion — قلب optimistic concurrency
- رشتهٔ opaque (اغلب مرتبط با revision ذخیرهسازی / etcd)
- با هر تغییر شیء عوض میشود
- کلاینت باید آن را بدون تفسیر برگرداند
کاربردها:
- Optimistic lock: update با version قدیمی → 409 Conflict
- Watch: از یک resourceVersion به بعد تغییرات را ببینید
- Change detection
خواندن → تغییر محلی → نوشتن با همان resourceVersion
اگر کس دیگری وسط نوشته → 409 → دوباره بخوان و retryهرگز resourceVersion را بین منابع مختلف یا بازههای طولانی cache نکنید بهعنوان عدد معنادار.
روی پاسخ list، metadata.resourceVersion لیست با version تکتک itemها فرق دارد — یکی برای مجموعه، یکی برای هر شیء.
۹. generation — نسل desired state
- عدد صحیح یکنواافزاینده per-resource
- وقتی spec / desired state عوض میشود معمولاً generation بالا میرود
- تغییر صرف status لزوماً generation را عوض نمیکند
الگوی Controllers:
status:
observedGeneration: 3
# اگر metadata.generation == 3 → کنترلر آخرین spec را دیدهDeployment از این الگو برای فهم «آیا rollout با آخرین generation همخوان است؟» استفاده میکند.
تفاوت با resourceVersion:
| generation | resourceVersion | |
|---|---|---|
| معنی | نسل منطقی desired state | نسخه ذخیرهسازی هر write |
| قابل مقایسه عددی | بله (monotonic) | نه — opaque |
| status-only update | معمولاً ثابت میماند | عوض میشود |
۱۰. ownerReferences — درخت مالکیت و Garbage Collection
لیستی از اشیائی که این شیء به آنها وابسته است.
metadata:
ownerReferences:
- apiVersion: apps/v1
kind: Deployment
name: web
uid: a1b2c3d4-...
controller: true
blockOwnerDeletion: true| فیلد | معنی |
|---|---|
| apiVersion / kind / name / uid | اشاره به مالک |
| controller: true | این مالک، کنترلر مدیریتکننده است (حداکثر یکی) |
| blockOwnerDeletion | در حذف foreground، حذف مالک را تا پاک شدن وابسته بلوکه میکند |
رفتار GC:
- اگر همه ownerها حذف شوند → شیء وابسته garbage-collect میشود
- Deployment → ReplicaSet → Pod زنجیرهٔ کلاسیک ownerReference است
kubectl get pod <pod> -o jsonpath='{.metadata.ownerReferences}'بدون ownerReference درست، orphan و نشت منبع پیش میآید؛ با owner غلط، حذف آبشاری غیرمنتظره.
۱۱. finalizers — قفل حذف تا cleanup تمام شود
آرایهای از رشتهها. تا خالی نشوند، شیء از etcd پاک نمیشود.
جریان:
- کاربر
kubectl deleteمیزند - سرور
deletionTimestampمیگذارد — شیء Terminating - کنترلر مسئول cleanup را انجام میدهد (مثلاً volume ابری، DNS، LB)
- همان کنترلر finalizer خودش را برمیدارد
- وقتی لیست خالی شد → حذف نهایی
metadata:
finalizers:
- kubernetes
- example.com/cleanup-dnsنکات حیاتی از docs:
- ترتیب پردازش اجباری نیست (برای جلوگیری از deadlock)
- بعد از set شدن
deletionTimestampمعمولاً فقط میتوان finalizer حذف کرد نه اضافه کرد - finalizer گیرکرده = شیء تا ابد Terminating
# اورژانس (با فهم ریسک): برداشتن finalizer گیرکرده
kubectl patch <resource> <name> -p '{"metadata":{"finalizers":[]}}' --type=mergeNamespace finalizer تضمین میکند اول محتوای ns پاک شود.
۱۲. deletionTimestamp و deletionGracePeriodSeconds
| فیلد | نقش |
|---|---|
| deletionTimestamp | زمان درخواست حذف graceful؛ توسط سرور set میشود |
| deletionGracePeriodSeconds | مهلت خاتمهٔ مهربانانه (مثلاً برای Pod)؛ فقط وقتی deletion set است؛ قابل کوتاه شدن |
برای Pod: ابتدا SIGTERM، بعد از grace period SIGKILL. تا finalizerها خالی نشوند، حتی بعد از timestamp ممکن است شیء در API بماند.
۱۳. managedFields — Server-Side Apply و مالکیت فیلد
نقشه میکند کدام workflow (کاربر، کنترلر، مسیر ci-cd) کدام فیلدها را مدیریت میکند.
- برای housekeeping داخلی SSA
- کاربر عادی معمولاً دستی set نمیکند
- در
kubectl get -o yamlشلوغ بهنظر میرسد
# خروجی تمیزتر برای انسان
kubectl get deploy web -o yaml --show-managed-fields=falseوقتی دو مدیر روی یک فیلد مینویسند، SSA از managedFields برای تشخیص conflict استفاده میکند — مرتبط با Helm 4 SSA و GitOps.
نمونهٔ کامل حاشیهنویسیشده
apiVersion: apps/v1
kind: Deployment
metadata:
# —— کاربر معمولاً مینویسد ——
name: web
namespace: production
labels:
app.kubernetes.io/name: web
app.kubernetes.io/instance: web-prod
env: production
annotations:
kubernetes.io/change-cause: "scale for friday traffic"
# —— سیستم بعد از create پر میکند (نمونه) ——
# uid: "..."
# resourceVersion: "123456"
# generation: 2
# creationTimestamp: "2026-09-05T12:00:00Z"
# managedFields: [...]Pod فرزند:
metadata:
name: web-7d4f8b6c9f-xk2pq
namespace: production
labels:
app.kubernetes.io/name: web
pod-template-hash: 7d4f8b6c9f
ownerReferences:
- apiVersion: apps/v1
kind: ReplicaSet
name: web-7d4f8b6c9f
uid: "..."
controller: true
blockOwnerDeletion: trueListMeta در برابر ObjectMeta
پاسخ kubectl get pods -o yaml برای لیست، metadata سطح لیست دارد (ListMeta): عمدتاً resourceVersion مجموعه و continue برای pagination — با ObjectMeta تکشیء اشتباه نگیرید.
دستورات روزمره روی metadata
# label / annotation
kubectl label pod web-xxx env=prod
kubectl label pod web-xxx env- # حذف کلید
kubectl annotate deploy web description='API پرداخت'
kubectl annotate deploy web description-
# نمایش
kubectl get pods --show-labels
kubectl get deploy web -o jsonpath='{.metadata.annotations}'
# مالکیت
kubectl get rs,pod -l app.kubernetes.io/name=web -o custom-columns=\
NAME:.metadata.name,OWNERS:.metadata.ownerReferences[*].kindدر GitOps (Flux / Argo) معمولاً labels/annotations را در Git نگه میدارید؛ uid و resourceVersion را commit نکنید.
اشتباهات و ضدالگوها
| اشتباه | چرا بد است |
|---|---|
| Select با annotation | کار نمیکند |
عوض کردن name / namespace در place | غیرمجاز — recreate |
Commit کردن resourceVersion / uid در Git | conflict و drift مصنوعی |
| پاک کردن بیخبر annotations کنترلر | رفتار Ingress/mesh میشکند |
| Finalizer بدون کنترلر مسئول | Terminating ابدی |
| Label sensetive (رمز) | labels در بسیاری APIها دیده میشوند؛ secret نیستند |
| یکسان فرض کردن label Deployment و Pod | Service به Pod میچسبد |
ارتباط با apiVersion و بقیهٔ شیء
یادآوری از مقاله apiVersion:
apiVersion + kind → نوع قرارداد (GVK)
metadata → هویت و روابط این نمونه
spec → desired state
status → observed state (سیستم/کنترلر)metadata دربارهٔ «این شیء کیست و چگونه مدیریت میشود» است؛ spec دربارهٔ «چه باید باشد».
Best practices
- از labelهای
app.kubernetes.io/*برای اپهای واقعی استفاده کنید - Selectorها را کوچک و پایدار نگه دارید؛ دادهٔ توصیفی را annotation کنید
- در مانیفست Git فقط فیلدهای قابلنوشتن کاربر را نگه دارید
- قبل از حذف Namespace، finalizer و منابع گیرکرده را بررسی کنید
- برای Jobهای موقت
generateNameرا در نظر بگیرید - OwnerReference را به کنترلرها بسپارید مگر CRD خودتان مینویسید
- 409 Conflict را در کنترلر/اپراتور با re-queue درست handle کنید
--show-managed-fields=falseبرای خوانایی؛ برای دیباگ SSA روشن بگذارید- Annotationهای controller-specific را در مستندات تیم فهرست کنید
- Secret و دادهٔ حساس را در label/annotation نگذارید — از Secret/ESO استفاده کنید
جمعبندی فیلد به فیلد
| فیلد | نویسنده | یک خط |
|---|---|---|
| name | کاربر | نام یکتا در ns؛ immutable |
| generateName | کاربر | پیشوند نام یکتا |
| namespace | کاربر | محدوده؛ immutable |
| uid | سیستم | هویت یکتا پس از recreate |
| labels | کاربر/ابزار | select و سازماندهی |
| annotations | کاربر/ابزار | فراداده غیرquery |
| creationTimestamp | سیستم | زمان ساخت |
| resourceVersion | سیستم | concurrency + watch |
| generation | سیستم | نسل desired state |
| ownerReferences | کنترلر/کاربر | مالکیت و GC |
| finalizers | کنترلر/کاربر | قفل حذف |
| deletionTimestamp | سیستم | شروع graceful delete |
| deletionGracePeriodSeconds | سیستم | مهلت خاتمه |
| managedFields | سیستم | مالکیت فیلد SSA |
| selfLink | — | منسوخ |
metadata ظاهر سادهای دارد؛ در واقع سیستم عصبی هویت، کشف سرویس، حذف ایمن و همزمانی خوشه است. Labels مسیر ترافیک و کنترلرها را میسازند؛ annotations ابزارها را تغذیه میکنند؛ uid و resourceVersion و finalizers جلوی chaos را میگیرند.
قدم بعدی
- یک Deployment را با
kubectl get deploy -o yamlباز کنید و هر فیلد metadata را علامت بزنید kubectl get pods --show-labelsو یک Service selector را با label Podها تطبیق دهید- یک Pod را delete کنید و ownerReferences / garbage collection را تماشا کنید
- روی یک Namespace در حال Terminating،
finalizersرا inspect کنید - مقاله apiVersion را کنار این یکی بگذارید — GVK + ObjectMeta = هویت کامل شیء
منابع
- ObjectMeta — Kubernetes API
- Labels and Selectors
- Annotations
- Namespaces
- Names and UIDs
- Owners and Dependents / GC
- Finalizers
- API conventions
- apiVersion (مقاله P30Light)
- etcd (مقاله P30Light)
منتشر شده در P30Light — بخش زیرساخت و سرور.