Kubernetes Services provide a stable network endpoint to access pods. Understanding the different service types is crucial for exposing your applications correctly within and outside your cluster.
What are Kubernetes Services?
Services in Kubernetes are an abstraction layer that provides a stable IP address and DNS name for a set of pods. They enable:
- Service discovery: Pods can find each other using service names
- Load balancing: Traffic is distributed across multiple pod instances
- Decoupling: Pod IPs can change, but service IPs remain stable
Service Types Overview
Kubernetes supports four main service types:
- ClusterIP - Default type, accessible only within the cluster
- NodePort - Exposes service on each node's IP at a static port
- LoadBalancer - Creates an external load balancer (cloud provider required)
- ExternalName - Maps service to an external DNS name
ClusterIP Service
ClusterIP is the default service type. It exposes the service on an internal IP address within the cluster, making it accessible only from within the cluster.
Use Cases
- Internal microservice communication
- Frontend to backend communication
- Service-to-service communication within the cluster
Configuration
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: ClusterIP # Optional, this is the default
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
Accessing ClusterIP Services
From within the cluster:
# Using service name (DNS)
curl http://my-service
# Using service IP
curl http://10.96.0.1
From pods:
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: curl
image: curlimages/curl
command: ["sleep", "3600"]
kubectl exec -it test-pod -- curl http://my-service
NodePort Service
NodePort exposes the service on each node's IP at a static port (the NodePort). This makes the service accessible from outside the cluster by accessing <NodeIP>:<NodePort>.
Use Cases
- Development and testing environments
- On-premises clusters without cloud load balancers
- Quick external access for debugging
Configuration
apiVersion: v1
kind: Service
metadata:
name: my-nodeport-service
spec:
type: NodePort
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
nodePort: 30080 # Optional, Kubernetes will assign if not specified (30000-32767)
Accessing NodePort Services
# Get node IP
kubectl get nodes -o wide
# Access from outside cluster
curl http://<NodeIP>:30080
# From any node
curl http://localhost:30080
Port Range
NodePort uses the range 30000-32767 by default. You can specify a port or let Kubernetes assign one:
# Check assigned NodePort
kubectl get svc my-nodeport-service
LoadBalancer Service
LoadBalancer is an extension of NodePort. It creates an external load balancer (when supported by cloud providers) that routes traffic to the service.
Use Cases
- Production workloads requiring external access
- High availability applications
- Cloud-native deployments
Configuration
apiVersion: v1
kind: Service
metadata:
name: my-loadbalancer-service
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
Cloud Provider Integration
AWS (EKS):
metadata:
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
GCP (GKE):
metadata:
annotations:
cloud.google.com/load-balancer-type: "Internal"
Azure (AKS):
metadata:
annotations:
service.beta.kubernetes.io/azure-load-balancer-internal: "true"
Accessing LoadBalancer Services
# Get external IP
kubectl get svc my-loadbalancer-service
# Access via external IP
curl http://<EXTERNAL-IP>
ExternalName Service
ExternalName maps a service to an external DNS name. It returns a CNAME record with the external name.
Use Cases
- Migrating to Kubernetes gradually
- Accessing external services with service abstraction
- Creating aliases for external resources
Configuration
apiVersion: v1
kind: Service
metadata:
name: external-database
spec:
type: ExternalName
externalName: database.example.com
ports:
- port: 5432
Accessing ExternalName Services
# From within cluster, access as internal service
kubectl run -it --rm test-pod --image=busybox --restart=Never -- nslookup external-database
Service Comparison
| Feature | ClusterIP | NodePort | LoadBalancer | ExternalName |
|---|---|---|---|---|
| Internal Access | ✅ | ✅ | ✅ | ✅ |
| External Access | ❌ | ✅ | ✅ | ❌ |
| Cloud Provider | Not needed | Not needed | Required | Not needed |
| IP Assignment | Cluster IP | Node IP | External IP | External DNS |
| Port Range | Any | 30000-32767 | Any | Any |
| Use Case | Internal services | Dev/Test | Production | External services |
Service Selectors
All service types (except ExternalName) use selectors to determine which pods to route traffic to:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: my-app
tier: frontend
ports:
- port: 80
targetPort: 8080
Pods matching these labels will receive traffic.
Headless Services
A headless service is created by setting clusterIP: None. It's useful for:
- StatefulSets
- Service discovery when you need pod IPs directly
- Custom load balancing
apiVersion: v1
kind: Service
metadata:
name: headless-service
spec:
clusterIP: None
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
Multiple Ports
Services can expose multiple ports:
apiVersion: v1
kind: Service
metadata:
name: multi-port-service
spec:
selector:
app: my-app
ports:
- name: http
port: 80
targetPort: 8080
- name: https
port: 443
targetPort: 8443
- name: metrics
port: 9090
targetPort: 9090
Service Discovery
DNS-Based Discovery
Services are automatically assigned DNS names:
- Format:
<service-name>.<namespace>.svc.cluster.local - Short form:
<service-name>.<namespace>or<service-name>(same namespace)
# From same namespace
curl http://my-service
# From different namespace
curl http://my-service.default.svc.cluster.local
Environment Variables
Pods automatically get environment variables for services:
# In pod
MY_SERVICE_SERVICE_HOST=10.96.0.1
MY_SERVICE_SERVICE_PORT=80
Best Practices
1. Use ClusterIP for Internal Communication
# Internal service
apiVersion: v1
kind: Service
metadata:
name: internal-api
spec:
type: ClusterIP # Explicit for clarity
selector:
app: api
ports:
- port: 8080
2. Use LoadBalancer for Production External Access
# Production external service
apiVersion: v1
kind: Service
metadata:
name: public-api
spec:
type: LoadBalancer
selector:
app: api
ports:
- port: 443
targetPort: 8443
3. Label Selectors Correctly
Ensure service selectors match pod labels exactly:
# Check pod labels
kubectl get pods --show-labels
# Verify service selector matches
kubectl describe svc my-service
4. Use Named Ports
Use named ports for clarity and flexibility:
ports:
- name: http
port: 80
targetPort: http-port # References container port name
Common Issues and Solutions
Service Not Routing Traffic
Problem: Service exists but traffic isn't reaching pods.
Solution:
# Check service endpoints
kubectl get endpoints my-service
# Verify selector matches pods
kubectl get pods -l app=my-app
# Check service selector
kubectl describe svc my-service
External IP Pending (LoadBalancer)
Problem: LoadBalancer service shows <pending> for external IP.
Solutions:
- Ensure cloud provider integration is configured
- Check cloud provider load balancer quotas
- Verify firewall rules allow traffic
Port Conflicts
Problem: NodePort conflicts or unavailable.
Solution:
- Specify custom NodePort in valid range (30000-32767)
- Check existing NodePort services
- Use LoadBalancer instead if available
Related Resources
- Understanding Kubernetes Ingress Controllers
- Kubernetes Headless Services Explained
- Kubernetes DNS Service Discovery
- Kubernetes Networking Guide
Conclusion
Understanding Kubernetes service types is fundamental for networking in Kubernetes. Choose the right service type based on your access requirements:
- ClusterIP: Internal cluster communication
- NodePort: Quick external access for development
- LoadBalancer: Production external access with cloud integration
- ExternalName: External service abstraction
Select the appropriate service type based on your use case, security requirements, and infrastructure capabilities.