OS docker container: what is the difference with a VM then?

You are lacking basic Docker concepts. It's a completely different thing.

The first thing you need to know is Docker's philosophy : run one process isolated in a container. You won't run an OS in a Docker container, you will run a process inside a container with a root filesystem content based on a linux distribution of your choosing. Ubuntu is a choice among others.

Now you should wonder how is it possible to get a process runing inside a linux base image different from the linux distribution your host is running with. For an OS to run you basically need :

  • A boot filesystem : contains the bootloader and the kernel that will reside in memory once loaded. We don't care about this in the case of Docker containers because the kernel is shared with the host and is the common part between all linux distributions.
  • A root filesystem : contains the filesystem structure. It may be different from one linux distribution to another. It's read-only until the boot sequence has finished.

Docker uses UnionFS to manage layers of disk blocks inside a container so you can pile them.

Behind the scenes, it uses an union mount which allows multiple filesystems to be mounted at the same time, appearing like a whole virtual one. It in fact drops the base image layer as read-write mode on top of the base root filesystem in read-only mode.

Here you have a pile of disk blocks layered in a way that the linux distribution the base image comes from would contain the same filesystem once installed in a real host, but it's inside a container this time.

The last thing lacking now is : how do you run this thing isolated ?

The answer is : namespaces. I won't go into the details here because it would deviate a bit from the original question. But what you need to know is that since kernel 2.4.19, namespaces of various kinds have appeared along the years. Currently the following namespaces are available :

  • IPC : IPC namespace (interprocess communications)
  • MNT : mount namespace
  • NET : network namespace
  • PID : pid namespace
  • USER : user namespace (uid)
  • UTS : UTS namespace (hostnames)

Namespaces are isolated structures inside the kernel that allow processes to run with a particular environment. For instance MNT namespace will be the key feature to get a process running in the base image root filesystem specificities. NET namespace will be another key feature for a container to have specific network interfaces in order to communicate with the docker bridge etc.

So, yes, the main purpose of all of this is to run an application isolated, ship it from your local environment to production easily with inside a box called container.

It would be a good idea to read docker's documentation before digging further into it.