Services
Kubernetes Services provide a stable network endpoint for accessing pods, even as pods are created, deleted, or moved between nodes. Think of a Service as a phone number that stays the same, while the actual phones (pods) behind it can change. Services solve the fundamental problem that pod IP addresses are temporary—when a pod restarts or is rescheduled, it gets a new IP address, but your Service IP and DNS name remain constant.
The Problem Services Solve
Pods in Kubernetes are ephemeral. They can be created, deleted, rescheduled to different nodes, or scaled up and down. Each pod gets its own IP address, but that IP address is temporary:
If your application tried to connect directly to pod IPs, it would break every time pods restart or scale. Services provide a stable abstraction layer:
How Services Work
A Service selects pods using labels and creates a stable IP address and DNS name. The Service continuously watches for pods matching its selector and updates its internal routing table (Endpoints) as pods come and go.
Service Types
Kubernetes provides four types of Services, each suited for different access patterns:
ClusterIP (Default)
The default Service type. Provides a stable IP address accessible only within the cluster. Used for internal service-to-service communication.
NodePort
Exposes the Service on each node’s IP at a static port. External clients can access the Service using <NodeIP>:<NodePort>. Useful for development or bare-metal clusters.
LoadBalancer
Automatically provisions an external load balancer (cloud provider specific). Provides the most straightforward way to expose Services externally in cloud environments.
Headless (clusterIP: None)
A Service without a cluster IP. Used when you need direct pod access or custom service discovery. Returns individual pod IPs via DNS instead of a single Service IP.
Service Discovery
Services are automatically discoverable via DNS. Kubernetes creates DNS records for Services that allow pods to find Services by name:
- Fully Qualified Domain Name (FQDN):
<service-name>.<namespace>.svc.cluster.local - Short name:
<service-name>(within the same namespace) - Cross-namespace:
<service-name>.<namespace>
Basic Service Example
Here’s a simple Service that routes traffic to pods labeled app: nginx:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: default
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 8080
protocol: TCP
type: ClusterIP
Key fields:
selector: Labels that identify which pods this Service targetsports: Port mapping (Service port → pod port)type: Service type (ClusterIP is default)
The Service will automatically find all pods with app: nginx labels and route traffic to them.
Service Ports
Services can expose multiple ports and map them to different pod ports:
apiVersion: v1
kind: Service
metadata:
name: multi-port-service
spec:
selector:
app: my-app
ports:
- name: http
port: 80
targetPort: 8080
protocol: TCP
- name: https
port: 443
targetPort: 8443
protocol: TCP
- name: metrics
port: 9090
targetPort: 9090
protocol: TCP
Service Lifecycle
When to Use Services
Use Services when you need:
✅ Stable endpoints - Access to pods that may restart or move
✅ Load balancing - Distribute traffic across multiple pod instances
✅ Service discovery - Find services by DNS name instead of IP addresses
✅ Abstraction - Decouple client applications from pod details
✅ Internal communication - Connect services within the cluster
✅ External access - Expose applications outside the cluster (NodePort/LoadBalancer)
Service vs Direct Pod Access
Using a Service (recommended):
- Stable IP and DNS name
- Automatic load balancing
- Works across pod restarts
- Handles pod scaling automatically
Direct pod access (not recommended):
- Pod IPs change on restart
- No load balancing
- Breaks when pods are rescheduled
- Requires manual IP management
Best Practices
- Always use Services - Never connect directly to pod IPs in production
- Use descriptive names - Service names should clearly indicate their purpose
- Match selectors carefully - Ensure Service selectors match your pod labels exactly
- Use port names - Name your ports for clarity, especially with multiple ports
- Choose the right type - Use ClusterIP for internal, LoadBalancer for external cloud access
- Monitor Endpoints - Check that Services are finding and routing to the correct pods
- Use namespaces - Organize Services with namespaces for better isolation
- Document port mappings - Clearly document which ports map to which pod ports
Troubleshooting
Service Not Routing Traffic
- Check selector matches pods:
kubectl get pods -l app=my-app - Verify Endpoints exist:
kubectl get endpoints <service-name> - Check Service selector:
kubectl describe service <service-name> - Verify pod labels:
kubectl get pods --show-labels
DNS Not Resolving
- Check CoreDNS is running:
kubectl get pods -n kube-system -l k8s-app=kube-dns - Try FQDN: Use
<service>.<namespace>.svc.cluster.localinstead of short name - Check namespace: Ensure client and Service are in the same namespace (or use FQDN)
Port Connection Issues
- Verify targetPort matches pod container port
- Check pod is listening on the correct port
- Test connectivity:
kubectl run -it --rm debug --image=busybox --restart=Never -- wget -O- <service-name>:<port>
Topics
- ClusterIP - Default internal Service type
- NodePort - Expose Services on node IPs
- LoadBalancer - Cloud provider load balancers
- Headless & Discovery - Direct pod access and custom discovery
- Endpoints & EndpointSlice - How Services track pods
See Also
- Ingress - HTTP/HTTPS routing and load balancing
- Network Policies - Control pod-to-pod network traffic
- DNS & CoreDNS - Service discovery via DNS
- Deployments - Managing pod replicas that Services route to