DEV Community

Cover image for Kubernetes Services: Solving the Ephemeral Pod Networking Problem
saheed
saheed

Posted on

Kubernetes Services: Solving the Ephemeral Pod Networking Problem

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
Enter fullscreen mode Exit fullscreen mode

You can deploy it with:

kubectl apply -f pod.yaml
Enter fullscreen mode Exit fullscreen mode

Then check the Pod:

kubectl get pods -o wide
Enter fullscreen mode Exit fullscreen mode

You might see something like:

NAME        READY   STATUS    IP            NODE
nginx-pod   1/1     Running   10.244.0.10   worker-node
Enter fullscreen mode Exit fullscreen mode

You could technically communicate with the application using:

10.244.0.10
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

The Pods can change, but the Service remains stable.

For example:

Client
   |
   | Request
   v
Service: my-app
   |
   +----> Pod 1
   |
   +----> Pod 2
   |
   +----> Pod 3
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Our Service can use a selector:

selector:
  app: nginx
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Apply it:

kubectl apply -f deployment.yaml
Enter fullscreen mode Exit fullscreen mode

Then verify:

kubectl get pods
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Apply it:

kubectl apply -f service.yaml
Enter fullscreen mode Exit fullscreen mode

Check the Service:

kubectl get services
Enter fullscreen mode Exit fullscreen mode

You should see something similar to:

NAME            TYPE        CLUSTER-IP      PORT(S)
nginx-service   ClusterIP   10.96.100.20    80/TCP
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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        |
+----------------+
Enter fullscreen mode Exit fullscreen mode

They don't necessarily have to be the same.

You could have:

ports:
  - port: 8080
    targetPort: 80
Enter fullscreen mode Exit fullscreen mode

In this case:

Service: 8080
Pod:     80
Enter fullscreen mode Exit fullscreen mode

The Different Kubernetes Service Types

Kubernetes provides several Service types for different networking requirements.

The four you'll encounter most often are:

  1. ClusterIP
  2. NodePort
  3. LoadBalancer
  4. 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
Enter fullscreen mode Exit fullscreen mode

You can also omit the type because ClusterIP is the default:

spec:
  selector:
    app: nginx
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

The application can then be accessed through:

<NodeIP>:30080
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Applications inside the cluster can reference:

external-database
Enter fullscreen mode Exit fullscreen mode

while Kubernetes resolves it to:

database.example.com
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

an application can communicate with:

nginx-service
Enter fullscreen mode Exit fullscreen mode

or, depending on the namespace:

nginx-service.default.svc.cluster.local
Enter fullscreen mode Exit fullscreen mode

This is extremely useful in microservices architectures.

For example:

Frontend
   |
   | http://user-service
   v
User Service
   |
   | http://database-service
   v
Database
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Now Pod B crashes.

Kubernetes replaces it:

nginx-service
      |
      +---- Pod A
      +---- Pod C
      +---- Pod D
Enter fullscreen mode Exit fullscreen mode

The client doesn't need to know that Pod B disappeared.

It continues communicating with:

nginx-service
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

2. Create a Service

kubectl apply -f service.yaml
Enter fullscreen mode Exit fullscreen mode

3. Inspect the Service

kubectl get svc
Enter fullscreen mode Exit fullscreen mode

4. Check the Service endpoints

kubectl get endpoints
Enter fullscreen mode Exit fullscreen mode

Depending on your Kubernetes version, you can also inspect EndpointSlices:

kubectl get endpointslices
Enter fullscreen mode Exit fullscreen mode

5. Delete a Pod

kubectl delete pod <pod-name>
Enter fullscreen mode Exit fullscreen mode

6. Watch Kubernetes recreate it

kubectl get pods -w
Enter fullscreen mode Exit fullscreen mode

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.

Kubernetes #DevOps #CloudEngineering #Containers #LearningInPublic

Top comments (0)