راهاندازی Horizontal Pod Autoscaler در Kubernetes خودمیزبان: مقیاسپذیری خودکار Pod بر اساس مصرف CPU و Memory

روی یک کلاستر Kubernetes خودمیزبان، چیزی به اسم مقیاسپذیری خودکار از قبل آماده نیست. در Kubernetes مدیریتشده مثل GKE یا EKS یک سری قطعه از قبل سر هم شده، اما روی کلاستری که خودتان بالا آوردهاید، باید هر تکه را دستی وصل کنید. این مقاله همان مسیر را قدمبهقدم نشان میدهد: از نصب Metrics Server تا راهاندازی Horizontal Pod Autoscaler بر اساس مصرف CPU و Memory.
Horizontal Pod Autoscaler چیست
Horizontal Pod Autoscaler (یا HPA) یک کنترلر داخل Kubernetes است که تعداد replicaهای یک Deployment را بر اساس مصرف واقعی منابع بالا و پایین میبرد. وقتی مصرف CPU از آستانهای که تعیین کردهاید بالاتر برود، HPA چند Pod تازه اضافه میکند؛ وقتی بار کم شود، بعد از مدتی همان Podها را حذف میکند.
تفاوتش با مقیاسپذیری دستی همین جاست: با kubectl scale شما باید مدام وضعیت را چک کنید و خودتان عدد replica را تغییر دهید. HPA این کار را با یک حلقهٔ کنترل خودکار انجام میدهد، به شرطی که منبع دادهای برای مصرف CPU و Memory در اختیارش بگذارید. همین «منبع داده» روی کلاستر خودمیزبان از پیش وجود ندارد و باید آن را خودتان نصب کنید.
پیشنیازها
قبل از شروع اینها را آماده کنید:
- یک کلاستر Kubernetes در حال اجرا (با kubeadm، k3s یا هر روش دیگر) با دسترسی
kubectlاز ماشین خودتان. - حداقل یک Deployment که
resources.requestsروی آن تعریف شده باشد؛ بدون این مقدار، HPA نمیداند درصد مصرف را نسبت به چه عددی حساب کند. - ظرفیت آزاد کافی روی nodeها برای اینکه Podهای جدید جایی برای اجرا شدن داشته باشند.
نصب Metrics Server در کلاستر خودمیزبان
Metrics Server همان چیزی است که دادههای مصرف CPU و Memory را از kubelet هر node جمع میکند و از طریق Metrics API (metrics.k8s.io) در دسترس بقیهٔ کلاستر میگذارد. بدون آن نه kubectl top کار میکند و نه HPA چیزی برای خواندن دارد.
نصب با یک دستور:
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
رفع خطای گواهی kubelet
روی کلاستر خودمیزبان، معمولا گواهی TLS کوبلت self-signed است و Metrics Server با خطای گواهی crash میشود. راهحل، اضافه کردن یک آرگومان به Deployment آن است:
kubectl -n kube-system patch deployment metrics-server \
--type='json' \
-p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'
این گزینه بررسی گواهی کوبلت را غیرفعال میکند. در یک محیط production که از PKI داخلی استفاده میکنید بهتر است بهجایش گواهی معتبر صادر کنید، اما برای شروع کار همین کافی است.
تست نصب
بعد از یک تا دو دقیقه که Metrics Server آمد بالا:
kubectl top nodes
kubectl top pods -A
اگر این دو دستور عدد نشان دادند، یعنی مسیر داده آماده است و میتوانید سراغ HPA بروید.
تعریف Resource Requests روی Deployment
HPA درصد مصرف را نسبت به requests حساب میکند، نه نسبت به limits. اگر requests تعریف نشده باشد، HPA اصلا نمیتواند هدف درصدی را محاسبه کند. یک نمونه:
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
عدد 250m یعنی یکچهارم یک هسته. این عدد را واقعی تنظیم کنید، نه خیلی کم (که HPA را زودتر از لازم فعال کند) و نه خیلی زیاد (که node جا برای Podهای تازه نداشته باشد).
راهاندازی Horizontal Pod Autoscaler
دو راه برای ساخت HPA وجود دارد.
روش اول، یک دستور ساده:
kubectl autoscale deployment myapp --cpu-percent=70 --min=2 --max=10
این یعنی وقتی میانگین مصرف CPU همهٔ replicaها از ۷۰٪ بگذرد، Kubernetes replica تازه اضافه میکند، حداقل ۲ و حداکثر ۱۰ عدد.
روش دوم، نوشتن یک منیفست که هم خواناتر است و هم قابل نگهداری در Git:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
برای اعمال آن:
kubectl apply -f hpa.yaml
مقیاسپذیری بر اساس Memory
همان منیفست را میشود با یک متریک دوم تکمیل کرد تا Memory هم بررسی شود:
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
وقتی چند متریک با هم تعریف شود، HPA همیشه بر اساس متریکی عمل میکند که بیشترین تعداد replica را پیشنهاد بدهد. نکتهای که اینجا باید در نظر بگیرید: مصرف Memory معمولا بعد از افت بار به همان سرعت CPU پایین نمیآید، چون خیلی از برنامهها حافظه را نگه میدارند و زود آزاد نمیکنند. اگر مقیاسپذیری فقط بر اساس Memory تنظیم شده باشد، ممکن است Podها دیرتر از انتظار کاهش پیدا کنند.
تست عملی: ایجاد بار و مشاهده مقیاسپذیری
برای دیدن HPA در عمل، یک بار مصنوعی روی سرویس بسازید:
kubectl run load-generator --image=busybox --restart=Never -- \
/bin/sh -c "while true; do wget -q -O- http://myapp; done"
و در یک پنجرهٔ دیگر وضعیت را زنده نگاه کنید:
kubectl get hpa -w
ظرف چند ثانیه تا چند دقیقه، ستون REPLICAS باید بالا برود. بعد از اینکه load-generator را پاک کنید، منتظر بمانید؛ HPA بهصورت پیشفرض یک پنجرهٔ پایداری ۳۰۰ ثانیهای برای کاهش replica دارد تا با هر نوسان کوچک بار، Podها مدام بالا و پایین نشوند.

مقایسهٔ روشهای مقیاسپذیری روی کلاستر خودمیزبان
قبل از اینکه فقط به HPA تکیه کنید، خوب است بدانید در کنارش چه گزینههای دیگری هست و کدامشان روی یک کلاستر خودمیزبان در دسترس است.
| روش | نحوهٔ کار | زمان واکنش | محدودیت روی کلاستر خودمیزبان |
|---|---|---|---|
مقیاسپذیری دستی (kubectl scale) | تغییر دستی تعداد replica | فوری، ولی نیاز به دخالت انسان | برای بار پیشبینینشده عملا دیر میرسد |
| Horizontal Pod Autoscaler | افزایش یا کاهش خودکار replica بر اساس CPU/Memory | چند ثانیه تا چند دقیقه | نیاز به Metrics Server، و node باید ظرفیت خالی داشته باشد |
| Vertical Pod Autoscaler | تغییر میزان CPU/Memory تخصیصی به هر Pod | کندتر، معمولا با ریستارت Pod همراه است | همزمان با HPA روی همان متریک قابل استفاده نیست |
| Cluster Autoscaler | اضافه یا کم کردن خود nodeها | چند دقیقه | روی VPS یا سرور اختصاصی خودمیزبان معمولا در دسترس نیست؛ اضافه کردن node دستی انجام میشود |
همین ردیف آخر نکتهٔ اصلی کلاستر خودمیزبان است: HPA تعداد Pod را کم و زیاد میکند، اما تعداد node را خودش زیاد نمیکند. اگر ظرفیت nodeهای فعلی تمام شود، Podهای تازه در وضعیت Pending میمانند و باید خودتان یک node دیگر اضافه کنید.
نکات عملی برای برنامهریزی ظرفیت
چند نکتهای که معمولا بعد از چند روز استفاده از HPA متوجهشان میشوید:
maxReplicasرا بر اساس ظرفیت واقعی nodeها تعیین کنید، نه یک عدد دلخواه. اگر مجموعrequestsده Pod بیشتر از CPU و RAM آزاد کلاستر باشد، HPA عدد ده را هدف میگیرد اما بخشی از آنها Pending میماند.- فیلد
behaviorدر منیفست HPA امکان تنظیم جداگانهٔ سرعت بالا رفتن و پایین آمدن را میدهد؛ برای سرویسهایی که نوسان ناگهانی دارند، معمولا scale-up سریعتر و scale-down محتاطتر تنظیم میشود. - اگر مصرف منابع کلاستر مدام به سقف میرسد، راهحل HPA نیست؛ آن موقع باید یک node با CPU و RAM بیشتر به کلاستر اضافه کنید.
برای همین مورد آخر، یک سرور ابری یا VPS با امکان ارتقای سریع پلن یا سفارش یک سرور اختصاصی جدید، کار اضافه کردن node تازه به کلاستر را خیلی سریعتر میکند؛ کافی است node جدید را بسازید، Kubernetes را روی آن نصب کنید و با kubeadm join به کلاستر وصلش کنید.
جمعبندی
راهاندازی Horizontal Pod Autoscaler روی یک کلاستر خودمیزبان سه مرحلهٔ اصلی دارد: نصب Metrics Server، تعریف requests درست روی Deployment، و ساخت منیفست HPA با آستانهٔ CPU یا Memory مناسب. بعد از آن، تنها کاری که میماند مانیتور کردن سرور است تا ببینید آستانهها با الگوی واقعی بار سرویستان جور است یا نیاز به تنظیم دوباره دارد.
اگر کلاستر فعلی جا برای Podهای تازهای که HPA میسازد ندارد، سراغ سرور ابری آریانت بروید و یک node تازه به کلاستر اضافه کنید.
سؤالات متداول
آیا HPA بدون Metrics Server کار میکند؟
نه. HPA دادههای مصرف CPU و Memory را از Metrics API میخواند و بدون نصب Metrics Server، دستور kubectl get hpa فقط عبارت <unknown> نشان میدهد.
آیا HPA میتواند بر اساس متریک سفارشی غیر از CPU و Memory کار کند؟ بله، با نصب چیزی مثل Prometheus Adapter میشود متریکهای سفارشی (مثل تعداد درخواست در ثانیه) را هم به HPA معرفی کرد. در حالت پیشفرض Kubernetes فقط CPU و Memory را پشتیبانی میکند.
چرا بعد از کم شدن بار، تعداد Podها فورا کاهش پیدا نمیکند؟
HPA یک پنجرهٔ پایداری پیشفرض ۳۰۰ ثانیهای برای scale-down دارد تا با هر افت موقت بار، Podها مدام حذف و دوباره ساخته نشوند. این عدد با فیلد behavior.scaleDown.stabilizationWindowSeconds قابل تغییر است.
آیا HPA روی StatefulSet هم کار میکند؟
از نظر فنی بله، چون scaleTargetRef میتواند به StatefulSet هم اشاره کند؛ اما چون خیلی از برنامههای stateful (مثل دیتابیسها) بهسادگی قابل مقیاسپذیری افقی نیستند، این حالت خیلی کمتر از HPA روی Deployment استفاده میشود.




