مدیریت منابع در Kubernetes دو سؤال را پاسخ میدهد: هر Pod چقدر منابع «لازم دارد» تا روی یک نود جا بگیرد، و هر Pod حداکثر چقدر «اجازهی مصرف» دارد. تنظیم نادرست این دو، پشت بسیاری از پادهای OOMKilled، نودهای ناپایدار و کلاسترهایی است که با وجود منابع آزاد، پاد جدید را زمانبندی نمیکنند. در ادامه، requests و limits، کلاسهای QoS و راهاندازی HPA را با مثال بررسی میکنیم.
requests و limits: دو مفهوم متفاوت
| requests | limits | |
|---|---|---|
| معنی | مقدار تضمینشده؛ مبنای زمانبندی | سقف مصرف مجاز |
| استفادهکننده | scheduler (انتخاب نود) | kubelet / هسته (اعمال محدودیت) |
| عبور از آن در CPU | مشکلی نیست (تا حد limit) | کندی (throttling) |
| عبور از آن در حافظه | مشکلی نیست (تا حد limit) | کشتهشدن کانتینر (OOMKilled) |
resources:
requests:
cpu: 250m # یکچهارم هسته
memory: 256Mi
limits:
cpu: "1"
memory: 256Mi
واحد CPU بر حسب هسته است (1000m = 1) و حافظه با Mi/Gi (توان ۲) نوشته میشود؛ 256M و 256Mi یکی نیستند.
کلاسهای QoS و ترتیب حذف
Kubernetes بر اساس requests و limits هر Pod یکی از سه کلاس QoS را به آن میدهد و هنگام کمبود حافظه در نود، از پایینترین کلاس شروع به حذف میکند:
- Guaranteed: برای همهی کانتینرها requests برابر limits است (هم CPU، هم حافظه). آخرین کاندیدای حذف.
- Burstable: دستکم یک request یا limit تعریف شده ولی شرط Guaranteed برقرار نیست. حالت متداول.
- BestEffort: هیچ requests و limits نیست. اولین کاندیدای حذف.
کلاس هر Pod را میتوانید با kubectl get pod <name> -o jsonpath='{.status.qosClass}' ببینید.
چگونه مقدار مناسب را پیدا کنیم؟
مقدارهای حدسی معمولاً یا بسیار کماند (OOMKilled و throttling) یا بسیار زیاد (هدررفت و پادهای Pending). روش عملی:
- با مقدارهای محافظهکارانه شروع کنید و برنامه را زیر بار واقعی یا آزمایشی اجرا کنید.
- مصرف واقعی را بخوانید:
kubectl top pod(نیازمند metrics-server) یا نمودارهای Prometheus (container_memory_working_set_bytesوrate(container_cpu_usage_seconds_total[5m])). - requests را نزدیک مصرف معمول (مثلاً صدک ۹۰) و limits حافظه را کمی بالاتر از اوج مصرف بگذارید.
- نتیجه را در طول زمان بازبینی کنید؛ مصرف با رشد برنامه عوض میشود.
kubectl top pod -n production
kubectl top node
قاعدههای تجربی
- حافظه: requests را برابر limits بگذارید. حافظه قابلفشردهسازی نیست؛ برنامهای که بیش از requests مصرف کند اولین هدف حذف است، و limit بالاتر از request فقط بیشتر نودها را بیشازحد متعهد (overcommit) میکند.
- CPU: requests را واقعبینانه بگذارید ولی limit سختگیرانه نگذارید یا آن را خیلی بالاتر بگیرید. CPU قابلفشردهسازی است و limit پایین فقط throttling ایجاد میکند که تأخیر را بالا میبرد.
- JVM و Node.js: اندازهی heap را به limit کانتینر وابسته کنید (
-XX:MaxRAMPercentageدر جاوا،--max-old-space-sizeدر Node.js)؛ در غیر این صورت برنامه فکر میکند حافظهی کل نود را دارد.
HorizontalPodAutoscaler
HPA تعداد replicas یک Deployment را بر اساس متریک (معمولاً CPU یا حافظه) خودکار تغییر میدهد. فرمول آن:
desiredReplicas = ceil( currentReplicas × currentMetric / targetMetric )
مثال: 4 replica، مصرف فعلی 90% از requests، هدف 60%
→ ceil(4 × 90 / 60) = 6 replica
نکتهی کلیدی: درصد مصرف نسبت به requests حساب میشود، نه limits. پس بدون requests، HPA کار نمیکند.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web
minReplicas: 3
maxReplicas: 12
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 50
periodSeconds: 60
K8SKubernetes YAML GeneratorDeployment همراه با requests و limits و HPA را با فرم بسازید.پیشنیازها: نصب metrics-server در کلاستر، تعریف requests برای همهی کانتینرهای Pod، و readinessProbe درست؛ بدون آن، Podهای جدید قبل از آمادهشدن ترافیک میگیرند. وضعیت را با این دستورها ببینید:
kubectl get hpa web --watch
kubectl describe hpa web # رویدادها و دلیل تصمیمها
اشتباههای رایج HPA
minReplicas: 1برای سرویس مهم؛ قطع یک Pod یعنی قطع سرویس.- هدف CPU خیلی بالا (مثل ۹۰٪)؛ تا HPA واکنش نشان دهد، تأخیر بالا رفته است. ۵۰ تا ۷۰ درصد معمول است.
- نگهداشتن
replicasدر مانیفست Deployment همزمان با HPA؛ هرkubectl applyتعداد را به مقدار ثابت برمیگرداند. فیلد replicas را وقتی HPA دارید حذف کنید. - مقیاسپذیری بر پایهی CPU برای برنامههای I/O-محور؛ در این سرویسها CPU بالا نمیرود. از متریک سفارشی (مثل طول صف یا تعداد درخواست) استفاده کنید.
LimitRange و ResourceQuota
در کلاستر مشترک، میتوانید برای هر namespace مقدار پیشفرض و سقف تعریف کنید تا هیچ Podی بدون منابع ساخته نشود و هیچ تیمی کل کلاستر را مصرف نکند:
apiVersion: v1
kind: LimitRange
metadata:
name: defaults
spec:
limits:
- type: Container
defaultRequest: { cpu: 100m, memory: 128Mi }
default: { cpu: 500m, memory: 256Mi }
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-quota
spec:
hard:
requests.cpu: "8"
requests.memory: 16Gi
pods: "40"
جمعبندی و مطالعهی بعدی
requests را مبنای زمانبندی و HPA بدانید، limits را سقف ایمنی، و مقدارها را از مصرف واقعی بخوانید نه حدس. اگر پادها OOMKilled یا Pending میشوند، راهنمای عیبیابی با kubectl مسیر بررسی را نشان میدهد و برای دیدن نمودار مصرف، راهاندازی Prometheus و Grafana را ببینید. مانیفستهای پایه هم در راهنمای Deployment، Service و Ingress آمدهاند.
پرسشهای متداول
اگر requests و limits را ننویسم چه میشود؟
چرا Pod من OOMKilled میشود؟
kubectl describe pod فیلد Last State: Terminated (OOMKilled) را ببینید.HPA چقدر طول میکشد تا واکنش نشان دهد؟
behavior قابلتنظیماند.