Full lesson
Explore the full explanation, examples, and visuals at your own pace.
Same port, different addresses
Each Pod gets its own IP address. Here, Node 1 runs web-a at 10.244.1.5 and web-b at 10.244.1.6. Both listen on port 8080, but they're different addresses, so there's no clash. The port number alone was never the full identity. The IP and port together are.
A network namespace: a private network stack
Think of a network namespace as an apartment with its own street address and its own mailbox labeled 8080. It holds a private copy of interfaces, routes, and ports. Port 8080 is only unique inside one namespace. Containers in the same Pod share that namespace, so they do share ports.
Inside Node 1
Inside Node 1, web-a and web-b each live in their own namespace. A virtual cable, called a veth pair, connects each one to a bridge on the node. The bridge routes traffic out through eth0. The network plugin hands out the Pod IPs, and exact wiring varies by plugin.
One flat Pod network across nodes
Now add Node 2. Each node hands out Pod IPs from its own range, so Node 1 uses 10.244.1.x and Node 2 uses 10.244.2.x. That keeps every address unique across the whole cluster. It also means frontend, on Node 2, can reach web-a at 10.244.1.5 directly, with no port mapping in between.
A new Pod, web-d, starts on Node 1 and also listens on port 8080. What happens?
A new Pod, web-d, starts on Node 1 and also listens on port 8080. What happens?
- It gets its own IP, so no conflict
- It fails because web-a already uses 8080
- Kubernetes moves it to a different port
A new Pod, web-d, starts on Node 1 and also listens on port 8080. What happens?
It gets its own IP, so no conflict. web-d gets its own network namespace and a fresh Pod IP from Node 1's range. Port 8080 only has to be unique within one namespace, so web-a, web-b and web-d can all use it side by side.
- It gets its own IP, so no conflict
- It fails because web-a already uses 8080
- Kubernetes moves it to a different port
Pod IPs change when Pods restart or reschedule.
Unique Pod IPs fix the conflicts, but they're temporary. When a Pod restarts, its IP can change, so frontend shouldn't hard-code 10.244.1.5.
Service web: stable name, stable IP
A Service fixes that. The Service named web has a stable IP, 10.96.0.10, on port 80. It uses the label app=web to find every matching Pod, across both nodes, and forwards traffic to port 8080. When Pods come and go, the endpoints update automatically.
Tracing one request
Follow one request. The frontend asks CoreDNS for web, and gets back the ClusterIP, 10.96.0.10. It sends traffic to port 80. Rules on Node 2, managed by kube-proxy, pick one endpoint and rewrite the destination to 10.244.1.6, port 8080. The packet crosses to Node 1, reaches web-b, and the response returns.
Where conflicts still happen
A port is unique only per IP address, inside one network namespace. Two containers in the same Pod share that space, so the second one to bind 8080 fails. Separate Pods each get their own IP, so both work. Think of each Pod as a tiny computer. hostPort is the exception, since it claims the node's port.
In practice
So in practice, give every replica containerPort 8080 and don't think twice. Have clients call the Service name, never individual Pods. The only ports you need to watch are duplicates inside a single Pod, or a hostPort claiming a port on a node.
- Every Pod can use containerPort 8080
- Clients call the Service name, not Pods
- Avoid duplicate ports inside one Pod
Unique IPs, shared port, one stable Service
Each Pod is its own tiny computer with its own IP, so port 8080 never clashes. And Services give a stable front door to them. Pod IPs can change, but the Service name stays put, and traffic finds a Pod behind it.






