Kubernetes Services – Complete Guide
Services provide stable networking for Pods. This covers all types for CKA.
1. Why Services?
- Pods are ephemeral (IPs change on restart)
- Services provide stable DNS name and IP
- Load balancing across multiple Pods
- Service discovery within cluster
2. Service Types
| Type | Scope | Use Case |
|---|---|---|
ClusterIP | Internal only | Default, pod-to-pod communication |
NodePort | External via node IP | Dev/testing, direct node access |
LoadBalancer | External via cloud LB | Production external traffic |
ExternalName | DNS alias | Access external services |
Headless | No ClusterIP | StatefulSets, direct pod access |
3. ClusterIP (Default)
Internal-only service. Only accessible within cluster.
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: ClusterIP # optional, default
selector:
app: myapp
ports:
- port: 80 # Service port
targetPort: 8080 # Pod portAccess: curl my-service.default.svc.cluster.local:80
4. NodePort
Exposes service on each node's IP at a static port (30000-32767).
apiVersion: v1
kind: Service
metadata:
name: my-nodeport
spec:
type: NodePort
selector:
app: myapp
ports:
- port: 80
targetPort: 8080
nodePort: 30080 # optional, auto-assigned if omittedAccess: curl <node-ip>:30080
Port mapping:
External → NodePort (30080) → Service Port (80) → Pod Port (8080)5. LoadBalancer
Creates external load balancer (cloud providers only).
apiVersion: v1
kind: Service
metadata:
name: my-lb
spec:
type: LoadBalancer
selector:
app: myapp
ports:
- port: 80
targetPort: 8080On-prem: Use MetalLB or stays in Pending state
6. ExternalName
Maps service to external DNS name (no proxying).
apiVersion: v1
kind: Service
metadata:
name: external-db
spec:
type: ExternalName
externalName: db.example.comAccess: curl external-db → resolves to db.example.com
7. Headless Service
No ClusterIP assigned. Returns Pod IPs directly.
apiVersion: v1
kind: Service
metadata:
name: headless-svc
spec:
clusterIP: None # This makes it headless
selector:
app: myapp
ports:
- port: 80Use cases:
- StatefulSets (stable network identity)
- Direct pod-to-pod communication
- Client-side load balancing
DNS returns: All Pod IPs instead of single ClusterIP
8. Service Selectors
Services route to Pods matching the selector labels.
Service:
spec:
selector:
app: web
tier: frontendMatching Pod:
metadata:
labels:
app: web
tier: frontend
version: v1 # Extra labels OKPod must have ALL labels in selector to receive traffic.
9. Ports Explained
ports:
- name: http # Optional, required if multiple ports
port: 80 # Service port (what clients use)
targetPort: 8080 # Pod port (where app listens)
nodePort: 30080 # Node port (NodePort type only)
protocol: TCP # TCP (default) or UDPtargetPort can be name:
# In Service
targetPort: http-port
# In Pod
ports:
- name: http-port
containerPort: 808010. Multi-Port Services
apiVersion: v1
kind: Service
metadata:
name: multi-port
spec:
selector:
app: myapp
ports:
- name: http
port: 80
targetPort: 8080
- name: https
port: 443
targetPort: 8443
- name: metrics
port: 9090
targetPort: 909011. Service Without Selector
Manually control endpoints (external service integration).
Service:
apiVersion: v1
kind: Service
metadata:
name: external-svc
spec:
ports:
- port: 80
# No selector!Endpoints:
apiVersion: v1
kind: Endpoints
metadata:
name: external-svc # Must match service name
subsets:
- addresses:
- ip: 192.168.1.100
- ip: 192.168.1.101
ports:
- port: 8012. DNS Names
| Type | DNS Format |
|---|---|
| Service | <service>.<namespace>.svc.cluster.local |
| Pod (headless) | <pod-name>.<service>.<namespace>.svc.cluster.local |
| Short form | <service> (same namespace) |
| Cross-namespace | <service>.<namespace> |
Examples:
curl my-service # Same namespace
curl my-service.default # Explicit namespace
curl my-service.default.svc.cluster.local # Full FQDN13. Session Affinity
Stick client to same Pod.
spec:
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10800 # 3 hours default14. Service CIDR
Services get IPs from service CIDR (default: 10.96.0.0/12).
Check: kubectl cluster-info dump | grep service-cluster-ip-range
15. Common Commands
# Create service imperatively
kubectl expose deployment nginx --port=80 --target-port=8080 --type=NodePort
# List services
kubectl get svc
# Describe service (shows endpoints)
kubectl describe svc my-service
# Get endpoints
kubectl get endpoints my-service
# Test service from within cluster
kubectl run test --rm -it --image=busybox -- wget -qO- my-service:80
# Get service YAML
kubectl get svc my-service -o yaml16. Imperative Commands
# ClusterIP
kubectl expose deployment nginx --port=80
# NodePort
kubectl expose deployment nginx --port=80 --type=NodePort
# With specific node port
kubectl expose deployment nginx --port=80 --type=NodePort --overrides='{"spec":{"ports":[{"port":80,"nodePort":30080}]}}'
# LoadBalancer
kubectl expose deployment nginx --port=80 --type=LoadBalancer
# From pod
kubectl expose pod nginx --port=80 --name=nginx-svc17. Troubleshooting
Service has no endpoints
kubectl get endpoints <service>Causes:
- Selector doesn't match any pods
- Pods not ready (failing readiness probe)
- Pods in wrong namespace
Can't access service
# Check if service exists
kubectl get svc
# Check endpoints
kubectl describe svc <name>
# Test from inside cluster
kubectl run test --rm -it --image=busybox -- wget -qO- <service>:<port>
# Check pod logs
kubectl logs <pod>18. CKA Exam Tips
- Default type is ClusterIP – don't need to specify
- kubectl expose is fastest for creating services
- NodePort range: 30000-32767
- Headless: set
clusterIP: None - Check endpoints when service doesn't route traffic
- Selectors must match Pod labels exactly
Appendix: Niche / Edge-case Scenarios
Session Affinity (moved from questions)
Scenario: The marketing team needs an internal web application that maintains session state based on the client's IP address.
Notes & Example: Session Affinity (ClientIP) sticks a client to the same pod.
spec:
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10800Use this sparingly in the exam — it's an edge case: prefer stateless apps.
Cross-Namespace DNS Discovery (moved from questions)
Scenario: A secure-vault service runs in a separate namespace (hiddensecrets) and must be reachable from default.
Notes & Example: Use FQDN to access services across namespaces: <service>.<namespace>.svc.cluster.local.
From a pod in default you can curl secure-vault.hiddensecrets.svc.cluster.local:80 to reach the service.
These cases are important conceptually but are niche; focus your practice on selectors, ports, and endpoints for CKA.
NodePort Traffic Policy (moved from questions)
Scenario: Exposing a front-end application externally using a NodePort while preserving the source IP is an advanced traffic-policy case.
Notes & Example: To preserve client source IP you can use externalTrafficPolicy: Local. This is an advanced option — good to know, but rarely required for core CKA tasks.
spec:
type: NodePort
externalTrafficPolicy: Local
ports:
- port: 80
nodePort: 31050Headless Service for StatefulSets (moved from questions)
Scenario: Stateful applications that require stable network identity and direct pod-to-pod DNS resolution.
Notes & Example: A headless Service is created by setting clusterIP: None, which makes DNS return individual Pod A records.
spec:
clusterIP: None
selector:
app: db
ports:
- port: 5432Verify by doing nslookup <service> inside the cluster: you should see multiple A records.
ExternalName Service (moved from questions)
Scenario: Map an in-cluster service name to an external DNS name without proxying traffic.
Notes & Example: An ExternalName Service points to an external DNS name.
apiVersion: v1
kind: Service
metadata:
name: access-google
spec:
type: ExternalName
externalName: google.comTest resolution from a pod to confirm access-google.<namespace>.svc.cluster.local resolves to google.com.