Apparently a container does not even need an OS whereas VMs do. Container != VM, but I never stopped to think about this before. Processes within the container can directly talk to the kernel on which the container is running. Most containers are built with a base OS image. Turns out you can create an image without a base OS by pulling the scratch image, that contains nothing.

Let’s create a small c program that is statically compiled.

$ cat small.c
#include <unistd.h>

int main()
{
  write(1, "Hi!", 3);
}

$ gcc -o small small.c --static

Just 852kB!

$ ls -l small --block-size=k
-rwxrwxr-x 1 username username 852K Aug 5 15:34 small

This executable has everything it needs to run and does not need an OS. There is nothing specific to Ubuntu, for example. It just prints “Hi!”.

$ ./small
Hi!

Let’s build a Docker image with this executable inside it.

# Run this in the same directory where the executable 'small' is.
$ cat Dockerfile
FROM scratch
ADD small /small
CMD ["/small"]

$ docker build -t small-image -f Dockerfile .

$ docker images

REPOSITORY     TAG       IMAGE ID         CREATED             SIZE
small-image    latest    46ad701a4cce     About an hour ago   872kB

It’s about 872kB which is almost the same size as the executable small. This should convince you that the scratch image has nothing in it and we can verify this a functional image without a base OS, directly talking to the kernel.

$ docker run small
Hi!

Hope you found this useful!