Podها ephemeralاند: ساخته میشوند، میمیرند، IP عوض میشود، تعداد replica بالا و پایین میرود. اگر frontend بخواهد مستقیم به IP لحظهای backend وصل شود، سرویسکشف شکننده میشود.
طبق مستندات رسمی Service:
Service روشی است برای expose کردن یک اپ شبکه که بهصورت یک یا چند Pod در cluster اجرا میشود — پشت یک endpoint روبهبیرون پایدار، حتی وقتی workload روی چند backend پخش است.
این مقاله deep dive روی Service و typeها است. بخش labels/selector به metadata وصل میشود؛ خود ObjectMeta را دوباره تکرار نمیکنیم.
مشکل و راهحل
| بدون Service | با Service |
|---|---|
| IP پاد عوض میشود | VIP یا DNS پایدار |
| باید لیست پادها را خودتان track کنید | selector + EndpointSlice خودکار |
| load balancing دستی | kube-proxy / dataplane |
| کشف سرویس سفارشی | DNS داخلی name.ns.svc.cluster.local |
Service یک انتزاع شبکه است: مجموعه منطقی endpointها + سیاست دسترسی.
آناتومی یک Service
apiVersion: v1
kind: Service
metadata:
name: web # باید DNS label معتبر (RFC 1123) باشد
namespace: production
labels:
app.kubernetes.io/name: web
spec:
type: ClusterIP # پیشفرض اگر ننویسید
selector:
app: web # labels روی Pod — نه لزوماً روی Deployment
ports:
- name: http
protocol: TCP
port: 80 # پورتی که کلاینت به Service میزند
targetPort: http # پورت/نام پورت روی Pod
sessionAffinity: Nonemetadata مهم برای Service
| فیلد | نقش در Service |
|---|---|
| name | پایهٔ DNS داخلی سرویس |
| namespace | محدودهٔ کشف (web.production.svc...) |
| labels | سازماندهی خود شیء Service (برای ابزارها/سیاست) |
| annotations | اغلب برای cloud LB، Ingress controller، mesh |
جزئیات عمومی ObjectMeta: مقاله metadata.
قلب اتصال: spec.selector و labels پاد
Service.spec.selector → match روی Pod.metadata.labels
→ فقط Podهای Ready معمولاً در Endpoints میآیندتله کلاسیک: label روی metadata دیپلویمنت با selector سرویس یکی نیست. Service به Pod template labels میچسبد. جزئیات labels در مقاله metadata؛ الگوی selector در spec.
kubectl get endpoints web -n production
kubectl get endpointslice -l kubernetes.io/service-name=web -n productionپورتها: port · targetPort · nodePort
| فیلد | معنی |
|---|---|
| port | پورت مجازی Service (آنچه کلاینت میبیند) |
| targetPort | پورت روی Pod (عدد یا نام containerPort) |
| nodePort | فقط برای NodePort/LoadBalancer — پورت روی هر Node |
| protocol | پیشفرض TCP؛ UDP / SCTP هم ممکن |
| name | وقتی چند پورت دارید اجباریتر؛ برای ارجاع |
| appProtocol | راهنما برای پیادهسازیها (مثلاً http) |
ports:
- name: http
port: 80
targetPort: http-web-svc # نام پورت در Pod
protocol: TCPمزیت targetPort نامدار: میتوانید شماره پورت داخل container را عوض کنید بدون شکستن کلاینتهایی که به port: 80 سرویس میزنند.
یک Service میتواند چند پورت داشته باشد (مثلاً http + metrics).
جدول یکنگاه: انواع Service
| Type | دسترسی | VIP؟ | کاربرد典型 |
|---|---|---|---|
| ClusterIP | فقط داخل cluster | بله (مگر headless) | سرویسبهسرویس — پیشفرض |
| NodePort | از بیرون via IP نود + پورت ثابت | بله + NodePort | lab، bare metal بدون LB ابری |
| LoadBalancer | IP/hostname بیرونی LB | بله + معمولاً NodePort | cloud production برای TCP/UDP |
| ExternalName | DNS CNAME به خارج | خیر — فقط DNS | وابستگی خارجی (DB/API مدیریتشده) |
Headless (clusterIP: None) | DNS مستقیم به Pod IPها | خیر | StatefulSet، کشف per-pod |
Ingress و Gateway type سرویس نیستند؛ معمولاً جلوی ClusterIP مینشینند برای HTTP(S).
۱. ClusterIP (پیشفرض)
spec:
type: ClusterIP
selector:
app: web
ports:
- port: 80
targetPort: 8080- یک Cluster IP داخلی تخصیص مییابد
- فقط از داخل cluster (و شبکه همتراز) reachable است
- برای اینترنت عمومی: جلوی آن Ingress / Gateway / mesh بگذارید
کشف DNS (CoreDNS):
web.production.svc.cluster.local
# کوتاه داخل همان ns: webاین نوع برای اکثر ترافیک east-west کافی است.
تخصیص IP
spec:
clusterIP: 10.96.100.10 # اختیاری؛ معمولاً خودکار
# یا clusterIP: None برای headlessبعد از create، clusterIP معمولاً immutable است.
۲. NodePort
روشنکردن Service روی هر Node روی یک پورت استاتیک (بازه پیشفرض رایج: ۳۰۰۰۰–۳۲۷۶۷).
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 8080
nodePort: 30080 # اختیاری؛ وگرنه خودکارلایهها:
Client → <NodeIP>:30080 → (kube-proxy) → ClusterIP → Pod- خودبهخود یک ClusterIP هم دارد
- مناسب تست، on-prem بدون CCM، یا جلوی LB سختافزاری خودتان
- هر Node همان nodePort را advertise میکند؛ ترافیک ممکن است به نودی برود که Pod ندارد (سپس hop داخلی) مگر
externalTrafficPolicy: Local
محدودیتها: تعداد پورت محدود، امنیتی بودن باز کردن روی همه نودها، نیاز به دانستن IP نود.
۳. LoadBalancer
برای expose بیرونی با load balancer خارجی (معمولاً cloud provider یا MetalLB / K3s ServiceLB).
spec:
type: LoadBalancer
selector:
app: web
ports:
- port: 80
targetPort: 8080
# loadBalancerIP: ... # وابسته به پیادهسازی؛ در dual-stack ضعیف است
allocateLoadBalancerNodePorts: true # پیشفرض؛ بعضی LB مستقیم به Pod میروندسلسلهمراتب مفهومی:
LoadBalancer ⊃ NodePort ⊃ ClusterIPیعنی معمولاً هم VIP ابری دارید، هم NodePort، هم ClusterIP.
kubectl get svc web -w
# EXTERNAL-IP از <pending> به IP واقعیبدون cloud controller / LB پیادهسازیشده، EXTERNAL-IP تا ابد pending میماند.
فیلدهای مرتبط cloud (بسته به provider):
- annotations مخصوص AWS/GCP/Azure
loadBalancerSourceRangesexternalTrafficPolicyبرای حفظ client IP و health check
allocateLoadBalancerNodePorts: false فقط وقتی LB مستقیماً به Podها route میکند معنا دارد؛ روی سرویس موجود، nodePortهای قبلی خودکار آزاد نمیشوند مگر از ports حذفشان کنید.
۴. ExternalName
بدون proxy به Pod — فقط DNS alias (CNAME) داخل cluster:
apiVersion: v1
kind: Service
metadata:
name: external-db
spec:
type: ExternalName
externalName: db.prod.example.com
# selector نگذاریدexternal-db.default.svc.cluster.local → CNAME → db.prod.example.comکاربرد: یک نام ثابت داخل cluster برای وابستگی خارج (RDS، API شریک، …) تا بین envها فقط externalName عوض شود.
- هیچ ClusterIP / kube-proxy برای این type نیست
- فیلدهایی مثل selector برای ساخت ExternalName معنا ندارند / پاک میشوند
۵. Headless Service (clusterIP: None)
گاهی VIP و proxy نمیخواهید — کلاینت باید مستقیم به Pod وصل شود (مثلاً quorum دیتابیس، Sticky identity).
apiVersion: v1
kind: Service
metadata:
name: mydb
spec:
clusterIP: None
selector:
app: mydb
ports:
- port: 5432
targetPort: 5432رفتار:
- ClusterIP تخصیص نمیشود
- kube-proxy این سرویس را handle نمیکند (بدون LB پلتفرمی)
- با selector: DNS رکوردهای A/AAAA به IP پادها
- برای StatefulSet +
serviceName: نامهای پایدار مثلmydb-0.mydb.ns.svc.cluster.local
بدون selector: DNS ممکن است به externalName یا رکوردهای تعریفشدهٔ دیگر وابسته باشد (طبق docs) — EndpointSlice خودکار ساخته نمیشود.
EndpointSlice (و Endpoints قدیمی)
کنترلر بهطور پیوسته Podهای مطابق selector را میخواند و EndpointSlice را بهروز میکند.
| API | وضعیت |
|---|---|
| EndpointSlice | مسیر مدرن؛ dual-stack؛ مقیاسپذیر (slice حدود ۱۰۰ endpoint) |
| Endpoints | deprecated نسبی؛ محدودیت ~۱۰۰۰؛ برای کلاینتهای جدید توصیه نمیشود |
Service بدون selector
برای backend خارج از cluster یا مهاجرت تدریجی:
# Service بدون selector
spec:
ports:
- port: 80
targetPort: 9376
---
# EndpointSlice دستی با label
# kubernetes.io/service-name: my-serviceمحدودیت: kubectl port-forward service/... به endpoint غیر-Pod معمولاً کار نمیکند (امنیتی).
IPهای loopback و link-local بهعنوان endpoint مجاز نیستند؛ ClusterIP سرویس دیگر هم مقصد معتبر برای kube-proxy نیست.
Discovery: DNS و متغیر محیطی
DNS (ترجیح مدرن)
<service>.<namespace>.svc.cluster.localHeadless: چند A/AAAA یا SRV بهجای یک VIP.
Env vars (میراث Docker-link مانند)
Podهایی که بعد از Service ساخته شوند ممکن است WEB_SERVICE_HOST / PORT بگیرند. شکننده است (ترتیب create) — DNS را ترجیح دهید.
سیاست ترافیک و affinity
sessionAffinity
spec:
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10800اتصالهای بعدی از همان client IP (آنگونه که proxy میبیند) به همان Pod. برای headless بیمعناست (proxy نیست).
با externalTrafficPolicy: Cluster، IP واقعی کلاینت ممکن است SNAT شود و affinity «کلاینت واقعی» را نبیند.
externalTrafficPolicy / internalTrafficPolicy
| مقدار | رفتار تقریبی |
|---|---|
| Cluster (پیشفرض خارجی) | ترافیک ممکن است به نود دیگر برود؛ SNAT محتمل |
| Local | فقط به Pod روی همان نود؛ اگر نباشد ممکن است drop؛ client IP بهتر حفظ میشود |
برای LB ابری، Local با health check نودهایی که Pod ندارند را از pool خارج میکند.
internalTrafficPolicy: Local مشابه برای ترافیک داخل cluster (کاهش hop، با ریسک endpoint خالی محلی).
Dual-stack و خانواده IP
Clusterهای dual-stack میتوانند:
spec:
ipFamilyPolicy: PreferDualStack # یا SingleStack / RequireDualStack
ipFamilies:
- IPv4
- IPv6جزئیات به CNI و نسخه cluster بستگی دارد — با kubectl explain service.spec.ipFamilyPolicy چک کنید.
proxy dataplane: kube-proxy و فراتر
بهطور کلاسیک kube-proxy (iptables / ipvs / nftables) VIP را به Podها میرساند. جایگزینها:
رفتار NodePort روی localhost و آدرسهای نود به mode و فلگهای kube-proxy وابسته است.
Service در برابر Ingress / Gateway
| Service | Ingress / Gateway API | |
|---|---|---|
| لایه | عمدتاً L4 (TCP/UDP) | L7 HTTP(S) |
| host/path | خیر (جز appProtocol hint) | بله |
| TLS termination | معمولاً در LB/Ingress | رایج |
| type | ClusterIP/NodePort/LB/… | شیء جدا |
الگوی رایج production HTTP:
Internet → LoadBalancer یا NodePort روی Ingress Controller
→ ClusterIP سرویسهای اپ
→ Podsمقاله مرتبط لبه: Contour.
انتخاب type — درخت تصمیم
فقط داخل cluster؟
├─ نیاز به VIP و LB؟ → ClusterIP
└─ نیاز به DNS مستقیم به هر Pod؟ → Headless (clusterIP: None)
از بیرون cluster؟
├─ HTTP(S) با host/path/TLS؟ → Ingress/Gateway جلوی ClusterIP
├─ cloud با CCM؟ → LoadBalancer (یا Ingress + LB یکبار)
├─ bare metal / lab؟ → NodePort یا MetalLB بهعنوان LoadBalancer
└─ فقط alias به سرویس خارجی؟ → ExternalNameنمونهٔ کاملتر
apiVersion: v1
kind: Service
metadata:
name: payment-api
namespace: production
labels:
app.kubernetes.io/name: payment
annotations:
# مثال وابسته به cloud — مقدار واقعی از docs provider
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
spec:
type: LoadBalancer
externalTrafficPolicy: Local
selector:
app.kubernetes.io/name: payment
app.kubernetes.io/component: api
ports:
- name: http
protocol: TCP
port: 443
targetPort: http
sessionAffinity: Noneدیباگ روزمره
kubectl get svc,endpoints,endpointslice -n production
kubectl describe svc payment-api -n production
# از یک Pod داخل cluster
curl -v http://payment-api.production.svc.cluster.local
# آیا selector پاد Ready دارد؟
kubectl get pods -l app.kubernetes.io/name=payment -n production| علامت | علت محتمل |
|---|---|
| Endpoints خالی | selector غلط؛ پاد NotReady؛ namespace اشتباه |
| Connection refused | targetPort غلط |
| LB pending | نبود CCM / MetalLB |
| NodePort timeout | فایروال نود؛ policy Local بدون Pod محلی |
| سرویس هست ولی DNS نه | CoreDNS؛ نام/ns غلط |
ارتباط با metadata و بقیهٔ مقالات
Pod.metadata.labels ←── selector ── Service.spec
Service.metadata.name/ns → DNS
Service.spec.type → نحوهٔ expose
readiness (در Pod spec) → عضویت در EndpointSlice- metadata — labels و قوانین نام
- spec — PodSpec و readiness
- apiVersion —
v1برای Service
Best practices
- پیشفرض داخلی: ClusterIP؛ لبه HTTP را با Ingress جدا کنید
- selector را با
app.kubernetes.io/*پایدار نگه دارید targetPortنامدار برای انعطاف نسخه- readinessProbe را جدی بگیرید — وگرنه ترافیک به پاد سرد میرود
- برای client IP واقعی روی LB:
externalTrafficPolicy: Localرا بفهمید و تست کنید - ExternalName برای رمز/اتصال DB کافی نیست — Secret جدا لازم است
- Headless را فقط وقتی per-pod identity لازم است استفاده کنید
- از Endpoints قدیمی در ابزار جدید پرهیز کنید؛ EndpointSlice
- در GitOps، type و annotationهای cloud را صریح و محیطی کنید
- قبل از production،
kubectl describe svcو تعداد endpoints را در چکلیست بگذارید
جمعبندی
| مفهوم | یک جمله |
|---|---|
| Service | دسترسی پایدار شبکه به مجموعه endpointها |
| ClusterIP | VIP داخلی — پیشفرض |
| NodePort | پورت ثابت روی هر نود |
| LoadBalancer | LB خارجی (+ معمولاً NodePort) |
| ExternalName | CNAME بدون proxy |
| Headless | بدون VIP؛ DNS به Podها |
| EndpointSlice | فهرست واقعی backendهای Ready |
| selector | پل metadata labels پاد ↔ ترافیک |
Service مشکل «Pod میمیرد، IP عوض میشود» را با یک قرارداد پایدار حل میکند. انتخاب type یعنی انتخاب کجا و چطور آن قرارداد دیده شود — از فقط-داخل-cluster تا لبههای ابری و aliasهای خارجی.
قدم بعدی
- یک Deployment + ClusterIP بسازید و از Pod دیگر
curlبزنید - عمداً selector را غلط کنید و Endpoints خالی را ببینید
- همان سرویس را NodePort کنید و از IP نود تست کنید
- یک Headless برای StatefulSet نمونه بسازید و DNS
pod-0.svcرا resolve کنید - برای HTTP لبه، Ingress جلوی ClusterIP بگذارید — نه لزوماً LoadBalancer جدا برای هر اپ
منابع
- Service — Kubernetes
- Service API reference
- EndpointSlices
- DNS for Services and Pods
- metadata (مقاله P30Light)
- spec (مقاله P30Light)
- CoreDNS (مقاله P30Light)
- Cilium (مقاله P30Light)
منتشر شده در P30Light — بخش زیرساخت و سرور.