Every pod is healthy and the service still answers nothing
Can I prove whether the Service is actually routing to any pods?
The ticket
CUSTOMER TICKET: order lookups return nothing, but everything looks healthy
Account: Tidewater Health (enterprise) Impact: order lookups failing for all users Started: after yesterday's platform work
Our order lookups have stopped returning anything since some platform work yesterday. Our team checked and everything reports healthy on your side, so they are stuck. The application does not error, it just gets nothing back.
Your job
- Everything healthy plus nothing working is a specific pattern. Work out what it points at.
- Prove where the request stops before you name a cause.
- Restore service and verify the customer's own workflow.
Working notes
The workload runs in the tse-training namespace on the kind-proveit
context. Unlike the Docker track there is no file to edit and no tse apply:
change the cluster directly, the way you would in production, then run
tse check. tse reset puts the ticket's state back.
- Track
- Kubernetes
- Time
- about 35 minutes
- Difficulty
- Involved
- Tier
- Core
Do these first: A release went out and the new version never arrived
Start it
In a Codespace or a local clone:
tse start kubernetes/04-service-reachable-but-returns-nothingThat provisions the broken system and prints the ticket above. Investigate with ordinary tools, then run tse check.
Look at the evidence
Real output, captured by running these commands against the broken system and checked against it on every build. It shows you what the evidence looks like. It cannot fix anything, and it will not tell you what is wrong.
Type a command you would reach for, or help.
Enter runs it. Shift and Enter start a new line. The up and down arrows walk back through what you have typed.
Investigation scratchpad
Saved in this browser as you type. Nothing is uploaded. 0 of 7 filled in.
In their words, not yours. Include scope and urgency.
Before running anything: target layer, expected output, two likely causes.
The command or query, and why it is safe to run here.
Three separate lists. This is the step people skip.
One proof sentence, one safe next step, one alternate hypothesis.
Plain language. Impact first. No blame, no speculation.
One gap, one command to repeat tomorrow, one confidence score.
Hints
Each hint gives away a little more. Try to spend a few minutes on your own evidence first, because the recall is what makes it stick.
Hint 1 of 3
"Everything reports healthy and nothing works" is not a contradiction. It is a pattern, and it points somewhere specific.
If the workload is healthy, and the application is fine, and the client gets nothing rather than an error, then the request is not reaching the application at all. Something in between is accepting it and delivering it nowhere.
So stop checking health. You already have that answer, and repeating it is the loop most people get stuck in. The question now is:
Does the thing in front of the application actually know about any of it?
The connection between a front door and the workload behind it is not a hardcoded link. It is a query, evaluated continuously, and a query can return nothing while looking completely correct.
Hint 2 of 3
The front door here matches workloads by their labels rather than by name. That matching happens constantly, and its result is written down in an object you can read directly.
That object is where the emptiness becomes visible. The front door itself will look perfectly healthy whether it matches two workloads or none, because from its own point of view nothing is wrong: it was asked to route to whatever matches, and it is doing exactly that.
Read the current result of the query. If it is empty, then you have proven the break is in the matching and not in the workload, the application, or the network.
Then compare the two halves the query joins: what is being asked for, and what the workload actually carries.
Hint 3 of 3
kubectl -n tse-training get endpointslices -l kubernetes.io/service-name=orders-api
No addresses. The Service is selecting nothing, which proves the failure is in the matching rather than in the workload or the application.
Now read both halves. What the Service asks for:
kubectl -n tse-training get service orders-api -o jsonpath='{.spec.selector}{"\n"}'
And what the pods actually carry:
kubectl -n tse-training get pods --show-labels
The values differ. Yesterday's platform work changed one side and not the other. Correct the Service so its selector matches the labels the pods already have, since the pods are running correctly and should not be disturbed:
kubectl -n tse-training edit service orders-api
kubectl -n tse-training get endpointslices -l kubernetes.io/service-name=orders-api
Solution
Write your customer update before you read this. Comparing your wording against the model answer is worth more than reading it cold.
Reveal the solution
Solution: healthy everywhere, routing nowhere
What the evidence proved
| Command | What it proved | What it did not prove |
|---|---|---|
kubectl get pods |
Pods are Running and Ready | Nothing about routing |
get endpointslices |
The Service has no endpoints at all | Why the selection is empty |
get service -o jsonpath |
The selector asks for app.kubernetes.io/name: orders |
|
get pods --show-labels |
The pods carry app.kubernetes.io/name: orders-api |
Empty endpoints is the fact that turns this ticket. It proves the break is in the selection rather than in the workload, the application, or the network, and it is invisible from everything the customer had already checked.
Root cause
A Service does not link to a Deployment. It runs a label query continuously and
routes to whatever currently matches. Yesterday's platform work changed the
Service's selector to orders while the pods kept the label orders-api, so
the query matches nothing and the Service routes to nothing.
Every health check the customer ran was accurate. The pods really were healthy, the Service really did exist, and DNS really did resolve. A Service with no endpoints still resolves and still accepts connections. It simply has nowhere to send them, which is why the client gets nothing back rather than an error.
Scoped fix
The pods are running correctly and should not be disturbed, so the Service moves:
kubectl -n tse-training edit service orders-api
# spec.selector: app.kubernetes.io/name: orders -> orders-api
kubectl -n tse-training get endpointslices -l kubernetes.io/service-name=orders-api
Confirm endpoints appear before declaring it fixed. Endpoints appearing is the proof, not the Service looking healthy again, which it did throughout.
Customer update
Your team was right that everything reports healthy, and that was genuinely true rather than a false reading. The problem was in between: the internal address for the order service selects the instances it should route to by label, and yesterday's platform work changed the label it looks for without changing the label the instances carry. The result is an address that resolves and accepts connections but has nothing behind it, which is why requests returned nothing instead of failing outright.
We have corrected the selection and confirmed the order service is now receiving traffic and returning results. Nothing was wrong with the application or its instances at any point.
If the same platform work touched other services, they are worth checking, as the same edit would produce the same silent failure.
Engineering escalation, if you needed one
Impact: order lookups returning empty for all users since yesterday's platform work. Evidence: EndpointSlice for
orders-apihas no addresses; Service selector isapp.kubernetes.io/name=orders; pods carryapp.kubernetes.io/name=orders-api; pods Running and Ready throughout. Confirmed: pod health, application health, DNS resolution. Ruled out: application fault, image, resource pressure, readiness. Suspected cause: a selector edit during platform work not matched by a label change on the workload. Request: identify which other Services were edited in the same change, since this failure mode reports healthy everywhere.
Check your understanding
Three questions on what the evidence here proved, and what it pointedly did not. Wrong answers explain themselves, and so do right ones.
tse quiz
Check your understanding
Three questions on what the evidence proved and what it did not. Every answer explains itself, including the right one.
3 questions, none answered yet.
Why this one exists
A Service is a label selector, not a link. It can exist, resolve, and accept connections while selecting nothing at all, and the endpoints are the only place that emptiness is visible.
In an interview
The classic Kubernetes networking question. Everything you look at first reports healthy, which is why candidates loop on pods and logs. Knowing that a Service is just a label query, and that its EndpointSlice is where that query's result becomes visible, is the whole test.
Commands introduced
kubectl get endpointsliceskubectl get pods --show-labelskubectl describe service
Evidence layers
- pod readiness
- service selector and pod labels
- endpoints