Service and DNS failures
A hop-by-hop checklist for "the app is not reachable": DNS, the Service, its selector and targetPort, EndpointSlices, readiness, NetworkPolicies and kube-proxy.
After this lesson
- 01You can walk a request from client to container and name the one command that proves each hop works.
- 02You can tell a selector mismatch, a wrong targetPort and a NetworkPolicy drop apart from the error the client prints.
- 03You can check cluster DNS end to end: resolv.conf, an nslookup from busybox, the CoreDNS pods and their logs.
- 04You can fix a broken Service or NetworkPolicy in place without breaking what the grader also checks.
The official competency is Troubleshoot services and networking, and it usually arrives as one sentence: the frontend cannot reach the backend, fix it. The Pods are Running, nothing is crashing, and the fault sits somewhere between the client and the container. You find it fastest by testing each hop in order instead of guessing, so this lesson gives you that order and the exact symptom each fault produces.
A client calls http://orders. Its resolver expands the name with the search domains from /etc/resolv.conf and asks CoreDNS, which answers with the Service's ClusterIP. The packet goes to that virtual IP; kube-proxy's rules on the client's node rewrite it to one Pod IP and the Service's targetPort, picked from the Service's EndpointSlices. The EndpointSlice controller fills those slices with Pods that match the selector and are Ready. Finally the CNI delivers the packet, and any NetworkPolicy selecting the destination Pod decides whether it is allowed in.
# 1. Does the Service exist, and what does it select and forward to?
kubectl -n shop get svc orders -o wide
kubectl -n shop get svc orders -o jsonpath='{.spec.selector}{"\n"}{.spec.ports}{"\n"}'
# 2. Do Pods match that selector exactly, and are they Ready?
kubectl -n shop get pods -l app=orders -o wide --show-labels
# 3. Did the selector produce endpoints? (Endpoints is deprecated since v1.33; read EndpointSlices.)
kubectl -n shop get endpointslices -l kubernetes.io/service-name=orders -o wide
# 4. Which port does the container actually listen on?
kubectl -n shop get pod -l app=orders -o jsonpath='{.items[0].spec.containers[*].ports}{"\n"}'
# 5. Is any NetworkPolicy selecting the backend Pods?
kubectl -n shop get netpol
kubectl -n shop describe netpol
# 6. Test from inside the cluster, by name and by Pod IP, with a short timeout.
kubectl -n shop run probe --image=busybox:1.36 --restart=Never -- sleep 3600
kubectl -n shop exec probe -- wget -qO- -T 3 http://orders.shop.svc.cluster.local/
kubectl -n shop exec probe -- wget -qO- -T 3 http://<pod-ip>:8080/Read the client's error before you read any YAML. On this lab (kube-proxy in iptables mode), a Service with no endpoints answers Connection refused, because kube-proxy installs a reject rule for it. A wrong targetPort also gives Connection refused, but from the Pod itself, and the EndpointSlice is populated. A NetworkPolicy drop gives no answer at all, so wget waits out its -T timeout. Refused with empty endpoints means selector or readiness; refused with endpoints means port; a hang means policy or the network.
Selectors, targetPort and readiness
- Selector. A Service selector is an exact, case-sensitive AND of every pair it lists:
tier: backenddoes not matchtier: Backend, and one extra key the Pods lack matches nothing. Compare it withkubectl get pods --show-labels. The Deployment's ownmetadata.labelsare irrelevant; onlyspec.template.metadata.labelsend up on Pods. - targetPort.
portis what clients dial on the ClusterIP;targetPortis where the packet lands in the Pod. LeavetargetPortout and it defaults toport, the classicConnection refusedwhen the app listens on 8080 and the Service says 80. A namedtargetPortfollows the container if its port number changes. - Readiness. A Pod whose readiness probe fails stays in the EndpointSlice with
ready: falseand receives no Service traffic. Three unready Pods behind a correct Service look exactly like a broken selector from the client's side; the EndpointSlice tells them apart.
# In the Pod template
ports:
- name: http
containerPort: 8080
---
# In the Service
ports:
- name: web
port: 80 # what clients call
targetPort: http # resolved per Pod to its containerPort named httpPolicies, DNS, kube-proxy and NodePort
- NetworkPolicy. Once any policy with
policyTypes: [Ingress]selects a Pod, only traffic some policy allows gets in. Check thatspec.podSelectorpicks the backend, thatfrommatches the client's labels (and namespace, whennamespaceSelectoris used), and thatportslists the container port. Policies see the packet after the Service rewrote it, so a rule for port 80 does nothing for an app on 8080. - DNS. Test with the full name,
nslookup <svc>.<ns>.svc.cluster.local, frombusybox:1.36.NXDOMAINmeans the name or namespace is wrong;no servers could be reachedmeans CoreDNS is down, unreachable or blocked. If the client's namespace has an egress policy, it must allow UDP and TCP 53 to CoreDNS, or every lookup times out. - kube-proxy. It runs as a DaemonSet in
kube-systemand programs each node's rules (iptables mode on this lab). A missing or crashing kube-proxy Pod on one node breaks ClusterIPs only for clients on that node, while Pod IPs keep working. - NodePort. The same Service, also opened on every node at
spec.ports[].nodePort(30000 to 32767). Test withcurl -s -m 3 http://<node-internal-ip>:<nodePort>/using an IP fromkubectl get nodes -o wide. On the lab run it inside a node (docker exec cka-worker curl …), because the node IPs live on Docker's network. WithexternalTrafficPolicy: Localonly nodes that run a backend Pod answer.
# Resolver config the kubelet wrote into the Pod
kubectl -n shop exec probe -- cat /etc/resolv.conf
# search shop.svc.cluster.local svc.cluster.local cluster.local / nameserver 10.96.0.10 / options ndots:5
# Use the FQDN with busybox nslookup; it is the unambiguous test
kubectl -n shop exec probe -- nslookup orders.shop.svc.cluster.local
kubectl -n shop exec probe -- nslookup kubernetes.default.svc.cluster.local
# CoreDNS: Pods, Service, logs and its config
kubectl -n kube-system get pods -l k8s-app=kube-dns -o wide
kubectl -n kube-system get svc kube-dns
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=50
kubectl -n kube-system get configmap coredns -o yaml
# kube-proxy: one Ready Pod per node, and its logs
kubectl -n kube-system get ds kube-proxy
kubectl -n kube-system get pods -l k8s-app=kube-proxy -o wide
kubectl -n kube-system logs ds/kube-proxy --tail=20
# The rules it wrote for a Service, on a node (exam: ssh <node>, then sudo iptables-save)
docker exec cka-worker iptables-save | grep 'shop/orders'
# NodePort from inside a node
kubectl -n shop get svc orders -o jsonpath='{.spec.ports[0].nodePort}'; echo
docker exec cka-worker curl -s -m 3 http://localhost:<nodePort>/In the docs · the tab you get on exam day
- Debug Services ↗search: “debug services”
- Debugging DNS Resolution ↗search: “debugging dns resolution”
- Network Policies ↗search: “network policy”
- Service ↗search: “service targetPort”
context · kubectl config use-context kind-cka
A Service that refuses connections
tsx-svc, requests from Pod shell to http://orders.tsx-svc.svc.cluster.local/hostname fail with Connection refused, although both orders Pods are Running. Find the fault and fix the Service orders so the request returns an orders Pod's hostname. Clients must keep using port 80. Do not modify the Deployment.- 01
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/ts-svcdns-1/setup | bash - 02
Solve it in your terminal
Work the way the exam makes you: kubectl, the docs, nothing else. Put any answer files under
/tmp/cka/. - 03
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/ts-svcdns-1/verify | bashCounts toward your readiness score. - 04
Clean up
curl -fsSL https://codewithmuh.com/labs/cka/t/ts-svcdns-1/cleanup | bash
context · kubectl config use-context kind-cka
A Service with no endpoints
tsx-sel, the Service catalog sends no traffic anywhere, even though the two Pods of Deployment catalog are Running and Ready. Fix the Service so that both catalog Pods become its endpoints and http://catalog.tsx-sel.svc.cluster.local/hostname answers from Pod shell. Do not modify the Deployment.- 01
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/ts-svcdns-2/setup | bash - 02
Solve it in your terminal
Work the way the exam makes you: kubectl, the docs, nothing else. Put any answer files under
/tmp/cka/. - 03
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/ts-svcdns-2/verify | bashCounts toward your readiness score. - 04
Clean up
curl -fsSL https://codewithmuh.com/labs/cka/t/ts-svcdns-2/cleanup | bash
context · kubectl config use-context kind-cka
A NetworkPolicy that blocks the frontend
tsx-netpol, Pod frontend must be able to call Service api on port 80, but its requests hang until they time out. Pod reports must stay blocked from api. Fix this by correcting the existing NetworkPolicy api-ingress. Do not delete it, do not add other policies and do not change any Pod's labels.- 01
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/ts-svcdns-3/setup | bash - 02
Solve it in your terminal
Work the way the exam makes you: kubectl, the docs, nothing else. Put any answer files under
/tmp/cka/. - 03
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/ts-svcdns-3/verify | bashCounts toward your readiness score. - 04
Clean up
curl -fsSL https://codewithmuh.com/labs/cka/t/ts-svcdns-3/cleanup | bash
Finished reading?
0 of 3 tasks passed. Readiness counts tasks, so run them before you move on.