How it works
The explanation, with examples you can run.
The manifest
apiVersion: v1kind: Servicemetadata: name: webspec: type: ClusterIP selector: app: web # the pods from the Deployment's template ports: - name: http port: 80 # what clients use targetPort: 3000 # what the container listens onkubectl get svc web# NAME TYPE CLUSTER-IP PORT(S)# web ClusterIP 10.96.41.120 80/TCPkubectl get endpointslices -l kubernetes.io/service-name=web# the ready pod IPs on port 3000How a connection reaches a pod
- The client resolves
web. Each pod's/etc/resolv.confpoints at the cluster DNS (CoreDNS) with search domains such asshop.svc.cluster.local, sowebexpands toweb.shop.svc.cluster.localand resolves to the ClusterIP. - The client connects to
10.96.41.120:80. No process listens on that address. - On the client's node, rules written by kube-proxy match the virtual IP and rewrite the destination to one endpoint, for example
10.244.2.17:3000. - The pod network delivers the packet to that pod, on whatever node it runs.
kube-proxy watches Services and EndpointSlices and rewrites those rules whenever pods come, go, or change readiness. Its default mode on Linux is still iptables; an nftables mode is available and is planned to become the default, and IPVS mode was deprecated in 1.35. Some network plugins (for example Cilium with eBPF) replace kube-proxy entirely. Load balancing happens per connection, so long-lived connections such as HTTP/2 or gRPC stick to one pod; balance those at layer 7 with a proxy or mesh.
Service types
- ClusterIP (default): reachable inside the cluster only.
- NodePort: also opens a port (30000-32767 by default) on every node.
- LoadBalancer: also asks the cloud provider for an external load balancer pointing at the nodes.
- Headless (
clusterIP: None): no virtual IP; DNS returns the pod IPs directly. StatefulSets use this to give each pod its own name. - ExternalName: a DNS alias (CNAME) for something outside the cluster.
When it does not connect
Check in this order:
- Endpoints empty? The selector does not match the pod labels, or no pod is ready.
- Wrong port?
targetPortmust be the port the container listens on (a named port is safest). - App bound to 127.0.0.1? It must listen on
0.0.0.0to accept traffic from outside its own pod. - Wrong namespace? Bare names resolve only in the caller's namespace; use
name.namespace. - NetworkPolicy? A default-deny policy drops traffic that is not explicitly allowed.
Because only ready pods are endpoints, readiness probes are also how a pod takes itself out of traffic during start-up, overload or shutdown.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.