Skip to main content
mastering ckad certified kubernetes application developer

Service and DNS Solutions

5 min read Chapter 38 of 87
Summary

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

SymptomCauseFix
Endpoints show <none>Selector mismatchRun kubectl get pods --show-labels and compare with kubectl describe svc echo-svc | grep Selector
DNS resolution failsCoreDNS not runningCheck kubectl get pods -n kube-system -l k8s-app=kube-dns
wget returns “connection refused”Wrong targetPortThe http-echo image listens on 5678 — verify targetPort is 5678, not 80
Only one endpoint despite 2 replicasOne Pod not readyCheck 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

SymptomCauseFix
404 on both pathsIngress Controller not runningInstall it and wait for ready state
503 on one pathBackend Service has no endpointsCheck the Service selector and Pod labels
Both paths return the same responseOnly one Ingress rule matchedVerify path values are /api and /web (not /api/ or missing slashes)
ADDRESS stays emptyingressClassName mismatchVerify it matches the installed controller (nginx)
curl: connection refusedKind port mapping missingEnsure 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