Recently, I’ve been spending a fair amount of time looking at the OCI runtime specification and at the reference implementation, runc. I tend to learn best by doing, and the low-level bits of how containers work have interested me for a long while now, so I’ve started writing a new non-production OCI runtime to learn more about it. In the OCI spec, the docker run interface that folks familiar with Docker containers use has been broken up into multiple steps: create and start. But what’s interesting about runc’s implementation here is that the standard input/output streams (which I tend to refer to as STDIO) for the container’s main process are hooked up to the STDIO streams of runc create rather than that of runc start. This means that if you run runc create in one terminal, and then run runc start in a second terminal, the input and output of your container will be hooked up to the first terminal rather than the second! I’m not entirely clear on the history of why runc behaves this way, but I think the how is interesting on its own. And that how is through multiple processes synchronizing via a FIFO.