פוסט
Kubernetes: עדכונים מתגלגלים, הגדרות, בדיקות בריאות וסקיילינג אוטומטי
מעדכנים את hello-app בלי השבתה וחוזרים אחורה, מעבירים הגדרות עם ConfigMaps ו-Secrets, מוסיפים בדיקות readiness ו-liveness, מגדירים requests ו-limits, ומגדילים עם HPA.
החלק הזה ממשיך מה-Deployment וה-Service בשם hello שבתיקייה k8s/, מDeployments, Services והכנסת תעבורה מבחוץ. כל שינוי כאן הוא עריכה של k8s/deployment.yaml ואחריה kubectl apply.
עדכונים מתגלגלים וחזרה לאחור
משנים את הקוד, בונים hello-app:1.1, טוענים אותו ל-kind, ומשנים את האימג’ ב-deployment.yaml:
docker build -t hello-app:1.1 .
kind load docker-image hello-app:1.1
# edit k8s/deployment.yaml: image: hello-app:1.1
kubectl apply -f k8s/deployment.yaml
kubectl rollout status deployment/hello
Kubernetes לא עוצר הכול ומתחיל מחדש. הוא מבצע עדכון מתגלגל (rolling update): מפעיל Pod חדש, מחכה שיהיה מוכן, מסיר ישן, וחוזר על זה. כברירת מחדל מותר ליצור עד 25% Pods נוספים (maxSurge) ועד 25% יכולים להיות לא זמינים (maxUnavailable); עם 3 עותקים זה Pod חדש אחד בכל פעם, ואף אחד לא חסר.
עדכון מתחיל רק כשתבנית ה-Pod (.spec.template) משתנה, למשל האימג’ או משתנה סביבה. סקיילינג לא מתחיל עדכון.
אם הגרסה החדשה גרועה, חוזרים אחורה:
kubectl rollout history deployment/hello
kubectl rollout undo deployment/hello
kubectl rollout undo deployment/hello --to-revision=1
כברירת מחדל Deployment שומר בשביל זה 10 ReplicaSets ישנים (revisionHistoryLimit). אחרי undo מתקנים גם את הקובץ, אחרת ה-apply הבא מחזיר את הגרסה הגרועה.
הגדרות: ConfigMaps ו-Secrets
מוציאים הגדרות מהאימג’, כדי שאותו אימג’ ירוץ בכל סביבה. ConfigMap מחזיק הגדרות רגילות, ו-Secret מחזיק הגדרות רגישות:
kubectl create configmap hello-config --from-literal=LOG_LEVEL=info
kubectl create secret generic hello-secret --from-literal=DB_PASSWORD=dev-only
מעבירים אותם לקונטיינר כמשתני סביבה, בתבנית ה-Pod:
containers:
- name: hello
image: hello-app:1.1
envFrom:
- configMapRef:
name: hello-config
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: hello-secret
key: DB_PASSWORD
envFrom טוען את כל המפתחות של ה-ConfigMap. secretKeyRef בוחר מפתח אחד מה-Secret. (השרת הקטן שלנו קורא רק את PORT; הם כאן כדי להראות את החיבור.) אפשר גם לחבר ConfigMaps ו-Secrets כקבצים.
השם מטעה. התיעוד של Secrets מזהיר ש-Secrets נשמרים כברירת מחדל לא מוצפנים ב-etcd, והערכים ב-YAML רק מקודדים ב-base64, שכל אחד יכול לפענח. מפעילים הצפנה במנוחה (encryption at rest), מגבילים עם RBAC מי קורא Secrets, ושוקלים מאגר סודות חיצוני. אף פעם לא מעלים ל-Git מניפסט של Secret עם ערכים אמיתיים.
בדיקות בריאות: probes
Kubernetes יודע אם התהליך בקונטיינר רץ, לא אם האפליקציה עובדת. Probes אומרים לו. התיעוד של probes מגדיר שלושה:
- Readiness: האם הקונטיינר מוכן לקבל תעבורה? אם הבדיקה נכשלת, ה-Pod מוסר מה-endpoints של ה-Service, אבל לא מופעל מחדש.
- Liveness: האם הקונטיינר עדיין תקין? אם הבדיקה נכשלת מספיק פעמים, ה-kubelet מפעיל את הקונטיינר מחדש.
- Startup: האם אפליקציה איטית סיימה לעלות? בדיקות liveness ו-readiness מחכות עד שהיא מצליחה.
מוסיפים אותם לקונטיינר:
readinessProbe:
httpGet:
path: /
port: 3000
periodSeconds: 5
livenessProbe:
httpGet:
path: /
port: 3000
periodSeconds: 10
failureThreshold: 3
readiness הופך עדכונים מתגלגלים לבטוחים: Pod חדש מקבל תעבורה רק אחרי שהוא עונה. באפליקציה אמיתית מכוונים את הבדיקות ל-endpoint קל כמו /healthz, ומשאירים את ה-liveness פשוט: אם הוא תלוי בבסיס הנתונים ובסיס הנתונים מגמגם, Kubernetes מפעיל מחדש את כל ה-Pods בבת אחת.
משאבים: requests ו-limits
אומרים ל-Kubernetes כמה CPU וזיכרון כל קונטיינר צריך:
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
memory: 128Mi
- Requests הם מה שה-scheduler שומר. Pod ממוקם רק על node שיש בו כמות פנויה כזו.
100mהם 100 millicores, עשירית CPU. - Limits הם התקרה. קונטיינר שעובר את מגבלת הזיכרון נהרג (
OOMKilled) ומופעל מחדש. מעבר למגבלת CPU רק מאט אותו.
בלי requests ה-scheduler מנחש, ו-Pod רעב אחד יכול להרעיב את השכנים שלו, אז מגדירים אותם בכל מקום.
סקיילינג אוטומטי
HorizontalPodAutoscaler (HPA) משנה בשבילכם את replicas לפי העומס:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: hello
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: hello
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
היעד הוא 70% בממוצע מה-CPU שהתבקש, ולכן requests של CPU חייבים להיות מוגדרים. ה-HPA צריך גם Metrics Server, ש-kind לא כולל ורוב העננים המנוהלים כן (המדריך של HPA). כש-HPA מנהל Deployment, מוחקים את replicas מהקובץ של ה-Deployment, אחרת כל apply מאפס אותו.