Home › CKAD › Topics › Practice tasks › Ingress Troubleshooting
CKAD · Services & Networking

Fix an Ingress That Doesn't Reach Its Application

The application should be reachable at http://content.prepium.local/content, but requesting that URL currently returns an error - the Ingress is misconfigured and traffic never reaches the Service.

Check live lab access → All CKAD tasks

Live lab access

This task description is public. Live practice requires full access unless this is the selected free weekly task. AI Lab Coach is available in single-task labs, including the free weekly task. See this week's free task.

Create an account to continue →

Read this week's free task →

On a phone? Read the task and create your account here, then sign in on a desktop or laptop for the terminal lab. Nothing starts until you choose Start.

The task

Context

A Deployment named content-app in namespace prepium is meant to be exposed through Ingress content-app-ingress. The manifests for the Deployment, Service, and Ingress are at /root/content-app/.

Task

The application should be reachable at http://content.prepium.local/content, but requesting that URL currently returns an error - the Ingress is misconfigured and traffic never reaches the Service.

Investigate the Ingress and the Service it points to, find the misconfiguration, and correct it so the route works.

Original Prepium guide · Written for Kubernetes v1.35 and checked against the official documentation on 6 October 2026. Use a disposable practice cluster. It needs an Ingress controller installed.

Troubleshoot an Ingress one hop at a time

A request through an Ingress crosses four hand-offs: the controller must claim the Ingress, a rule must match the host and path, the rule's backend must name a real Service port, and that Service must have ready endpoints. A broken route almost always fails at exactly one of these. Checking them in order is faster than rereading the whole manifest, and it tells you which object to edit.

controller ─(class)─→ Ingress rule ─(host+path)─→ Service:port ─(selector)─→ EndpointSlice ─→ Pods
   hop 1                 hop 2                      hop 3                      hop 4

1. Reproduce with a fault of our own

Save this as ckad-ingress-fix-broken.yaml, set the class, and apply it. The Service listens on 8080 and forwards to the container's port 80, but the Ingress backend asks for Service port 80.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ledger-ui
  namespace: prepium-tutorial
spec:
  replicas: 2
  selector:
    matchLabels:
      app: ledger-ui
  template:
    metadata:
      labels:
        app: ledger-ui
    spec:
      containers:
      - name: web
        image: nginx:1.27-alpine
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: ledger-ui
  namespace: prepium-tutorial
spec:
  selector:
    app: ledger-ui
  ports:
  - name: http
    port: 8080
    targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ledger
  namespace: prepium-tutorial
spec:
  ingressClassName: CHANGE-ME   # a NAME from: kubectl get ingressclass
  rules:
  - host: ledger.example.test
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: ledger-ui
            port:
              number: 80        # deliberate fault: the Service listens on 8080
kubectl create namespace prepium-tutorial
kubectl apply -f ckad-ingress-fix-broken.yaml
CTRL=203.0.113.10:30080   # node IP and NodePort (or ADDRESS) of your controller
curl -s -o /dev/null -w '%{http_code}\n' -H "Host: ledger.example.test" "http://$CTRL/"

Instead of 200 you get an error status generated by the controller, because it has nowhere to send the request.

2. Hops 1 and 2: is the Ingress claimed, and does a rule match?

kubectl get ingressclass
kubectl -n prepium-tutorial get ingress ledger
kubectl -n prepium-tutorial describe ingress ledger

Confirm the class exists, the host is spelled the way you send it in the Host header, and the request path fits the pathType. Exact /reports will not match /reports/, and Prefix matches whole path segments only. Here both hops are fine.

3. Hop 3: does the backend name a real Service port?

kubectl -n prepium-tutorial get svc ledger-ui -o jsonpath='{.spec.ports}'

The Ingress port.number must equal the Service's port, not the container's targetPort. In our example the Service only offers 8080, so port 80 matches nothing. The controller's log may also mention the backend it could not resolve; find its Pods with kubectl get pods -A | grep -i ingress and read the most recent lines with kubectl logs --tail=50, looking for your Ingress or Service name.

4. Hop 4: does the Service have ready endpoints?

kubectl -n prepium-tutorial get endpointslices -l kubernetes.io/service-name=ledger-ui
kubectl -n prepium-tutorial get pods -l app=ledger-ui --show-labels

Each Service's EndpointSlices carry the kubernetes.io/service-name label, so this lookup is reliable. An ENDPOINTS column of <none> means the selector matches no Pods: compare spec.selector with the Pod labels. If addresses are listed, use -o yaml to confirm their conditions.ready is true. Here the endpoints are present, which confirms the fault sits between Ingress and Service.

5. Fix the reference and retest

Change the backend to port.number: 8080, or better, to port.name: http so it survives a renumbering, apply, and run the same curl. A 200 now proves every hop. Fix the object that is wrong; changing the Service port to suit a broken Ingress can break other clients of that Service.

A caveat on paths: the Ingress API has no field for rewriting a URL. Rewrites are a controller feature, configured with that controller's own annotations, so an annotation written for one controller is simply ignored by another. If the app answers 404 only under a sub-path, check what path the backend actually receives before adding annotations.

Common mistakes

Example checkEvidence
Ingress is claimedingressClassName names an existing IngressClass
Backend reference resolvesIngress port equals a spec.ports[].port or name on the Service
Service has endpointsEndpointSlice endpoints show conditions.ready: true
Route works end to endcurl through the controller with the Host header returns 200

Cleanup: kubectl delete namespace prepium-tutorial. References: Ingress, Debug Services, EndpointSlices. Next, try Ingress configuration or Service selector troubleshooting.

Exam
CKAD
Domain
Services & Networking
Grading
Programmatic · partial credit

What this tests

Expose workloads with services and ingress, and restrict traffic with network policies. On the CKAD exam, Services & Networking tasks are graded purely on what you build in the cluster - not multiple choice - so the only way to get faster is to do them on a real cluster against a clock.

Practice it for real

The public description lets you study the task before signing up. Full access includes this live lab; the selected Task of the Week is free with an account. You solve the task in a real terminal, hit validate, and a programmatic checker scores exactly what you got right and wrong (with partial credit). You can open the solution while practising, then retry and use the failed checks to improve your score.

Related CKAD tasks