- Pod IPs are ephemeral: stable virtual IP + DNS from Service
- Traffic:
Client -> Service (port) -> Pod (targetPort -> containerPort) - Selector must match Pod labels exactly
Service Type Hierarchy
ClusterIP -> NodePort -> LoadBalancer
\
ExternalName (DNS-only)
1. ClusterIP (default)
- Internal virtual IP; only accessible inside cluster
- DNS same NS:
backend; cross NS: backend.default
apiVersion: v1
kind: Service
metadata:
name: backend
spec:
type: ClusterIP
selector:
app: backend
ports:
- port: 80
targetPort: 8080
Session affinity (sticky sessions)
spec:
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10800
None (default): round-robin; ClientIP: same source IP → same Pod
2. NodePort
- Port range: 30000-32767; auto-assigned if not specified
Client -> NodeIP:NodePort -> Service -> Pod
spec:
type: NodePort
ports:
- port: 80
targetPort: 8080
nodePort: 30007
3. LoadBalancer
- Provisions external cloud load balancer
EXTERNAL-IP may be <pending> without cloud provider- Internally still uses NodePort
4. ExternalName
- Pure DNS alias; no proxying, no IP, no endpoints, no selector
spec:
type: ExternalName
externalName: db.example.com
my-db.default.svc.cluster.local -> db.example.com
5. Headless Service
clusterIP: None; DNS returns Pod IPs directly
spec:
clusterIP: None
selector:
app: db
ports:
- port: 5432
6. Selector-less Service (manual endpoints)
spec:
ports:
- port: 80
targetPort: 9999
selector: null
---
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: ext-service
labels:
kubernetes.io/service-name: ext-service
addressType: IPv4
ports:
- port: 9999
endpoints:
- addresses:
- 192.168.1.10
Traffic Mapping
DNS (CoreDNS)
kubectl exec <pod> -- nslookup webapp-svc
kubectl exec <pod> -- wget -qO- http://webapp-svc:80
Commands
Debug Checklist
- Selector matches Pod labels
kubectl get endpoints not emptytargetPort == containerPort- Pod is Ready
- Same namespace
Exam gotchas
- Empty endpoints = no traffic; always verify
kubectl get endpoints <svc-name> - ClusterIP is default
- LoadBalancer still uses NodePort internally
- ExternalName: no selector, no ClusterIP, no proxying
sessionAffinity: ClientIP for sticky sessions