Kubernetes Services Exposing Your Application

Pods have IP addresses, but those addresses change every time a Pod restarts or gets replaced. A Kubernetes Service gives your application a stable address that stays the same no matter how many Pods come and go behind it. Services also load-balance traffic across all matching Pods automatically.

The Problem Services Solve

Imagine you send letters to a business. If the business moves its office every week, you cannot use the old address. Instead, you use the company's permanent PO box address — letters always reach the right place regardless of where the actual office is located that week. A Kubernetes Service is that PO box.

Client sends request to Service IP: 10.96.0.15:80
          ↓
Service load-balances to one of:
   Pod A: 10.1.0.5:8080  (running)
   Pod B: 10.1.0.6:8080  (running)
   Pod C: 10.1.0.7:8080  (just restarted, new IP)

How Services Find Their Pods

Just like ReplicaSets, Services use label selectors. The Service watches all Pods in the cluster and forwards traffic to any Pod that matches its selector. When a Pod is added, removed, or replaced, the Service automatically updates its list without any configuration change.

The Four Service Types

ClusterIP (Default)

ClusterIP gives your Service an IP address that is only reachable inside the cluster. No external traffic can reach it. Use this for internal communication between microservices — for example, a frontend service reaching a backend API.

External Internet → ✗ Cannot reach ClusterIP
Pod inside cluster → ✓ Can reach ClusterIP

NodePort

NodePort opens a port (30000–32767) on every worker node. Traffic arriving at any node's IP on that port reaches the Service. Use this for development or when you need direct node-level access. It is not recommended for production because it exposes a port on every node and you must manage firewall rules yourself.

External request → Node IP : 31000 → Service → Pod

LoadBalancer

LoadBalancer provisions a cloud load balancer (from AWS, GCP, Azure, etc.) that gets a public IP address. Traffic from the internet hits the load balancer, which forwards it to the Service, which distributes it to Pods. This is the standard way to expose public-facing applications on managed Kubernetes clusters.

Internet → Cloud Load Balancer (public IP) → Service (ClusterIP) → Pods

ExternalName

ExternalName maps the Service to a DNS name outside the cluster. Instead of routing to Pods, the Service returns a CNAME record. Use this to give a Kubernetes-friendly name to an external database or API that lives outside your cluster.

Pod calls: my-db.default.svc.cluster.local
Service returns: db.example.com (external hostname)

Writing a Service YAML

apiVersion: v1
kind: Service
metadata:
  name: frontend-service
spec:
  selector:
    app: frontend
  type: ClusterIP
  ports:
  - protocol: TCP
    port: 80        # Port the Service listens on
    targetPort: 8080  # Port on the Pod

The port is what clients use to reach the Service. The targetPort is what the container inside the Pod actually listens on. These can be the same number, but separating them gives you flexibility.

A LoadBalancer Service Example

apiVersion: v1
kind: Service
metadata:
  name: web-public
spec:
  selector:
    app: web
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 8080
kubectl apply -f service.yaml
kubectl get service web-public

Output:

NAME          TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)
web-public    LoadBalancer   10.96.20.5      34.120.45.100    80:31240/TCP

The EXTERNAL-IP column shows the public IP. Open it in a browser and your app appears.

Service Discovery with DNS

Kubernetes runs an internal DNS server. Every Service automatically gets a DNS name:

<service-name>.<namespace>.svc.cluster.local

A Pod in the same namespace can reach the Service using just the Service name:

# From inside a Pod:
curl http://frontend-service
curl http://frontend-service.production.svc.cluster.local

This DNS-based discovery is how microservices find each other in Kubernetes. No hard-coded IP addresses, no external service registry needed.

Endpoints: What Is Behind the Service

Kubernetes creates an Endpoints object alongside each Service. It lists the actual IPs of all Pods that match the selector. You can inspect it to see exactly which Pods a Service is currently routing to:

kubectl get endpoints frontend-service

Output:

NAME               ENDPOINTS
frontend-service   10.1.0.5:8080,10.1.0.6:8080,10.1.0.7:8080

When to Use Which Service Type

ScenarioService Type
Internal microservice communicationClusterIP
Quick testing, development accessNodePort
Public-facing application on cloudLoadBalancer
Give internal name to external serviceExternalName

Key Points

  • Services give Pods a stable, permanent address even as individual Pod IPs change.
  • Services use label selectors to find and load-balance traffic across matching Pods.
  • ClusterIP is for internal traffic, NodePort for development, LoadBalancer for public access.
  • Every Service gets an automatic DNS name for easy discovery between microservices.
  • Inspect the Endpoints object to see which Pod IPs are behind a Service at any moment.

Leave a Comment