Service and DNS Solutions
SummaryStep-by-step solutions for Exercises 1 and 2: creating...
Step-by-step solutions for Exercises 1 and 2: creating...
Step-by-step solutions for Exercises 1 and 2: creating a ClusterIP Service with DNS resolution verification from a busybox Pod, and deploying NGINX Ingress on Kind with path-based routing to two backend Services.
Service and DNS Solutions
Solution: Exercise 1 — ClusterIP Service with DNS Resolution
This exercise requires creating a Deployment, exposing it via a ClusterIP Service, and verifying DNS resolution and connectivity from another Pod.
Step 1: Create the Deployment
kubectl create deployment echo-server --image=hashicorp/http-echo --replicas=2 -- -text="hello from echo"
Verify the Pods are running:
kubectl get pods -l app=echo-server
Expected output:
NAME READY STATUS RESTARTS AGE
echo-server-7d4f8b5c6-abc12 1/1 Running 0 5s
echo-server-7d4f8b5c6-def34 1/1 Running 0 5s
Both replicas should show 1/1 Running. The hashicorp/http-echo image starts an HTTP server on port 5678 by default, responding with the text specified in the -text argument.
Step 2: Create the Service
kubectl expose deployment echo-server --name=echo-svc --port=80 --target-port=5678
This creates a ClusterIP Service that:
- Listens on port 80
- Forwards traffic to port 5678 on the backing Pods
- Uses the selector
app=echo-server(inherited from the Deployment)
Alternatively, use a declarative manifest:
apiVersion: v1
kind: Service
metadata:
name: echo-svc
spec:
type: ClusterIP
selector:
app: echo-server
ports:
- protocol: TCP
port: 80
targetPort: 5678
Verify the Service:
kubectl get svc echo-svc
Expected output:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
echo-svc ClusterIP 10.96.45.200 <none> 80/TCP 3s
Step 3: Verify Endpoints
kubectl get endpoints echo-svc
Expected output:
NAME ENDPOINTS AGE
echo-svc 10.244.1.3:5678,10.244.2.5:5678 5s
Two endpoints — one for each replica. If this shows <none>, the Service selector does not match the Pod labels.
Step 4: Test DNS Resolution
kubectl run dnstest --image=busybox:1.36 --rm -it --restart=Never -- nslookup echo-svc
Expected output:
Server: 10.96.0.10
Address: 10.96.0.10:53
Name: echo-svc.default.svc.cluster.local
Address: 10.96.45.200
pod "dnstest" deleted
The resolved address matches the Service’s ClusterIP. CoreDNS returned the fully qualified domain name.
Step 5: Test HTTP Connectivity
kubectl run curltest --image=busybox:1.36 --rm -it --restart=Never -- wget -qO- echo-svc
Expected output:
hello from echo
pod "curltest" deleted
The response comes from one of the echo-server Pods via the Service. The short DNS form echo-svc works because the test Pod is in the same namespace.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
Endpoints show <none> | Selector mismatch | Run kubectl get pods --show-labels and compare with kubectl describe svc echo-svc | grep Selector |
| DNS resolution fails | CoreDNS not running | Check kubectl get pods -n kube-system -l k8s-app=kube-dns |
| wget returns “connection refused” | Wrong targetPort | The http-echo image listens on 5678 — verify targetPort is 5678, not 80 |
| Only one endpoint despite 2 replicas | One Pod not ready | Check Pod status: kubectl get pods -l app=echo-server |
Cleanup
kubectl delete deployment echo-server
kubectl delete svc echo-svc
Solution: Exercise 2 — Ingress Routing on Kind
This exercise requires deploying two applications, creating Services for both, and configuring an Ingress resource with path-based routing.
Step 1: Verify the Ingress Controller
Ensure the NGINX Ingress Controller is running:
kubectl get pods -n ingress-nginx -l app.kubernetes.io/component=controller
If no Pods appear, install it:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
kubectl wait --namespace ingress-nginx \
--for=condition=ready pod \
--selector=app.kubernetes.io/component=controller \
--timeout=90s
Step 2: Deploy the Applications
kubectl create deployment api-app --image=hashicorp/http-echo -- -text="API"
kubectl create deployment web-app --image=hashicorp/http-echo -- -text="WEB"
Verify both are running:
kubectl get deployments api-app web-app
Expected output:
NAME READY UP-TO-DATE AVAILABLE AGE
api-app 1/1 1 1 5s
web-app 1/1 1 1 5s
Step 3: Create the Services
kubectl expose deployment api-app --port=80 --target-port=5678
kubectl expose deployment web-app --port=80 --target-port=5678
Verify both Services have endpoints:
kubectl get endpoints api-app web-app
Each Service should list one Pod IP.
Step 4: Create the Ingress Resource
cat > ingress-exercise.yaml << 'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: exercise-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-app
port:
number: 80
- path: /web
pathType: Prefix
backend:
service:
name: web-app
port:
number: 80
EOF
kubectl apply -f ingress-exercise.yaml
The rewrite-target: / annotation rewrites the URL path before sending it to the backend. Without this, the backend receives /api or /web as the path, which may not match its expected routes. With the annotation, it receives /.
Step 5: Verify the Ingress
kubectl get ingress exercise-ingress
Expected output:
NAME CLASS HOSTS ADDRESS PORTS AGE
exercise-ingress nginx * localhost 80 10s
Wait for the ADDRESS field to populate (may take a few seconds).
Step 6: Test the Routes
curl http://localhost/api
Expected output:
API
curl http://localhost/web
Expected output:
WEB
Both paths route to their respective backend Services through the Ingress Controller.
Step 7: Verify with describe
kubectl describe ingress exercise-ingress
Look for the rules section showing the backend Services and their endpoints. The Events section should not show errors.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| 404 on both paths | Ingress Controller not running | Install it and wait for ready state |
| 503 on one path | Backend Service has no endpoints | Check the Service selector and Pod labels |
| Both paths return the same response | Only one Ingress rule matched | Verify path values are /api and /web (not /api/ or missing slashes) |
ADDRESS stays empty | ingressClassName mismatch | Verify it matches the installed controller (nginx) |
| curl: connection refused | Kind port mapping missing | Ensure Kind cluster config maps port 80 to the control-plane node |
Cleanup
kubectl delete ingress exercise-ingress
kubectl delete deployment api-app web-app
kubectl delete svc api-app web-app