פוסט
Kubernetes: Deployments, Services והכנסת תעבורה מבחוץ
מריצים את hello-app כ-Deployment ששומר על שלושה עותקים, נותנים לו כתובת קבועה עם Service, משווים בין סוגי Service, ומנתבים תעבורה מבחוץ עם Gateway API או Ingress.
החלק הזה צריך את הקלאסטר של kind ואת יסודות המניפסטים מKubernetes מאפס לגיבור, ואת האימג’ hello-app מDocker מאפס לגיבור: שרת Node קטן על פורט 3000.
Deployments: שומרים על N עותקים רצים
בונים את האימג’ עם תגית גרסה אמיתית וטוענים אותו לקלאסטר של kind (אחרת ה-nodes של kind לא רואים את האימג’ים המקומיים שלכם):
docker build -t hello-app:1.0 .
kind load docker-image hello-app:1.0
למה 1.0 ולא latest? Kubernetes תמיד מנסה למשוך :latest מ-registry, והאימג’ שלנו קיים רק מקומית. תגית גרסה גם אומרת בדיוק מה רץ.
יוצרים תיקייה k8s/ וקובץ k8s/deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello
labels:
app: hello
spec:
replicas: 3
selector:
matchLabels:
app: hello
template:
metadata:
labels:
app: hello
spec:
containers:
- name: hello
image: hello-app:1.0
ports:
- containerPort: 3000
קוראים את זה כמו משפט: תשמור על 3 עותקים של Pods עם התווית app: hello, והנה התבנית ליצירת אחד. ה-selector חייב להתאים ל-labels שב-template, אחרת ה-API דוחה אותו.
kubectl apply -f k8s/deployment.yaml
kubectl get deployments
kubectl get pods -l app=hello
NAME READY UP-TO-DATE AVAILABLE AGE
hello 3/3 3 3 20s
מאחורי הקלעים ה-Deployment יצר ReplicaSet, וה-ReplicaSet יצר את ה-Pods. מנהלים את ה-Deployment, ומשאירים לו את כל השאר.
עכשיו רואים את לולאת התיקון בפעולה. מוחקים Pod אחד (לוקחים שם מהפלט של get pods):
kubectl delete pod <one-of-the-hello-pods>
kubectl get pods -l app=hello
Pod חדש עם שם חדש כבר עולה.
סקיילינג הוא שדה אחד: משנים בקובץ את replicas: 3 ל-5 ומריצים apply שוב. לבדיקה מהירה:
kubectl scale deployment/hello --replicas=5
עדיף הקובץ: אם משנים בפקודה ואחר כך מריצים עליו apply, חוזרים ל-3.
Services: כתובת קבועה ל-Pods
Pods הם חד-פעמיים. כל Pod חדש מקבל IP חדש, ולכן שום דבר לא אמור לדבר ישירות עם IP של Pod. Service נותן לקבוצת Pods שם ו-IP קבועים, ומפזר תעבורה בין ה-Pods שתואמים ל-selector שלו ברגע זה.
יוצרים את k8s/service.yaml:
apiVersion: v1
kind: Service
metadata:
name: hello
spec:
selector:
app: hello
ports:
- port: 80
targetPort: 3000
port הוא מה שלקוחות משתמשים בו. targetPort הוא הפורט בקונטיינר שאליו התעבורה הולכת. מריצים apply על כל התיקייה, ובודקים מתוך הקלאסטר עם Pod זמני:
kubectl apply -f k8s/
kubectl get services
kubectl run tmp --rm -it --image=busybox:1.37 --restart=Never -- wget -qO- http://hello
Hello from a container
השם hello עובד כי לקלאסטר יש DNS משלו. באותו namespace מספיק שם ה-Service; מ-namespace אחר משתמשים ב-hello.<namespace>.
כדי להגיע אליו מהדפדפן שלכם בזמן פיתוח, מעבירים פורט מקומי:
kubectl port-forward service/hello 8080:80
# in another terminal:
curl localhost:8080
סוגי Service
בלי type, Service הוא ClusterIP. התיעוד של Services מפרט את השאר:
| סוג | מה הוא עושה |
|---|---|
ClusterIP |
ברירת המחדל. IP ושם DNS קבועים, רק בתוך הקלאסטר. |
NodePort |
פותח גם פורט אחד על כל node, מהטווח 30000-32767 כברירת מחדל. |
LoadBalancer |
מבקש גם מספק הענן load balancer חיצוני. |
ExternalName |
כינוי DNS (CNAME) לשם מחוץ לקלאסטר. בלי שום proxy. |
בענן, type: LoadBalancer נותן ל-Service אחד כתובת IP ציבורית. עם הרבה שירותים לא רוצים load balancer לכל אחד.
הכנסת תעבורה מבחוץ: Gateway ו-Ingress
כדי לנתב הרבה שמות host ונתיבים להרבה Services דרך נקודת כניסה אחת, ל-Kubernetes יש שני APIs:
- Ingress, הישן. עמוד ה-Ingress ממליץ היום על Gateway במקומו ואומר שה-API של Ingress הוקפא: הוא עדיין עובד, אבל לא מקבל יכולות חדשות.
- Gateway API, המחליף המומלץ. מי שמפעיל את הקלאסטר מקים
Gateway(נקודת הכניסה), וכל צוות מחבר אליו אובייקטים מסוגHTTPRoute.
HTTPRoute ששולח את hello.example.com ל-Service שלנו:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: hello
spec:
parentRefs:
- name: my-gateway
hostnames:
- hello.example.com
rules:
- backendRefs:
- name: hello
port: 80
אף אחד משני ה-APIs לא עושה כלום לבד: צריך בקר שמממש אותו, מותקן בקלאסטר או מסופק על ידי הענן (המימושים).
הבקר הפופולרי ingress-nginx הוצא משימוש במרץ 2026. התקנות קיימות ממשיכות לרוץ אבל בלי תיקוני אבטחה, ולכן אם מדריך אומר להתקין אותו, בוחרים בקר שמתוחזק.