چهار ستون یک مانیفست کلاسیک:
apiVersion: apps/v1 # قرارداد API
kind: Deployment # نوع شیء
metadata: # هویت — مقاله جدا
name: web
spec: # وضعیت مطلوب ← موضوع این مقاله
replicas: 3
selector: { ... }
template: { ... }
# status: # وضعیت مشاهدهشده — سیستم مینویسدطبق مستندات اشیاء Kubernetes: تقریباً هر شیء دارای spec (آنچه میخواهید) و status (آنچه واقعاً هست) است. control plane پیوسته actual را به desired نزدیک میکند.
این مقاله deep dive روی spec است — نه تکرار مقاله metadata. هویت در metadata است؛ قصد اجرایی در spec.
spec در برابر metadata در برابر status
| لایه | نویسنده اصلی | نقش |
|---|---|---|
| metadata | کاربر + سیستم | نام، ns، labels، owners، finalizers، resourceVersion |
| spec | کاربر (و گاه admission/defaulting) | desired state — «باید اینگونه باشد» |
| status | سیستم / کنترلرها | observed state — Ready، replicas، conditions، IP |
شما: spec.replicas = 3
کنترلر: میبیند status.readyReplicas = 2 → یک Pod دیگر میسازدkubectl edit روی status معمولاً بیفایده یا موقتی است؛ منبع حقیقت برای intent همان spec (و Git در GitOps) است.
قانون طلایی: هر Kind، یک شکل spec
هیچ «لیست ثابت جهانی فیلدهای spec» برای همه منابع وجود ندارد. spec یک Pod با spec یک Service یا Certificate (CRD) کاملاً فرق دارد.
kubectl explain pod.spec
kubectl explain deployment.spec
kubectl explain service.spec
kubectl explain ingress.spec --api-version=networking.k8s.io/v1الگوهای تکرارشونده:
- مستقیم: منابعی که خودشان اجرا میشوند (Pod، تا حدی Job)
- Controller + template: Deployment / StatefulSet / DaemonSet / CronJob → داخل spec یک Pod template
- شبکه / سیاست: Service، Ingress، NetworkPolicy — بدون container
- پیکربندی: بخش زیادی از intent در
dataاست نه همیشه زیر کلیدspec(ConfigMap/Secret) - CRD: هر اپراتور schema خودش را در
specتعریف میکند
نقشه ذهنی: از Deployment تا Container
Deployment.spec
├── replicas
├── selector (اغلب immutable)
├── strategy (RollingUpdate / Recreate)
├── revisionHistoryLimit
├── minReadySeconds
└── template # PodTemplateSpec
├── metadata.labels # باید با selector جور باشد
└── spec # ← این همان PodSpec است
├── containers[]
├── initContainers[]
├── volumes[]
├── restartPolicy
├── nodeSelector / affinity / tolerations
├── securityContext
├── serviceAccountName
├── dnsPolicy / hostNetwork / ...
└── ...بیشتر «عمق spec» که روزمره مینویسید، در PodSpec (یا template.spec) است.
Deep Dive: PodSpec — هستهٔ اجرا
Containers (الزامی برای Pod مفید)
هر container حداقل name و معمولاً image دارد:
spec:
containers:
- name: api
image: ghcr.io/example/api:1.4.2
imagePullPolicy: IfNotPresent # Always | Never | IfNotPresent
command: ["api"] # Entrypoint override
args: ["--port=8080"]
ports:
- name: http
containerPort: 8080
protocol: TCP
env:
- name: ENV
value: production
- name: DB_URL
valueFrom:
secretKeyRef:
name: db
key: url
envFrom:
- configMapRef:
name: api-config
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
volumeMounts:
- name: data
mountPath: /var/lib/api
workingDir: /app| فیلد | نقش |
|---|---|
| name | یکتا داخل Pod |
| image | ایمیج اجرا |
| imagePullPolicy | Always برای :latest پیشفرض رایج است |
| command / args | جایگزین ENTRYPOINT/CMD ایمیج |
| ports | مستندسازی + شبکه؛ باز کردن port روی Service جداست |
| env / envFrom | متغیر محیطی |
| resources | scheduling (requests) و سقف (limits) |
| volumeMounts | اتصال volume تعریفشده در Pod |
Probes — تشخیص سلامت
Kubelet دورهای چک میکند:
| Probe | معنی عملی |
|---|---|
| livenessProbe | مرده؟ → restart container |
| readinessProbe | آماده ترافیک؟ → حذف از Endpoints سرویس |
| startupProbe | شروع کند؛ تا موفق نشود liveness را عقب میاندازد |
انواع action: httpGet، tcpSocket، exec، grpc.
readinessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3بدون readiness درست، Service ترافیک را به Pod نیمهآماده میفرستد.
Lifecycle hooks
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo start"]
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 5"] # فرصت drainهمراه terminationGracePeriodSeconds در سطح Pod برای SIGTERM → SIGKILL.
initContainers و sidecars
spec:
initContainers:
- name: migrate
image: migrate:1
command: ["migrate", "up"]
containers:
- name: api
image: api:1Initها ترتیبی و تا موفقیت کامل قبل از app containers اجرا میشوند. الگوی sidecar (مثلاً log/proxy) container همعمر در همان Pod است؛ در نسخههای جدیدتر Kubernetes مفهوم sidecar با restartPolicy ویژه روی init هم مطرح شده — با kubectl explain نسخه cluster چک کنید.
volumes و volumeMounts
تعریف در spec.volumes، مصرف در container:
| نوع رایج | کاربرد |
|---|---|
| emptyDir | موقت همعمر Pod |
| configMap / secret | فایل پیکربندی |
| persistentVolumeClaim | داده پایدار |
| projected | ترکیب چند منبع |
| csi / hostPath / nfs | وابسته به محیط |
spec:
volumes:
- name: data
persistentVolumeClaim:
claimName: api-data
containers:
- name: api
volumeMounts:
- name: data
mountPath: /dataScheduling: کجا اجرا شود؟
| فیلد | نقش |
|---|---|
| nodeSelector | ساده: label نود |
| affinity / antiAffinity | قوانین نرم/سخت نسبت به نود یا Pod |
| tolerations | تحمل taint نود |
| topologySpreadConstraints | پخش بین zone/host |
| runtimeClassName | مثلاً Kata — مقاله Kata |
| priorityClassName | اولویت scheduling / preemption |
| schedulerName | scheduler غیرپیشفرض |
امنیت در spec
سطح Pod (spec.securityContext) و سطح container (containers[].securityContext):
spec:
serviceAccountName: api-sa
automountServiceAccountToken: false
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: api
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]تنظیمات container در صورت تداخل، تنظیمات همپوشان Pod را override میکنند (جزئیات volume ownership جداست).
شبکه و DNS داخل PodSpec
| فیلد | نقش |
|---|---|
| hostname / subdomain | DNS داخلی |
| dnsPolicy | ClusterFirst، Default، … |
| dnsConfig | nameserver/search سفارشی — مرتبط با CoreDNS |
| hostNetwork / hostPID / hostIPC | اشتراک namespace با نود (حساس امنیتی) |
| shareProcessNamespace | PID مشترک بین containers |
restartPolicy و مهلتها
| مقدار | کاربرد |
|---|---|
| Always | پیشفرض Deployment/RS |
| OnFailure | Jobهای رایج |
| Never | Job دقیق / debug |
spec:
restartPolicy: Always
terminationGracePeriodSeconds: 30
activeDeadlineSeconds: 600 # سقف عمر (مثلاً Job/Pod)فیلدهایی که سیستم روی Pod پر میکند (نه در مانیفست اولیه شما)
بعد از schedule، مواردی مثل nodeName، و در status آدرسها ظاهر میشوند. ویرایش دستی بسیاری از فیلدهای Pod ممنوع یا محدود است.
محدودیت تغییر Pod بعد از create
طبق مستندات Pod، بهروزرسانی in-place Pod عمدتاً محدود است به چیزهایی مثل:
spec.containers[*].image/initContainers[*].imagespec.activeDeadlineSecondsspec.terminationGracePeriodSeconds- افزودن به
spec.tolerations - و برخی فیلدهای جدیدتر مثل scheduling gates
عوض کردن ports، env، volumes، یا افزودن container → معمولاً رد یا نیاز به حذف/بازساخت. به همین دلیل workload controllers با عوض کردن template Pod جدید میسازند.
Workload specs: کنترلرها
Deployment (apps/v1)
| فیلد spec | نقش |
|---|---|
| replicas | تعداد مطلوب Pod |
| selector | کدام Podها مال این Deploymentاند — در apps/v1 بعد از create immutable |
| template | PodTemplateSpec |
| strategy.type | RollingUpdate یا Recreate |
| strategy.rollingUpdate | maxUnavailable / maxSurge |
| revisionHistoryLimit | نگهداشت ReplicaSetهای قدیمی |
| progressDeadlineSeconds | کی rollout شکستخورده اعلام شود |
| paused | توقف rollout |
قانون حیاتی:
spec.selector باید با template.metadata.labels جور باشد
وگرنه API رد میکندتغییر template (image، label، env، …) → ReplicaSet جدید و rollout. تغییر صرف replicas scale است نه لزوماً revision کامل image.
ReplicaSet
معمولاً مستقیم نمینویسید؛ زیر Deployment ساخته میشود. spec مشابه: replicas + selector + template.
StatefulSet
برای هویت پایدار و storage:
| فیلد | نقش |
|---|---|
| serviceName | headless Service برای DNS پایدار |
| volumeClaimTemplates | PVC per Pod |
| podManagementPolicy | OrderedReady / Parallel |
| updateStrategy | RollingUpdate / OnDelete |
| ordinals | کنترل شماره ایندکس (نسخههای جدیدتر) |
نام Podها پایدار: web-0، web-1، …
DaemonSet
یک (یا بیشتر با tolerance) Pod per Node مطابق selector. spec.updateStrategy برای rolling روی نودها.
Job و CronJob (batch/v1)
Job.spec:
| فیلد | نقش |
|---|---|
| template | Pod؛ معمولاً restartPolicy: OnFailure/Never |
| completions / parallelism | چند کار موفق / موازی |
| backoffLimit | سقف retry |
| ttlSecondsAfterFinished | پاکسازی خودکار |
| activeDeadlineSeconds | مهلت کل Job |
CronJob.spec: schedule، jobTemplate، concurrencyPolicy (Allow/Forbid/Replace)، successfulJobsHistoryLimit.
شبکه در spec (بدون Pod template)
Service
spec:
type: ClusterIP # NodePort | LoadBalancer | ExternalName
selector:
app: web # label روی Podها — نه لزوماً روی Deployment
ports:
- name: http
port: 80
targetPort: http
protocol: TCP
sessionAffinity: None
# clusterIP / externalIPs / loadBalancerIP — وابسته به محیطبدون selector میتوان Endpoints/EndpointSlice دستی داشت (ExternalName یا سرویس headless پیشرفته).
Ingress (networking.k8s.io/v1)
spec:
ingressClassName: nginx
tls:
- hosts: ["app.example.com"]
secretName: app-tls
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80pathType اجباری است؛ جزئیات apiVersion در مقاله apiVersion.
NetworkPolicy
spec.podSelector + ingress/egress rules — کدام ترافیک مجاز است (Cilium اغلب موتور enforcement است).
Config و Secret — intent کجا نشسته؟
| Kind | الگوی رایج |
|---|---|
| ConfigMap / Secret | عمدتاً data / stringData؛ گاهی immutable: true |
| PersistentVolumeClaim | spec.accessModes، resources.requests.storage، storageClassName |
| HorizontalPodAutoscaler | spec.scaleTargetRef، minReplicas، maxReplicas، metrics |
Secret در etcd (رمزنگاری در rest وابسته به پیکربندی cluster) — در Git از Sealed/ESO استفاده کنید.
Defaulting، Validation و Apply
- شما YAML ناقص میفرستید
- Defaulting فیلدهای پیشفرض را پر میکند (مثلاً
protocol: TCP) - Validation (OpenAPI / CEL) رد یا قبول میکند
- Admission webhooks ممکن است spec را mutate/validate کنند
- شیء ذخیره میشود؛ کنترلر reconcile را شروع میکند
از Kubernetes 1.25+ field validation سمت سرور قویتر است (kubectl --validate=strict).
kubectl apply -f app.yaml --server-side # SSA؛ مرتبط با managedFields در metadata
kubectl diff -f app.yaml
kubectl explain deploy.spec.strategy.rollingUpdate.maxSurgeImmutable در برابر Mutable در spec
| معمولاً بعد از create قفل | معمولاً قابل تغییر |
|---|---|
Deployment spec.selector | replicas، template، strategy |
| بسیاری label selectorهای مالکیت | image داخل template (با rollout) |
Service clusterIP (پس از تخصیص) | ports (با محدودیت)، selector |
| Job selector در برخی حالات | parallelism در محدوده مجاز |
PVC storageClassName / حجم در بسیاری provisionerها | annotationها؛ افزایش حجم اگر CSI اجازه دهد |
قانون عملی: اگر API گفت immutable → object جدید بسازید یا از کنترلر بخواهید جایگزین کند (rollout).
CRD و Operators: spec سفارشی
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: app-tls
spec:
secretName: app-tls
issuerRef:
name: letsencrypt
kind: ClusterIssuer
dnsNames:
- app.example.comاینجا spec دیگر PodSpec نیست — schema اپراتور است. همان اصل برقرار است: شما desired مینویسید؛ کنترلر status را پر میکند و عمل میکند. مثالها: cert-manager، Istio VirtualService، Flux HelmRelease، Helm values که به spec تبدیل میشوند.
نمونهٔ یکپارچه حاشیهنویسیشده
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: production
labels:
app.kubernetes.io/name: web
spec:
replicas: 3 # desired count
revisionHistoryLimit: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
selector: # immutable پس از create
matchLabels:
app: web
template:
metadata:
labels:
app: web # باید با selector یکی باشد
spec: # PodSpec
serviceAccountName: web
securityContext:
runAsNonRoot: true
containers:
- name: web
image: ghcr.io/example/web:1.2.0
ports:
- containerPort: 8080
name: http
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
memory: 256Mi
readinessProbe:
httpGet:
path: /ready
port: http
livenessProbe:
httpGet:
path: /live
port: httpاشتباهات رایج درباره spec
| اشتباه | واقعیت |
|---|---|
| ویرایش Pod زنده بهجای Deployment | drift؛ کنترلر برمیگرداند یا فیلد immutable است |
| selector سرویس = labelهای metadata دیپلویمنت | باید label Pod باشد |
| نداشتن readiness | ترافیک به Pod سرد |
| requests خیلی کم / بدون limit حافظه | نویز همسایه یا OOM بیبرنامه |
فرض اینکه همه Kindها replicas دارند | Service/Ingress ندارند |
| commit کردن status در Git | intent نیست؛ نویز reconcile |
| عوض کردن selector Deployment | معمولاً باید recreate |
ارتباط با GitOps و Helm
- Helm: values → رندر → پر کردن specها
- Flux / Argo: Git را desired میدانند و spec cluster را همتراز میکنند
- تغییر spec در cluster بدون Git → drift تا reconcile بعدی
سهگانه مقالات مرتبط:
- apiVersion — قرارداد نوع
- metadata — هویت و روابط
- spec (این مقاله) — وضعیت مطلوب
Best practices
- همیشه با
kubectl explain <kind>.specنسخه cluster خودتان را مرجع کنید - intent را در Git نگه دارید؛ status را ignore کنید
- probes را جدی بگیرید — readiness برای Service حیاتی است
- requests را برای scheduling واقعی بگذارید
- securityContext حداقلی (non-root، drop caps) را پیشفرض کنید
- selectorها را از روز اول پایدار طراحی کنید
- برای داده پایدار StatefulSet/PVC؛ برای stateless Deployment
- قبل از apply:
kubectl diffو validate - در CI، schema را با kubeconform روی version هدف تست کنید
- CRD: فقط فیلدهای documented اپراتور را در spec بنویسید
جمعبندی
| مفهوم | یک جمله |
|---|---|
| spec | اعلام desired state توسط شما |
| status | گزارش actual state توسط سیستم |
| PodSpec | هستهٔ اجرا داخل اکثر workloadها |
| template | قالب ساخت Pod توسط کنترلر |
| immutable fields | بعد از create قفل؛ مسیر تغییر = recreate/rollout |
| هر Kind | شکل spec مخصوص خود را دارد |
spec جایی است که میگویید cluster چه باید بکند. metadata میگوید شیء کیست؛ status میگوید اکنون کجاست. تسلط بر PodSpec و الگوی controller+template، خواندن تقریباً هر YAML کوبرنتیز را ممکن میکند.
قدم بعدی
kubectl explain pod.spec --recursive | lessرا یکبار ورق بزنید- یک Deployment را با
kubectl get deploy -o yamlباز کنید و فقط بلوکspecرا مطالعه کنید - readiness را عمداً بشکنید و ببینید Endpoints خالی میشود
- سعی کنید
spec.selectorیک Deployment را عوض کنید — خطای immutable را ببینید - مقالات metadata و apiVersion را در کنار این یکی کامل کنید
منابع
- Kubernetes Objects — spec and status
- Pods
- Deployments
- Configure a Security Context
- API conventions
- metadata (مقاله P30Light)
- apiVersion (مقاله P30Light)
منتشر شده در P30Light — بخش زیرساخت و سرور.