Basis Lab

What a Container Actually Is

Follow One Request In, and Name Every Translation on the Way

Last timeWho the Process Thinks It Is

A container holds a network stack of its own, so the same address means two different things inside and outside. One request is followed across the join and every hop priced.

A stack of its own, not a cable into yours

The network view is the one of the six separated views that people reason about

with the wrong picture, and the wrong picture is a cable. A cable would mean the

container is sitting in the host's network holding one more address on it. That

is not what happens. The process is handed a second stack.

A stack is more than an address. It is the set of network interfaces that

exist, the routing table that decides which of them a packet leaves by, the table of which link-layer address belongs to which neighbour, and the

65,535 ports that can be listened on. Hand a process a

view of its own and all of that is new and almost entirely empty. Two

interfaces usually exist in it: one end of a pair that reaches out of the box,

and a loopback.

That loopback is where most of the trouble starts, because it is not the host's.

The standards are unambiguous that the whole of 127.0.0.0/8 is internal to one

host and never appears on a network, and a network view is, for this purpose, a

host. So the host running the service has one 127.0.0.1 and the container has

another, and nothing can get from one to the other, because getting there would

require a packet addressed to a loopback to cross a network and that is the one

thing the address is defined not to do.

Count them for the running example. Ten containers from the 180 MB image, each

with a view of its own, on one machine. That is 10+1=1110 + 1 = 11 distinct loopback

interfaces, all answering to the same four numbers, each reaching exactly one

thing. Ten of the eleven are invisible from the host and from each other.

The ports work the same way, and this is the half of it that saves work rather

than causing it. Each view has its own 65,535, so all ten containers can listen

on port 8080 at once with nothing to arrange, because there are ten separate

port 8080s. The collision people expect does not happen inside. It happens on

the host, and only for the containers whose ports are published, which is the

subject two sections down.

What has to exist before a packet can cross

Two stacks with no relationship do not reach each other. Whatever connects them

is built, and it is built out of three parts.

The first is a pair of virtual interfaces, created together, where everything

written into one end comes out of the other. One end is put into the container's

view and the other stays in the host's. That is the only physical fact in the

arrangement, and it is why the container's traffic is visible on the host at all.

The second is a bridge in the host's view with the outside ends of all those

pairs attached to it. A bridge forwards by link-layer address, so once the

containers are on it they are neighbours on one subnet and find each other the

ordinary way, by asking who holds a given address and caching the answer.

Nothing rewrites anything on that path. Container to container is the plainest

leg in the system and the one people assume is complicated.

The third is a translation at the edge, and it is needed because of the

addresses. A bridge network is cut from the private blocks, which are defined

as not routed on the public internet. Take 172.18.0.0/16 as the running one,

with the host holding 172.18.0.1 on its end of the bridge, the service on

172.18.0.4 and a data store on 172.18.0.5. A client out on the internet cannot

address 172.18.0.4, not because something forbids it but because no router will

carry it anywhere. So the only address the outside can use is one of the host's,

and something has to rewrite the host's address and port into the container's.

FIG 1The whole arrangement, written down as what each part holds
yaml
networks:
  app_net:
    subnet: 172.18.0.0/16        # 2 to the 16th addresses in it
    gateway: 172.18.0.1          # the host end of the bridge

services:
  web:
    address: 172.18.0.4
    listens: 0.0.0.0:8080        # every address in its own view, not only its loopback
    published: 198.51.100.7:80   # the one pair the outside can use
  store:
    address: 172.18.0.5
    listens: 0.0.0.0:5432
    published: none              # reachable by name from web, by nothing from outside
Four addresses and three ports, and every confusion in this subject is two of them being treated as one. 172.18.0.4 port 8080 is where the service is. 198.51.100.7 port 80 is where the outside world is told it is. Those are different pairs on different stacks and the published rule is the only thing relating them. The subnet line is worth its own arithmetic, below.

The subnet fixes how many containers the bridge will hold, and the arithmetic is

worth doing once because the answer surprises people in both directions. A /16

is 216=65,5362^{16} = 65{,}536 addresses. Three are not available to a container: the

network address itself, the broadcast address, and the gateway the host holds.

Ten containers are running. So 65,536−3−10=65,52365{,}536 - 3 - 10 = 65{,}523 addresses are

still free. Nobody runs out of addresses on a bridge. People do run out on a

/24, which is 28=2562^8 = 256 addresses and 253 usable, and that is a limit a busy

machine can actually reach.

The lesson stops here

5 more paragraphs to go

You have read the opening. The rest of the argument, the problems that check whether it landed, and the lines worth keeping at the end all come with a plan.

The first lesson of every course in the library reads the whole way through, free, so you can see exactly what the rest of them are.

See the planThe contents

This is the reading half

Starting the course gives you your own copy of it. Every idea on every page has problems standing under it, marked with a reason rather than a tick, and any sentence you do not believe can be opened and argued with. None of that can happen on a page nobody owns.

The contents

The rest of this course

  1. 01One Kernel, Many Processes, and No Boot Sequence Anywhere
  2. 02Six Views a Process Can Be Given Instead of Yoursopening only
  3. 03A Different Root Directory, and Why It Is Not a Wallopening only
  4. 04Half a Processor and 512 MB, and Why Only One of Them Killsopening only
  5. 05Layers, and Why One Line Rebuilds Sixty Megabytesopening only
  6. 06Why the File It Wrote Is Owned by Rootopening only
  7. 07Follow One Request In, and Name Every Translation on the Wayyou are here
  8. 08The Boundary Is a View, and the Kernel Underneath It Is Sharedopening only

Read alongside