למה אתם כנראה משלמים יותר מדי על Kubernetes
בכנות? כשראיתי את הנתונים לראשונה, לא האמנתי. לפי סקר CNCF עדכני, כ-68% מהארגונים משלמים על Kubernetes בין 20% ל-40% יותר מהנדרש. וזה עוד מעט — בביקורות שנערכו ב-2026 מגלים ש-80-90% מה-Pods מוגדרים עם בקשות CPU וזיכרון מנופחות לגמרי. מחקר אחד אפילו מצא פער של פי 8 בין ה-CPU המבוקש לבין השימוש בפועל. פי שמונה.
אז איך זה קורה? ברוב המקרים, מפתחים מגדירים ערכי requests גבוהים כדי להימנע מ-throttling או מקריסות OOMKill. זו גישה שמובנת לחלוטין — עדיף בטוח מאשר מצטער, נכון? — אבל מבחינה כלכלית, היא שורפת כסף. כשה-Pod מבקש יותר משאבים ממה שהוא באמת צריך, ה-scheduler של Kubernetes שומר את הקיבולת הזו גם אם היא לא מנוצלת. התוצאה? Nodes שנראים "מלאים" בעוד שהשימוש בפועל נמוך, וה-Cluster Autoscaler מוסיף Nodes מיותרים בשמחה.
דוגמה קטנה שעושה את זה מוחשי: Node עם 4 ליבות שמריץ 4 Pods, כל אחד מבקש ליבה אחת אבל צורך בפועל 0.2 ליבות — מבזבז 68% מהקיבולת. הכפילו את זה ב-50 או 100 Nodes ומקבלים בזבוז של אלפי דולרים. בחודש.
המדריך הזה יראה לכם בדיוק איך לזהות את הבזבוז, למדוד את השימוש האמיתי, וליישם rightsizing בצורה בטוחה — עם כלים ודוגמאות קוד שאפשר להפעיל כבר היום.
מה זה Rightsizing ולמה זו ההשקעה הכי משתלמת ב-FinOps
Rightsizing בהקשר של Kubernetes הוא בעצם התהליך של התאמת הקצאות המשאבים — CPU, זיכרון, ואחסון — לצריכה האמיתית של כל workload. לא יותר, לא פחות. המטרה היא למצוא את נקודת האיזון בין ביצועים, יעילות, ועלות.
ולמה זו ההשקעה הכי משתלמת? כי אפילו הפחתה קטנה של 5-15% בהקצאות לכל Pod יכולה להצטבר לחיסכון של 30-60% ברמת ה-Cluster, הודות ל-bin packing יעיל יותר. ארגונים שמיישמים rightsizing שיטתי מדווחים על חיסכון של 40-70% בעלויות Kubernetes — בלי לפגוע בביצועים. מספרים שקשה להתווכח איתם.
לפני שממשיכים, חשוב להבין שני מושגים מרכזיים:
- Requests — כמות המשאבים המינימלית שה-Pod מבקש. ה-scheduler משתמש בערך הזה כדי להחליט על איזה Node לשבץ את ה-Pod.
- Limits — התקרה המקסימלית. אם ה-Pod חורג מגבול הזיכרון, הוא נהרג (OOMKill). חורג מ-CPU? מקבל throttling.
הגדרת requests נכונה היא הצעד הקריטי ביותר — כי זה מה שקובע כמה Nodes תצטרכו, ובסופו של דבר כמה תשלמו.
שלב 1: זיהוי בזבוז — כמה באמת מנוצל?
לפני שמתחילים לשנות הגדרות, צריך להבין את המצב הקיים. אי אפשר לתקן מה שלא מודדים. הנה פקודת kubectl שתראה לכם את הפער בין מה שמבוקש לבין מה שמנוצל בפועל:
kubectl top pods -n production --containers | \
awk 'NR==1{print $0, "REQ_CPU", "REQ_MEM"} NR>1{print}' | \
column -t
לתמונה מפורטת יותר, הנה סקריפט שמשווה בין requests לשימוש אמיתי ומחשב ניצולת:
#!/bin/bash
# pod-utilization-report.sh
# דוח ניצולת משאבים לכל ה-Pods ב-namespace
NAMESPACE=${1:-default}
echo "=== Pod Utilization Report for namespace: $NAMESPACE ==="
echo ""
printf "%-40s %-12s %-12s %-10s %-12s %-12s %-10s\n" \
"POD" "CPU_REQ" "CPU_USED" "CPU_%" "MEM_REQ" "MEM_USED" "MEM_%"
echo "-----------------------------------------------------------------------------------------------------------"
kubectl get pods -n "$NAMESPACE" -o json | jq -r '
.items[] |
.metadata.name as $pod |
.spec.containers[] |
"\($pod) \(.resources.requests.cpu // "none") \(.resources.requests.memory // "none")"
' | while read pod cpu_req mem_req; do
usage=$(kubectl top pod "$pod" -n "$NAMESPACE" --no-headers 2>/dev/null)
if [ -n "$usage" ]; then
cpu_used=$(echo "$usage" | awk '{print $2}')
mem_used=$(echo "$usage" | awk '{print $3}')
printf "%-40s %-12s %-12s %-10s %-12s %-12s\n" \
"$pod" "$cpu_req" "$cpu_used" "" "$mem_req" "$mem_used"
fi
done
הריצו את הסקריפט על כל namespace ותקבלו תמונה ברורה של היכן הבזבוז הגדול ביותר. חפשו Pods שבהם הניצולת מתחת ל-30% — אלו המועמדים הראשונים ל-rightsizing.
שלב 2: הגדרת VPA במצב המלצות בלבד
Vertical Pod Autoscaler (VPA) הוא כלי Kubernetes שמנתח שימוש במשאבים ומספק המלצות — או מיישם אותן אוטומטית — להקצאות CPU וזיכרון. ב-2026, ה-API היציב הוא autoscaling.k8s.io/v1.
ההמלצה שלי? התחילו תמיד במצב Off. ככה אתם מקבלים המלצות בלי שVPA נוגע בשום דבר — אפס סיכון.
התקנת VPA
# התקנה באמצעות Helm
helm repo add cowboysysop https://cowboysysop.github.io/charts/
helm install vpa cowboysysop/vertical-pod-autoscaler \
--namespace kube-system
# ודאו שכל הרכיבים רצים
kubectl get pods -n kube-system | grep vpa
הגדרת VPA במצב Off
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: myapp-vpa
namespace: production
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: myapp
updatePolicy:
updateMode: "Off"
resourcePolicy:
containerPolicies:
- containerName: myapp-container
minAllowed:
cpu: 50m
memory: 64Mi
maxAllowed:
cpu: 4
memory: 8Gi
controlledResources:
- cpu
- memory
אחרי כמה ימים של איסוף נתונים (אני ממליץ על לפחות 3-5 ימים), בדקו את ההמלצות:
kubectl describe vpa myapp-vpa -n production
בפלט תראו שלושה ערכים שכדאי לשים לב אליהם:
- Lower Bound — המינימום שנדרש כדי להימנע מ-throttling
- Target — ההמלצה האופטימלית של VPA
- Upper Bound — המקסימום שה-Pod עשוי להזדקק לו
כלל אצבע שעובד לי טוב: הגדירו את ה-request לערך ה-Target, ואת ה-limit ל-10-50% מעל (תלוי כמה אתם שמרנים). לגבי זיכרון, מומלץ להשתמש ב-P95 של ה-working set כבסיס.
שלב 3: התקנת Goldilocks — דשבורד ויזואלי להמלצות
אז VPA נותן המלצות, אבל לרוץ בין עשרות פקודות kubectl זה לא כיף. כאן נכנס Goldilocks — כלי קוד פתוח מבית Fairwinds שיושב מעל VPA ומספק דשבורד ויזואלי ממש נוח. פשוט פותחים דפדפן ורואים את כל ה-Deployments עם ההמלצות שלהם במקום אחד.
התקנה
# התקנת Goldilocks באמצעות Helm
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
kubectl create namespace goldilocks
helm install goldilocks --namespace goldilocks \
fairwinds-stable/goldilocks
הפעלה על namespace
# סמנו את ה-namespace שרוצים לנטר
kubectl label namespace production \
goldilocks.fairwinds.com/enabled=true
# Goldilocks ייצור אוטומטית VPA objects עבור כל Deployment
גישה לדשבורד
# פתחו port-forward לדשבורד
kubectl -n goldilocks port-forward svc/goldilocks-dashboard 8080:80
# פתחו בדפדפן: http://localhost:8080
הדשבורד מציג שני סוגי המלצות:
- Guaranteed QoS — requests ו-limits שווים, מבוסס על Target של VPA. מתאים ל-workloads קריטיים שלא רוצים שום הפתעות.
- Burstable QoS — requests נמוכים מ-limits, מבוסס על Lower Bound ו-Upper Bound. מתאים ל-workloads עם שינויים בעומס.
טיפ חשוב (ולמדתי את זה בדרך הקשה): ככל שה-Pods רצים יותר זמן, הנתונים שVPA אוסף מדויקים יותר. המתינו לפחות שבוע לפני שמיישמים המלצות, ובדקו שוב אחרי חודש.
שלב 4: יישום ההמלצות בצורה בטוחה
אוקיי, אספתם מספיק נתונים ויש לכם המלצות ברורות מ-VPA ו-Goldilocks. הגיע הזמן ליישם. אבל — ולא אלאה לחזור על זה — עשו את זה בהדרגה. לא הכול בבת אחת.
תהליך מומלץ
- התחילו מסביבת staging — יישמו את ההמלצות קודם בסביבה שאינה production. תמיד.
- עדכנו Deployment אחד בכל פעם — אל תשנו את כל ה-Deployments בבת אחת (כן, גם אם זה מפתה).
- עקבו אחרי מדדים — בדקו CPU throttling, OOMKills, ו-latency לפני ואחרי השינוי.
- הגדירו התראות — צרו alerts על חריגות בביצועים כדי שלא תגלו בעיות באיחור.
הנה דוגמה לעדכון Deployment עם הערכים החדשים:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: api-server
template:
metadata:
labels:
app: api-server
spec:
containers:
- name: api
image: myapp/api-server:latest
resources:
requests:
cpu: 150m # היה 500m - הופחת על בסיס VPA Target
memory: 256Mi # היה 1Gi - הופחת על בסיס P95
limits:
cpu: 300m # 2x requests - מאפשר burst
memory: 384Mi # 1.5x requests - מרווח ביטחון
שימו לב לירידה — מ-500m ל-150m ב-CPU ומ-1Gi ל-256Mi בזיכרון. זה חיסכון משמעותי ל-Pod בודד, ומשמעותי בהרבה כשמכפילים את זה ב-replicas ו-deployments.
אחרי העדכון, עקבו אחרי המדדים האלה:
# בדיקת OOMKills
kubectl get events -n production --field-selector reason=OOMKilling
# בדיקת CPU throttling (דורש metrics-server)
kubectl top pods -n production --sort-by=cpu
# בדיקת סטטוס Pods
kubectl get pods -n production -o wide
שלב 5: אופטימיזציה ברמת ה-Node עם Karpenter
Rightsizing ברמת ה-Pod הוא רק חצי מהסיפור. החצי השני? אופטימיזציה ברמת ה-Node.
כאן Karpenter נכנס לתמונה. Karpenter הוא autoscaler קוד פתוח ל-Kubernetes שמספק Nodes בזמן אמת בהתאם לצרכי ה-Pods. בניגוד ל-Cluster Autoscaler המסורתי שעובד עם Node Groups קבועים מראש, Karpenter בוחר את סוג המכונה האופטימלי עבור כל Pod — כולל תמיכה ב-Spot Instances.
למה זה שינוי כללי משחק
- Just-in-Time Provisioning — יוצר בדיוק את ה-Node שצריך, בגודל הנכון. לא יותר, לא פחות.
- Consolidation — מזהה Nodes עם ניצולת נמוכה ומחליף אותם ב-Nodes קטנים יותר
- תמיכה ב-Spot Instances — שילוב אוטומטי של Spot עם On-Demand לחיסכון נוסף של 60-90%
- פשטות — אין צורך לנהל עשרות Node Groups כמו ב-Cluster Autoscaler. פחות YAML, יותר שקט.
דוגמת NodePool
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: cost-optimized
spec:
template:
spec:
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ["spot", "on-demand"] # מעדיף Spot, fallback ל-On-Demand
- key: node.kubernetes.io/instance-type
operator: In
values:
- m7i.large
- m7i.xlarge
- m6i.large
- m6i.xlarge
- c7i.large
- c7i.xlarge
- key: topology.kubernetes.io/zone
operator: In
values:
- us-east-1a
- us-east-1b
- us-east-1c
limits:
cpu: 200
memory: 400Gi
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 30s
ההגדרה consolidationPolicy: WhenEmptyOrUnderutilized היא המפתח כאן — Karpenter ינטר Nodes עם ניצולת נמוכה ויחליף אותם ב-Nodes קטנים וזולים יותר, באופן אוטומטי. זה כמו rightsizing ברמת התשתית.
הגנה מפני בזבוז עתידי: LimitRange ו-ResourceQuota
Rightsizing הוא לא פעולה חד-פעמית — וזה משהו שהרבה צוותים לומדים בדרך הקשה. בלי מדיניות שמונעת בזבוז חוזר, כל deployment חדש עלול לחזור להגדרות מנופחות. למזלנו, Kubernetes מספק שני כלים מובנים בדיוק בשביל זה.
LimitRange — ברירות מחדל וגבולות לכל Pod
apiVersion: v1
kind: LimitRange
metadata:
name: pod-resource-limits
namespace: production
spec:
limits:
- type: Container
default:
cpu: 200m
memory: 256Mi
defaultRequest:
cpu: 100m
memory: 128Mi
max:
cpu: 2
memory: 4Gi
min:
cpu: 50m
memory: 64Mi
LimitRange מבטיח שכל Container חדש שנוצר ב-namespace יקבל ברירות מחדל סבירות. מפתח שלא הגדיר resources? לא נורא, הוא יקבל אותם אוטומטית. וגם לא יוכל לבקש יותר מהמקסימום המוגדר.
ResourceQuota — תקרת משאבים לכל ה-namespace
apiVersion: v1
kind: ResourceQuota
metadata:
name: production-quota
namespace: production
spec:
hard:
requests.cpu: "20"
requests.memory: 40Gi
limits.cpu: "40"
limits.memory: 80Gi
pods: "100"
ResourceQuota מגביל את סך המשאבים שכל ה-Pods ב-namespace יכולים לצרוך. בלי זה, צוות אחד יכול "לאכול" את כל הקיבולת של ה-Cluster בלי שאף אחד שם לב.
תהליך Rightsizing שוטף — לוח זמנים מומלץ
אז הגדרתם הכול, הכלים רצים, חסכתם כסף. מעולה. אבל כדי שזה יימשך, צריך להפוך את זה לשגרה. הנה לוח הזמנים שעובד לנו:
- שבועי — הצצה מהירה לדשבורד Goldilocks לזיהוי חריגות בולטות
- חודשי — סבב rightsizing לכל ה-Deployments ועדכון requests/limits
- אחרי כל שינוי משמעותי — עדכוני קוד גדולים, שינויי תנועה, או שדרוגי תלויות דורשים בדיקה מחדש
- רבעוני — סקירה של מדיניות ה-LimitRange וה-ResourceQuota מול דפוסי השימוש העדכניים
שאלות נפוצות
איך עושים rightsizing ל-Pods ב-Kubernetes?
התהליך מתחיל בניטור צריכת המשאבים בפועל באמצעות כלים כמו metrics-server, VPA, ו-Goldilocks. אחרי איסוף נתונים של לפחות שבוע, משווים בין ה-requests/limits הנוכחיים לבין השימוש האמיתי, ומתאימים את ההגדרות כך שה-requests יהיו קרובים ל-P95 של הצריכה. מומלץ לעשות את זה בהדרגה — namespace אחד בכל פעם — ולעקוב אחרי מדדי ביצועים אחרי כל שינוי.
כמה אפשר לחסוך מ-rightsizing של Kubernetes?
ארגונים שמיישמים rightsizing שיטתי מדווחים על חיסכון של 30-70%. לדוגמה, חברת Trax חסכה 75% בעלויות Kubernetes באמצעות rightsizing אוטומטי, ו-SNCF הפחיתה 30% מהעלויות תוך שיפור היציבות. גם הפחתות קטנות לכל Pod מצטברות לחיסכון גדול ברמת ה-Cluster.
מה עדיף — VPA או HPA?
הם לא מתחרים, הם משלימים. VPA מתאים requests/limits אנכית (יותר CPU/זיכרון לכל Pod), בעוד HPA מוסיף או מפחית Pods אופקית. דפוס נפוץ שעובד טוב: HPA לסקיילינג על בסיס CPU, ו-VPA במצב Off לקבלת המלצות לזיכרון. רק ודאו שהמלצות VPA לא מתנגשות עם טריגרים של HPA.
האם VPA מפיל Pods בזמן עדכון?
תלוי במצב. במצב Off ו-Initial — VPA לא נוגע ב-Pods בכלל. במצב Recreate, VPA מסיר ומייצר Pods מחדש כדי ליישם שינויים. החל מגרסה 1.4, יש מצב InPlaceOrRecreate שמנסה לעדכן משאבים בלי restart — ואם לא מצליח, חוזר ל-eviction. לסביבות production, התחילו עם Off והעלו בהדרגה.
כל כמה זמן צריך לעשות rightsizing?
כשגרה — פעם בחודש. בנוסף לזה, בדקו מחדש אחרי שינויי קוד משמעותיים, שינויים בתבניות תנועה, שדרוגי תלויות, או אירועים חריגים. ארגונים מתקדמים כבר עברו ל-rightsizing אוטומטי מתמשך עם Karpenter ו-VPA במצב Auto, עם guardrails שמגנים מפני הפתעות.