Containers Share Localhost

Why can an app and its sidecar reach each other over 127.0.0.1 with no network in between? Every container in a Pod joins the same network namespace, so they stand on the same loopback and the same eth0 and bind their ports in a single shared space. A loopback call never leaves the Pod, a bind of a pair another container holds comes back as address already in use, and from outside the Pod is one host whose container on that port answers.

Play the animation 5 steps, animated, best on a wide screen

Containers Share Localhost diagram: Containers in one Pod share a network stack

Containers Share Localhost, step by step

  1. Every container in this Pod joins one network namespace, so all of them share a single port space. The app binds :8080 in that space and the sidecar binds :15001, and neither of them gets a table of its own. A port claimed in there is claimed for the whole Pod rather than for one container.

    Play from step 1
  2. The app now calls 127.0.0.1:15001. Both containers stand on the same loopback, so the call goes down into lo and straight back up into the sidecar. There is no veth hop and nothing on the wire, just a loopback delivery inside the Pod.

    Play from step 2
  3. A bind claims an address and a port together, so the shared space is where the two containers meet. The sidecar already holds 127.0.0.1:15001, and an app that asked for that same pair would be refused with address already in use. Any port the sidecar has not claimed, :9090 here, is still open to it.

    Play from step 3
  4. A call from outside arrives on eth0, the one interface in the Pod that faces the network, at 10.244.1.5. It carries a port, and the container holding that port answers, here the app on :8080. From the outside the Pod is one host with one address per family, however many containers run inside.

    Play from step 4
  5. So the network belongs to the Pod rather than to a container: the address, the loopback and the port space are shared, while each container keeps its own root filesystem, and its own process tree unless the Pod sets shareProcessNamespace. That is what lets a sidecar proxy take the app traffic on localhost without leaving the Pod.

    Play from step 5

Sources