CKAD — Services Lab

2 minute read

Lab 1: Service Types

# Create a Deployment
kubectl create deployment httpd --image=httpd:2.4 --replicas=3

# Expose as ClusterIP
kubectl expose deployment httpd --port=80 --name=httpd-clusterip
kubectl get svc httpd-clusterip

# Test from inside the cluster
kubectl run test --image=busybox:1.36 --rm -it -- wget -qO- http://httpd-clusterip
# Expected: <html><body><h1>It works!</h1></body></html>

# Expose as NodePort
kubectl expose deployment httpd --port=80 --type=NodePort --name=httpd-nodeport
kubectl get svc httpd-nodeport
# Note the NodePort assigned (e.g., 30080)

Lab 2: Cross-Namespace Service Access

# Create a namespace and deployment
kubectl create namespace backend
kubectl create deployment api --image=nginx:1.27 -n backend
kubectl expose deployment api --port=80 -n backend

# Access from default namespace
kubectl run test --image=busybox:1.36 --rm -it -- wget -qO- http://api.backend
# Expected: nginx welcome page

# Use fully qualified name
kubectl run test --image=busybox:1.36 --rm -it -- wget -qO- http://api.backend.svc.cluster.local
# Expected: nginx welcome page

Practice Questions

Q1: Create a ClusterIP Service named api-svc that routes traffic on port 8080 to Pods labeled app=api on port 3000.

Show Answer ```yaml apiVersion: v1 kind: Service metadata: name: api-svc spec: type: ClusterIP selector: app: api ports: - port: 8080 targetPort: 3000 ``` Or imperatively (if a matching deployment exists): ```bash kubectl expose deployment api --port=8080 --target-port=3000 --name=api-svc ```

Q2: What is the DNS name to reach a Service named db in the production namespace from a Pod in the default namespace?

Show Answer ``` db.production ``` Or the fully qualified form: ``` db.production.svc.cluster.local ``` Both work. The shorter form is sufficient in most cases.

Q3: A Service has no endpoints. What are the possible causes?

Show Answer Common causes for empty endpoints: 1. **Selector mismatch** — The Service selector does not match any Pod labels. Check with: ```bash kubectl describe svc # Check Selector kubectl get pods --show-labels # Check Pod labels ``` 2. **No Pods exist** — The Pods matching the selector have not been created or are not running. 3. **Pods not ready** — Pods that fail readiness probes are removed from endpoints. Check: ```bash kubectl get pods # Look for non-Ready Pods ``` 4. **Wrong namespace** — The Service and Pods are in different namespaces. </details> **Q4: Convert this ClusterIP Service to a NodePort Service on port 30100:** ```yaml apiVersion: v1 kind: Service metadata: name: web spec: selector: app: web ports: - port: 80 targetPort: 80 ```
Show Answer ```yaml apiVersion: v1 kind: Service metadata: name: web spec: type: NodePort selector: app: web ports: - port: 80 targetPort: 80 nodePort: 30100 ``` Or edit it in place: ```bash kubectl patch svc web -p '{"spec":{"type":"NodePort","ports":[{"port":80,"targetPort":80,"nodePort":30100}]}}' ```
**Q5: What is a headless Service and when would you use it?**
Show Answer A headless Service has `clusterIP: None`. Instead of getting a single virtual IP, DNS returns the IP addresses of all matching Pods directly. ```yaml spec: clusterIP: None selector: app: db ``` Use cases: - **StatefulSets** — each Pod gets a stable DNS name like `pod-0.headless-svc.namespace.svc.cluster.local` - **Client-side load balancing** — the client decides which Pod to connect to - **Service discovery** — applications that need to know all backend IPs (e.g., database clusters)
--- [← Previous: CRDs & Operators](/k8s/ckad/crds-operators/){: .btn .btn--inverse} [Next: Ingress & Network Policies →](/k8s/ckad/ingress/){: .btn .btn--primary}

Updated: