Introduction
In Kubernetes, pods are temporary. They can start, stop, or move at any time, leading to changing IP addresses. This makes direct communication between pods unreliable. Services solve this problem by providing a stable IP address and DNS name for a group of pods, ensuring seamless communication. This article explains how Services work, their types, and how to troubleshoot common issues.
Key Concepts Explained with Examples
1. Service Types
Services come in different types to suit various needs:
ClusterIP (Default)
What it does: Exposes pods internally within the cluster.
Example: A frontend app needs to connect to a backend database.
apiVersion: v1 kind: Service metadata: name: backend-db spec: selector: app: mysql ports: - port: 3306 targetPort: 3306
The frontend pods use
backend-db:3306
to access the database, even if the database pods restart or scale.
NodePort
What it does: Exposes a service on a static port on each node’s IP.
Example: Exposing a web app to external users via
<NodeIP>:30080
.spec: type: NodePort ports: - port: 80 nodePort: 30080
LoadBalancer
What it does: Integrates with cloud providers (e.g., AWS, GCP) to assign a public IP.
Example: Hosting a public-facing website. Traffic from
203.0.113.10:80
is routed to pods.
ExternalName
What it does: Maps a service to an external DNS name (e.g., a legacy database outside Kubernetes).
spec: type: ExternalName externalName: my-legacy-database.example.com
2. Service Discovery
Pods can discover Services via:
Environment Variables: Automatically injected into pods.
# Inside a pod: echo $BACKEND_DB_SERVICE_HOST # Output: 10.96.128.15
DNS: Services get a DNS name like
<service-name>.<namespace>.svc.cluster.local
.# A pod connects to the backend using: curl http://backend-db.default.svc.cluster.local
3. Ingress: Advanced HTTP Routing
Ingress manages external access using rules (e.g., routing based on URL paths).
Example: Routing
/api
to a backend and/app
to a frontend.apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-ingress spec: rules: - host: myapp.example.com http: paths: - path: /api backend: service: name: backend port: 80 - path: /app backend: service: name: frontend port: 80
4. Readiness Probes
Readiness probes ensure pods only receive traffic when they’re ready.
Example: A pod running a Node.js app must finish initializing before accepting requests.
readinessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 10 # Wait 10s after startup
5. Headless Services for Direct Pod Access
Useful for stateful apps (e.g., databases) where direct pod IP access is needed.
spec:
clusterIP: None # Makes it "headless"
selector:
app: redis
DNS Lookup: Returns all pod IPs.
nslookup redis-headless.default.svc.cluster.local # Output: 10.244.1.10, 10.244.2.20
Troubleshooting Checklist with Examples
Service IP Not Responding?
✅ Check Endpoints:
kubectl get endpoints my-service # Ensure pods are listed.
❌ Don’t Ping Service IP: It’s a virtual IP—pinging won’t work.
Pod Not Part of a Service?
✅ Verify Labels:
kubectl get pods -l app=my-label
Can’t Connect Externally?
✅ Check Firewall Rules (NodePort/LoadBalancer):
gcloud compute firewall-rules create allow-nodeport --allow=tcp:30080
Readiness Probe Failing?
✅ Inspect Logs:
kubectl logs my-pod # Check why /health endpoint fails.
DNS Issues?
✅ Test DNS Resolution:
kubectl exec -it dnsutils -- nslookup my-service
Conclusion
Kubernetes Services act as a reliable bridge between pods and clients, ensuring stable communication despite pod changes. By using ClusterIP, NodePort, LoadBalancer, or Ingress, you can expose apps internally or externally. Readiness probes and headless services add flexibility for complex scenarios. Always validate configurations with kubectl get endpoints
and DNS checks to avoid common pitfalls. With these tools, managing microservices in Kubernetes becomes straightforward and robust.