Appendix: DNS, HTTP, and TCP/IP
Build a practical mental model for names, addresses, ports, connections, requests, and Kubernetes networking.
When a page cannot reach an API, “the network” is too broad a diagnosis. Work layer by layer: name resolution, IP reachability, TCP connection, HTTP exchange, then browser policy.
Last updated: 2026-07-20
Who this chapter is for
This appendix is for beginners who have (or can deploy) the full-stack Minikube release and want a repeatable debugging habit. Basic Chapter 9 knowledge helps but is not mandatory if you run the prepare block below.
Download this chapter's files
Use your browser to download either ivia-chapter-11.tar.gz or ivia-chapter-11.zip. The archive is self-contained; you do not need this tutorial repository.
Open a terminal after the browser download:
cd ~/Downloads
tar -xzf ivia-chapter-11.tar.gz
cd ivia-chapter-11
All remaining relative paths in this chapter start from that extracted directory.
The challenge
Challenge: trace one request to the backend from DNS name through TCP connection to HTTP response and identify the layer of any failure.
Prerequisites
- A terminal with
kubectlandcurl. - A running Minikube cluster; the package includes a full-stack release to deploy if needed.
nslookupordigfor host DNS checks.
Learning goals
After this chapter, you will be able to:
- Distinguish DNS from routing
- Distinguish IP addresses from ports
- Distinguish TCP from HTTP
- Distinguish cluster DNS from public DNS
- Distinguish HTTP failures from CORS enforcement
Prepare a traceable release
If simple-app is not already deployed, create it from this package:
minikube addons enable ingress
kubectl label node minikube ivia.ch/nodetype=app --overwrite
minikube image build -t simple-backend:local fullstack-app/backend
minikube image build -t simple-frontend:local fullstack-app/frontend
helm upgrade --install simple-app \
oci://harbor.ivia.ch/ivia-generic-helm-chart/ivia-generic-helm-chart \
--version 4.8.0 -n tutorial --create-namespace \
--atomic --timeout 5m \
-f fullstack-app/values.yaml
A layered request
- DNS maps a name such as
api.simple-app.testto an IP address. - IP routes packets between network interfaces.
- TCP establishes an ordered byte stream to a port such as 80 or 8080.
- HTTP sends a method, path, headers, and optional body over that connection.
- CORS is a browser policy applied to cross-origin HTTP responses; curl does not enforce it.
Kubernetes adds two useful abstractions. A Service has a stable virtual IP and DNS name despite changing Pod IPs. Ingress examines HTTP hostnames and paths, then forwards to a Service.
Diagnostic story: start outside the cluster (hosts/--resolve → TCP → HTTP), then move inside (Service DNS → port-forward). Stop at the first layer that fails.
Trace from your computer
MINIKUBE_IP=$(minikube ip)
printf 'Minikube IP: %s\n' "$MINIKUBE_IP"
nslookup api.simple-app.test || true
curl --verbose --resolve api.simple-app.test:80:$MINIKUBE_IP \
http://api.simple-app.test/health
Expected observations: Minikube prints an IP; nslookup may fail for .test names (that is fine if you use --resolve); verbose curl shows Connected to, GET /health, and HTTP 200 with JSON.
--resolve supplies a temporary DNS answer for curl. In verbose output, find the chosen IP, Connected to, the request line GET /health, the Host header, the response status, and JSON body.
Test raw TCP availability without sending HTTP:
nc -vz "$MINIKUBE_IP" 80
You should see a successful connection to port 80. If nc is unavailable, curl's connection lines provide the same practical checkpoint.
Trace inside Kubernetes
Start a temporary DNS client Pod. We do this because cluster DNS names are not the same as your laptop’s hosts file.
kubectl run dns-check -n tutorial --rm -it --restart=Never \
--image=registry.k8s.io/e2e-test-images/dnsutils:1.3 -- \
nslookup simple-app-backend.tutorial.svc.cluster.local
You should see an address answer for the Service. The complete Service name means: Service simple-app-backend, namespace tutorial, Service zone svc, cluster domain cluster.local.
Forward the Service and bypass ingress:
kubectl port-forward service/simple-app-backend 8080:8080 -n tutorial
In another terminal:
curl --verbose http://localhost:8080/health
Expect HTTP 200. If direct Service forwarding works but ingress does not, investigate Ingress, host resolution, or its controller—not the backend process.
Expected validation
The host trace connects to Minikube port 80 and receives HTTP 200 from /health. Cluster DNS returns a Service address. Port forwarding also returns 200. You should be able to name the first failed layer if one check differs.
Troubleshooting and common pitfalls
- DNS answer exists but connection is refused: naming worked; inspect the destination port, process, Service endpoints, and firewall.
- TCP connects but HTTP is 404: transport worked; check Host header, route, and path.
- HTTP succeeds in curl but browser fails: inspect CORS, mixed content, certificates, and browser console.
- Pod IP used directly: Pod IPs are replaceable. Use a Service name inside the cluster.
localhostambiguity: it always refers to the current network namespace—the host, a container, or a Pod depending on where the command runs.- ICMP ping fails: many systems block ping while TCP/HTTP works; test the protocol you actually need.
Recap and practice
Recap: Prove DNS, then TCP, then HTTP, then browser policy. Cluster DNS and laptop DNS are different systems.
Try to explain in your own words:
- What does a successful
ncto port 80 prove that HTTP 200 does not yet prove? - Why might ingress fail while
kubectl port-forwardto the Service still works?
Exercise: Intentionally use the wrong Host header with curl and note whether you get a different HTTP status.
Stretch: From the dnsutils Pod, resolve the frontend Service name and compare it to the backend Service name.