Blog
Kubernetes Services: exposing your Deployment to traffic
A Deployment keeps your Pods running, but nothing can reach them yet. Services are how you expose your app — inside the cluster or to the outside world.
Article info
In the last post we got a Deployment running with three replicas. The Pods are up, they’re healthy — but nothing can actually talk to them. No traffic reaches them from other services, and nothing reaches them from outside the cluster either.
That’s where Services come in.
What a Service does
A Service gives your Pods a stable network address. Pods come and go — they get restarted, replaced, rescheduled — and their IP addresses change every time. A Service sits in front of them and keeps a consistent endpoint regardless of what’s happening underneath.
Think of it as a load balancer that always knows which Pods are healthy and routes traffic to them.
The basic structure
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80 The key part is selector — it matches the labels on your Pods. The Service automatically finds all Pods with app: nginx and routes traffic to them. When a Pod goes down and a new one comes up with the same label, the Service picks it up automatically.
port is what the Service exposes. targetPort is the port on the Pod itself. They’re often the same, but don’t have to be.
Service types
This is where it gets useful. Kubernetes has a few Service types depending on who needs to reach your app.
ClusterIP (default)
Only accessible from inside the cluster. Other services and Pods can reach it, but nothing outside can.
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: ClusterIP
selector:
app: nginx
ports:
- port: 80
targetPort: 80 This is the default if you don’t specify a type. Good for internal communication between services.
NodePort
Exposes the Service on a port on each Node’s IP. Accessible from outside the cluster if you know the Node IP.
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: NodePort
selector:
app: nginx
ports:
- port: 80
targetPort: 80
nodePort: 30080 NodePort range is 30000–32767. Useful for development and testing, but not great for production — you’re exposing a port on every node.
LoadBalancer
Provisions an external load balancer from your cloud provider (AWS, GCP, Azure). This is the standard way to expose an app to the internet in production.
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- port: 80
targetPort: 80 The cloud provider assigns an external IP. Takes a minute to provision. Check the status with:
kubectl get service nginx-service When EXTERNAL-IP shows an address instead of <pending>, it’s ready.
Applying and checking
# Apply the Service
kubectl apply -f service.yaml
# List all services
kubectl get services
# Get details about a specific service
kubectl describe service nginx-service The describe output shows you the endpoints — the actual Pod IPs the Service is routing to. If endpoints are empty, check that your selector labels match what’s on your Pods.
Putting it together
Here’s a complete setup: a Deployment and a Service for the same app.
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:1.27
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: ClusterIP
selector:
app: nginx
ports:
- port: 80
targetPort: 80 Notice the --- separator — you can put multiple resources in a single file and apply them together with one kubectl apply -f.
Why this matters
Without a Service, your Deployment is isolated. With one, it becomes reachable — either by other services inside the cluster, or by the outside world. Most real apps need both: a ClusterIP Service for internal communication and a LoadBalancer or Ingress for external traffic.
Next up: how to manage configuration and sensitive data in Kubernetes using ConfigMaps and Secrets.