Lesson 5 · Workloads, config & networking
Services & cluster DNS
A stable name in front of ever-changing Pods — so nothing ever chases a Pod IP.
Your win: explain why Services exist, the four types (ClusterIP / NodePort / LoadBalancer / headless), and how in-cluster DNS lets one service reach another by name.
The problem Services solve
Lesson 3 and 4 left you with a fact: Pods are ephemeral, and their IPs change every time a ReplicaSet replaces one. So you can never hard-code a Pod IP. A Service is the fix: a stable name and virtual IP that fronts a dynamic set of Pods, chosen by label selector. Pods come and go behind it; the Service address never changes, and it load-balances across whichever Pods are currently ready.1
app: bob) and routes only to the ones passing
their readiness probe (Lesson 8). That's how a rolling update (Lesson 4)
stays seamless: a new Pod joins the Service's pool only once it's ready, and a terminating
Pod is removed from the pool first. The Service is the moving target's stable handle.
The four Service types
| Type | Reachable from | Use |
|---|---|---|
| ClusterIP (default) | inside the cluster only | service-to-service — the norm |
| NodePort | a fixed port on every node | simple external access / dev |
| LoadBalancer | an external IP (cloud LB) | expose to the internet |
headless (clusterIP: None) | DNS returns Pod IPs directly | stable per-Pod addressing (StatefulSets, L7) |
Cluster DNS — reach a service by name
Kubernetes runs an in-cluster DNS. Every Service gets a name:
<service>.<namespace>.svc.cluster.local, and within the same
namespace you can use just <service>.2
This is the exact idea you already know from Course 1 — Docker Compose let containers reach
each other by service name on a shared network — scaled to the whole cluster.
type: ClusterIP is hard-coded at line 12 — with named
http and grpc ports (:14-25). So all ~25 backend services talk to
each other over ClusterIP + cluster DNS, never Pod IPs. The only
LoadBalancer in the backend is
backend/zeus/templates/lb_service.yaml:13 (a static IP for
sftpgo); there are no NodePorts. External traffic doesn't come in through
Services at all here — it enters via the Istio ingress gateway (Course 4), which routes to
these ClusterIP Services.
tom and conversationmgmt reuse the normal
ClusterIP Service (its serviceName points there). Worth noting now; it makes
sense once you see why in Lesson 7.
Kubernetes docs — Service & DNS
Service types, selectors and endpoints, and how DNS names resolve for Services and Pods.
→ kubernetes.io — Service
→ kubernetes.io — DNS for Services and Pods
Check yourself (from memory)
Q1. A Service is needed because Pods…
Q2. The default Service type, reachable only inside the cluster, is…
Q3. Service bob in namespace ns resolves in-cluster as…
service.namespace.svc.cluster.local; same
namespace can shorten to just bob. Cluster DNS resolves it.
clusterIP: None → DNS returns Pod IPs, for
StatefulSets). CLUSTER DNS: reach a service at
service.namespace.svc.cluster.local (or just service in-namespace)
— like Course 1's Docker service-name resolution, cluster-wide. Repo: every service is a
ClusterIP from _service.tpl:4 (type hard-coded :12); only zeus is a
LoadBalancer; no NodePorts; external traffic enters via Istio (Course 4), not Services.