Files
rootnode-academy/content/root/root-07-kubernetes-networking-config/m03-services-and-service-discovery/01-lesson-services.md
T
ced4568andClaude Sonnet 5 dbcc210889 feat(root): author networking and configuration curriculum
root-07-m03-services-and-service-discovery — a new, full gold-standard-
pattern module: the Service/Endpoints/DNS request path, choosing the
right Service type. Lesson, demonstration (a Service with zero
Endpoints — the single fastest diagnostic check for this failure
class), knowledge check, guided exercise (ClusterIP vs. NodePort vs.
LoadBalancer for three real components), a real Lab
(expose-service-basics), and a reflection.

root-07-m04-ingress-networkpolicy-foundations — a new PARTIAL module:
Ingress and NetworkPolicy at the architectural level (the security-
control framing of NetworkPolicy is deliberately deferred to ROOT 09).
Lesson + knowledge check + real Labs (ingress-task, network-policy).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-26 09:06:19 -05:00

88 lines
4.2 KiB
Markdown

# The Service/Endpoints/DNS Request Path
## The problem: Pod IPs are not stable
Every Pod gets its own IP address, but that IP is NOT durable — when a Pod is replaced (a
rollout, a crash recovery, a reschedule), the new Pod gets a brand new IP. If another part of
your application had that old IP hardcoded, it would silently start talking to nothing. This is
the exact problem in `expose-service-basics`'s scenario: "other pods cannot reliably connect
because pod IPs change when they restart."
## A Service: a stable address in front of a moving set of Pods
A Service is a stable virtual IP and DNS name that automatically routes to whichever Pods
currently match its label selector — regardless of how many there are or how often they change.
You never talk to a Pod's IP directly in normal operation; you talk to the Service, and the
Service's Endpoints (a live, continuously-updated list of the matching Pods' IPs) determines
where traffic actually goes.
```yaml
apiVersion: v1
kind: Service
metadata:
name: redis-svc
spec:
selector:
app: redis # <- matches Pods by label, same mechanism from ROOT 05
ports:
- port: 6379
```
This is the same label-selector mechanism you learned in ROOT 05 — a Service doesn't know or
care about specific Pod names, only which Pods currently carry a matching label.
## The three Service types you'll use most
- **ClusterIP** (the default) — reachable only from inside the cluster. Use this for
internal-only communication, like one microservice talking to another or to a database.
- **NodePort** — additionally exposes the Service on a static port on every node's own IP,
reachable from outside the cluster. Mostly used for development/testing or when there's no
cloud load balancer available.
- **LoadBalancer** — asks the cloud provider to provision a real external load balancer pointed
at the Service. This is the standard way to expose something to the public internet on a
cloud-hosted cluster.
Choosing wrong isn't just a style preference — a ClusterIP Service is architecturally
unreachable from outside the cluster no matter how correctly everything else is configured.
## DNS: how Pods actually find a Service by name
Every Service automatically gets a DNS name inside the cluster
(`<service-name>.<namespace>.svc.cluster.local`, or usually just `<service-name>` from within
the same Namespace) — this is why application code can use a plain hostname like `redis-svc`
instead of an IP address at all. Kubernetes' internal DNS resolves that name to the Service's
stable virtual IP, which then routes to whichever Pods are currently healthy.
## The full request path, end to end
```
Client -> DNS lookup "redis-svc" -> Service's stable virtual IP
-> Service consults its Endpoints (live list of matching, ready Pods)
-> traffic forwarded to one of those Pod IPs
```
Every one of these steps can fail independently, which is exactly why "the app can't reach
redis" requires checking each layer rather than guessing — the next activity shows you what
that looks like when the Endpoints layer is empty.
## Instructor Notes
**Approximate timing:** 15 minutes read, 10-12 minutes live with the request-path diagram.
**Demo plan:** Before the next activity, it's worth live-running `kubectl get endpoints
<service-name>` against a healthy Service so students see a populated Endpoints list before
they see an empty one in the demonstration.
**Likely misconceptions to watch for:**
- Students often think a Service "is" a load balancer process running somewhere. It's closer to
a routing rule maintained by `kube-proxy` on every node — worth clarifying that there's no
single "Service Pod" to go find and debug.
- ClusterIP vs. NodePort vs. LoadBalancer is sometimes memorized without the "why" — the
knowledge check's Service-type question is designed to test the underlying reasoning, not
just recall.
**Discussion question:** "If a Service's selector matches zero Pods, does the Service itself
fail to exist?" (Answer: no — the Service object exists fine; its Endpoints list is just empty,
which looks like connection failure from the client's side without any error at the Service
level itself. This is exactly the next activity's topic.)