نسخه آنلاین در حال بارگذاری زمان... تهران: ۲۶°C
۲۸ کاربر آنلاین

PNo.30Light

نشریه تخصصی هوش مصنوعی، سیستم‌های سرور و مهندسی داده

تازه ترین‌ها
زیرساخت و سرور
زمان مطالعه: ۳۲ دقیقه ۰ بازدید

metadata در YAML کوبرنتیز: Deep Dive کامل — Labels، Annotations، Owners و Finalizers

نویسنده: تحریریه فنی P30Light
metadata در YAML کوبرنتیز: Deep Dive کامل — Labels، Annotations، Owners و Finalizers
✦ خلاصه نکات کلیدی مقاله
  • metadata = ObjectMeta مشترک همه منابع پایدار — هویت، سازمان‌دهی، مالکیت و lifecycle.
  • Labels قابل select هستند؛ Annotations دادهٔ ابزاری بدون query.
  • uid / resourceVersion / generation / finalizers / ownerReferences موتور concurrency و GC هستند.

بعد از 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: production

Namespace خودش یک شیء است با 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 (خلاصه زود)

LabelsAnnotations
Query / select
برای کنترلرهای built-inرایجگاه (tooling)
حجم دادهکوچک، شناساییمی‌تواند بزرگ‌تر / JSON
مثالapp=webchecksum، 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 historykubernetes.io/change-cause
Ingress / Controllerannotationهای nginx، traefik، …
GitOps / SSAtracking فیلدها
build CIcommit 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)
  • با هر تغییر شیء عوض می‌شود
  • کلاینت باید آن را بدون تفسیر برگرداند

کاربردها:

  1. Optimistic lock: update با version قدیمی → 409 Conflict
  2. Watch: از یک resourceVersion به بعد تغییرات را ببینید
  3. 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:

generationresourceVersion
معنینسل منطقی 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 پاک نمی‌شود.

جریان:

  1. کاربر kubectl delete می‌زند
  2. سرور deletionTimestamp می‌گذارد — شیء Terminating
  3. کنترلر مسئول cleanup را انجام می‌دهد (مثلاً volume ابری، DNS، LB)
  4. همان کنترلر finalizer خودش را برمی‌دارد
  5. وقتی لیست خالی شد → حذف نهایی
metadata:
  finalizers:
    - kubernetes
    - example.com/cleanup-dns

نکات حیاتی از docs:

  • ترتیب پردازش اجباری نیست (برای جلوگیری از deadlock)
  • بعد از set شدن deletionTimestamp معمولاً فقط می‌توان finalizer حذف کرد نه اضافه کرد
  • finalizer گیرکرده = شیء تا ابد Terminating
# اورژانس (با فهم ریسک): برداشتن finalizer گیرکرده
kubectl patch <resource> <name> -p '{"metadata":{"finalizers":[]}}' --type=merge

Namespace 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: true

ListMeta در برابر 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 در Gitconflict و drift مصنوعی
پاک کردن بی‌خبر annotations کنترلررفتار Ingress/mesh می‌شکند
Finalizer بدون کنترلر مسئولTerminating ابدی
Label sensetive (رمز)labels در بسیاری APIها دیده می‌شوند؛ secret نیستند
یکسان فرض کردن label Deployment و PodService به Pod می‌چسبد

ارتباط با apiVersion و بقیهٔ شیء

یادآوری از مقاله apiVersion:

apiVersion + kind     → نوع قرارداد (GVK)
metadata              → هویت و روابط این نمونه
spec                  → desired state
status                → observed state (سیستم/کنترلر)

metadata دربارهٔ «این شیء کیست و چگونه مدیریت می‌شود» است؛ spec دربارهٔ «چه باید باشد».


Best practices

  1. از labelهای app.kubernetes.io/* برای اپ‌های واقعی استفاده کنید
  2. Selectorها را کوچک و پایدار نگه دارید؛ دادهٔ توصیفی را annotation کنید
  3. در مانیفست Git فقط فیلدهای قابل‌نوشتن کاربر را نگه دارید
  4. قبل از حذف Namespace، finalizer و منابع گیرکرده را بررسی کنید
  5. برای Jobهای موقت generateName را در نظر بگیرید
  6. OwnerReference را به کنترلرها بسپارید مگر CRD خودتان می‌نویسید
  7. 409 Conflict را در کنترلر/اپراتور با re-queue درست handle کنید
  8. --show-managed-fields=false برای خوانایی؛ برای دیباگ SSA روشن بگذارید
  9. Annotationهای controller-specific را در مستندات تیم فهرست کنید
  10. 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 را می‌گیرند.


قدم بعدی

  1. یک Deployment را با kubectl get deploy -o yaml باز کنید و هر فیلد metadata را علامت بزنید
  2. kubectl get pods --show-labels و یک Service selector را با label Podها تطبیق دهید
  3. یک Pod را delete کنید و ownerReferences / garbage collection را تماشا کنید
  4. روی یک Namespace در حال Terminating، finalizers را inspect کنید
  5. مقاله apiVersion را کنار این یکی بگذارید — GVK + ObjectMeta = هویت کامل شیء

منابع


منتشر شده در P30Light — بخش زیرساخت و سرور.

لینک گزارش با موفقیت کپی گردید!