If you’re learning Kubernetes, one concept you’ll encounter almost immediately is the Service.
At first, Kubernetes can feel straightforward:
- Create a Pod.
- Deploy your application.
- Check that the Pod is running.
- Access the application.
But then you run into a problem:
How do you reliably communicate with a Pod if its IP address can change at any time?
This is where Kubernetes Services come in.
In this article, we'll explore why Pods are considered ephemeral, the networking problem this creates, how Kubernetes Services solve it, and the different Service types you should know.
The Problem: Pods Are Ephemeral
A Pod is the smallest deployable unit in Kubernetes. It can contain one or more containers running your application.
For example, you might have a Pod running an NGINX application:
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
You can deploy it with:
kubectl apply -f pod.yaml
Then check the Pod:
kubectl get pods -o wide
You might see something like:
NAME READY STATUS IP NODE
nginx-pod 1/1 Running 10.244.0.10 worker-node
You could technically communicate with the application using:
10.244.0.10
But there's a problem.
What happens if the Pod crashes?
Kubernetes may create a replacement Pod with a completely different IP address:
Old Pod: 10.244.0.10
New Pod: 10.244.0.15
If your application or another service was relying directly on 10.244.0.10, that connection would no longer work.
This is the ephemeral Pod problem.
Pods can:
- Restart
- Be deleted
- Be recreated
- Be rescheduled to another node
- Scale up or down
Their IP addresses can therefore change.
We need something more stable.
A Kubernetes Service provides a stable network endpoint for accessing a set of Pods. Instead of communicating directly with a Pod's IP address, clients communicate with the Service.
The Service then routes the request to one of the matching Pods.
Think of it like this:
Client
|
v
+----------------+
| Kubernetes |
| Service |
+----------------+
/ | \
/ | \
v v v
Pod A Pod B Pod C
The Pods can change, but the Service remains stable.
For example:
Client
|
| Request
v
Service: my-app
|
+----> Pod 1
|
+----> Pod 2
|
+----> Pod 3
If Pod 1 is deleted and Kubernetes creates Pod 4, the Service can automatically route traffic to the available Pods.
That's the real value of a Service.
How Does a Service Know Which Pods to Route Traffic To?
This is where Labels and Selectors become important.
Suppose we have three Pods with the following label:
labels:
app: nginx
Our Service can use a selector:
selector:
app: nginx
Kubernetes then associates the Service with all Pods matching that selector.
For example:
Service
|
| selector: app=nginx
|
+---------- Pod 1
| app=nginx
|
+---------- Pod 2
| app=nginx
|
+---------- Pod 3
app=nginx
If one of those Pods disappears, Kubernetes updates the endpoints associated with the Service.
Creating a Kubernetes Service
Let's create a Deployment first.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
Apply it:
kubectl apply -f deployment.yaml
Then verify:
kubectl get pods
You should see three Pods running.
Now create a Service:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
Apply it:
kubectl apply -f service.yaml
Check the Service:
kubectl get services
You should see something similar to:
NAME TYPE CLUSTER-IP PORT(S)
nginx-service ClusterIP 10.96.100.20 80/TCP
Notice something important:
The Service now has its own stable IP address.
The Pods may change, but the Service's identity remains stable within the cluster.
Understanding port and targetPort
One part of Services that can initially be confusing is the difference between port and targetPort.
Consider:
ports:
- port: 80
targetPort: 80
port
This is the port exposed by the Service.
targetPort
This is the port on the Pod where the application is actually listening.
For example:
Client
|
| Service port 80
v
+----------------+
| Service |
| :80 |
+----------------+
|
| targetPort 80
v
+----------------+
| Pod |
| :80 |
+----------------+
They don't necessarily have to be the same.
You could have:
ports:
- port: 8080
targetPort: 80
In this case:
Service: 8080
Pod: 80
The Different Kubernetes Service Types
Kubernetes provides several Service types for different networking requirements.
The four you'll encounter most often are:
- ClusterIP
- NodePort
- LoadBalancer
- ExternalName
Let's look at each one.
1. ClusterIP
ClusterIP is the default Service type.
It exposes the application internally within the Kubernetes cluster.
spec:
type: ClusterIP
You can also omit the type because ClusterIP is the default:
spec:
selector:
app: nginx
This is useful when applications inside the cluster need to communicate with each other.
For example:
Frontend
|
v
Backend Service
|
+----> Backend Pod
+----> Backend Pod
+----> Backend Pod
The frontend doesn't need to know the individual IP addresses of the backend Pods.
It can communicate with the Service instead.
2. NodePort
A NodePort exposes the application through a port on each Kubernetes node.
Example:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: NodePort
selector:
app: nginx
ports:
- port: 80
targetPort: 80
nodePort: 30080
The application can then be accessed through:
<NodeIP>:30080
NodePort is particularly useful for learning Kubernetes and in some local development environments.
However, in production cloud environments, you'll often use a LoadBalancer or an Ingress/Gateway-based architecture instead.
3. LoadBalancer
A LoadBalancer Service is commonly used when you want to expose an application externally through a cloud provider's load-balancing infrastructure.
Example:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- port: 80
targetPort: 80
On supported cloud platforms, Kubernetes can request a load balancer from the cloud provider.
Conceptually:
Internet
|
v
+-------------------+
| Cloud Load |
| Balancer |
+-------------------+
/ | \
v v v
Pod A Pod B Pod C
The exact implementation depends on your Kubernetes environment and cloud provider.
4. ExternalName
ExternalName is different from the other Service types.
Instead of routing traffic to Pods, it maps a Kubernetes Service name to an external DNS name.
For example:
apiVersion: v1
kind: Service
metadata:
name: external-database
spec:
type: ExternalName
externalName: database.example.com
Applications inside the cluster can reference:
external-database
while Kubernetes resolves it to:
database.example.com
This can be useful when applications need to interact with external services.
Service Discovery in Kubernetes
One of the biggest benefits of Services is service discovery.
Kubernetes provides DNS-based service discovery through its cluster DNS system.
Instead of using an IP address like:
10.96.100.20
an application can communicate with:
nginx-service
or, depending on the namespace:
nginx-service.default.svc.cluster.local
This is extremely useful in microservices architectures.
For example:
Frontend
|
| http://user-service
v
User Service
|
| http://database-service
v
Database
Each component can communicate using stable Service names instead of hardcoded Pod IP addresses.
What Happens When a Pod Dies?
This is where the Service really proves its value.
Suppose we have:
nginx-service
|
+---- Pod A
+---- Pod B
+---- Pod C
Now Pod B crashes.
Kubernetes replaces it:
nginx-service
|
+---- Pod A
+---- Pod C
+---- Pod D
The client doesn't need to know that Pod B disappeared.
It continues communicating with:
nginx-service
The Service handles the stable networking endpoint while Kubernetes manages the underlying Pods.
A Simple Mental Model
If you're new to Kubernetes, remember this:
Pods run your application. Services provide a stable way to reach those Pods.
Or even simpler:
Pods = Where the application runs
Service = How the application is reached
This distinction becomes especially important when working with Deployments and microservices.
A Deployment manages the lifecycle and scaling of Pods, while a Service provides stable networking to those Pods.
Try It Yourself
The best way to understand Kubernetes networking is to experiment with it.
Try this simple exercise:
1. Create a Deployment
kubectl apply -f deployment.yaml
2. Create a Service
kubectl apply -f service.yaml
3. Inspect the Service
kubectl get svc
4. Check the Service endpoints
kubectl get endpoints
Depending on your Kubernetes version, you can also inspect EndpointSlices:
kubectl get endpointslices
5. Delete a Pod
kubectl delete pod <pod-name>
6. Watch Kubernetes recreate it
kubectl get pods -w
Then check the Service again.
The Pod IP may have changed, but your application can still be reached through the Service.
Final Thoughts
Kubernetes Services solve one of the fundamental networking challenges created by ephemeral Pods.
Instead of relying on individual Pod IP addresses, Services provide a stable endpoint and use selectors to route traffic to the appropriate Pods.
The four Service types are worth understanding:
| Service Type | Primary Use |
|---|---|
| ClusterIP | Internal cluster communication |
| NodePort | Expose an application through a node port |
| LoadBalancer | External access through a cloud load balancer |
| ExternalName | Map a Service to an external DNS name |
Don't just memorize these definitions.
Build something. Break it. Delete Pods. Scale your Deployment. Change Service types. Inspect the endpoints.
That's when Kubernetes networking starts to make sense.
If you're a junior DevOps or Cloud Engineer learning Kubernetes, hands-on experimentation will take you much further than memorizing definitions for an exam.
Keep building. Keep breaking things. And most importantly, keep learning in public.
Top comments (0)