Learning objectives
By the end of this module, you should be able to:
- Explain why Pod IPs should not be treated as stable service addresses.
- Create a ClusterIP Service for a Deployment.
- Resolve and call a Service from another Pod.
Pod IPs are ephemeral identities
Pods can be recreated with different IP addresses. Clients therefore need a stable abstraction that selects healthy matching backends rather than hard-coding individual Pod addresses.
Services provide stable discovery
A ClusterIP Service gets a virtual service address and DNS name within the cluster. Its selector identifies backend Pods; EndpointSlice objects represent the discovered endpoints.
DNS is namespace-aware
A Service named web in namespace gnu-k8s-fundamentals is reachable as web from the same namespace and through a fully qualified service DNS name from elsewhere, subject to network policy and DNS health.
Worked examples
See the idea in practice.
Expose a Deployment internally
kubectl -n gnu-k8s-fundamentals expose deployment web --name=web-svc --port=80 --target-port=80
kubectl -n gnu-k8s-fundamentals get service web-svc
kubectl -n gnu-k8s-fundamentals get endpointslices -l kubernetes.io/service-name=web-svc
- The Service remains stable while Pods can be replaced.
- EndpointSlices show the selected backend addresses.
Hands-on lab
Lab — Reach a Service by DNS
Goal: Expose a replicated web Deployment and call it from a temporary client Pod.
Before you start
- kubectl is installed and can reach the lab cluster.
- Use the dedicated gnu-k8s-fundamentals namespace unless a step explicitly says otherwise.
STEP 1Create backend replicas
kubectl -n gnu-k8s-fundamentals create deployment svc-web --image=nginx:alpine
kubectl -n gnu-k8s-fundamentals scale deployment svc-web --replicas=2
kubectl -n gnu-k8s-fundamentals rollout status deployment/svc-web --timeout=120s
STEP 2Create a ClusterIP Service
kubectl -n gnu-k8s-fundamentals expose deployment svc-web --name=svc-web --port=80 --target-port=80
STEP 3Inspect Service and endpoints
kubectl -n gnu-k8s-fundamentals get svc svc-web
kubectl -n gnu-k8s-fundamentals get endpointslices -l kubernetes.io/service-name=svc-web
STEP 4Call the Service through DNS
kubectl -n gnu-k8s-fundamentals run net-client --rm -i --restart=Never --image=busybox:1.36 -- wget -qO- http://svc-web
STEP 5Clean up
kubectl -n gnu-k8s-fundamentals delete service svc-web
kubectl -n gnu-k8s-fundamentals delete deployment svc-web
Verify
- The Service has a ClusterIP.
- EndpointSlices contain backend addresses.
- The client resolves svc-web and receives nginx content.
Expected outcome
- The request succeeds without using a Pod IP directly.
If it fails
- If endpoints are empty, compare Service selector with Pod labels.
- If DNS fails, test the fully qualified name and inspect cluster DNS Pods.
Real-world connectionServices decouple clients from Pod churn and are the normal in-cluster discovery mechanism for replicated applications.
Avoid these traps
Common mistakes
- Hard-coding Pod IP addresses in clients.
- Assuming a Service creates Pods.
- Using NodePort by default when only in-cluster access is required.
Knowledge check
Can you explain it without looking back?
Open each answer only after you have tried to answer the question yourself.
1Why is a Service useful when Pods are replaced?
It provides stable discovery and selects current matching backends.
2What usually determines a Service backend set?
Its label selector.
3Where can you inspect discovered Service endpoints?
EndpointSlice resources.