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.
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 →
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
- Using the container port in
port.number. The Ingress talks to the Service. - Testing with the ClusterIP and declaring the Ingress fixed. Only a request through the controller with the right Host header tests the rule.
- Missing a selector typo because the Pods are Running. Running Pods that the selector does not match still leave the Service empty.
- Copying a rewrite annotation from a blog written for a different controller, which then has no effect.
| Example check | Evidence |
|---|---|
| Ingress is claimed | ingressClassName names an existing IngressClass |
| Backend reference resolves | Ingress port equals a spec.ports[].port or name on the Service |
| Service has endpoints | EndpointSlice endpoints show conditions.ready: true |
| Route works end to end | curl 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.
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.