I used to think of Docker containers as lightweight, trimmed-down virtual machines. The comparison made sense because, at least in the initial marketing of Docker, it was always compared to virtual machines — for example, “Docker takes less time to spin up than VM,” and so on. But docker containers are not virtual machines. Let’s do a side-by-side comparison of the Docker container and virtual machines.
Virtual machines (VMs) are an abstraction of physical hardware that turns one server into many. The hypervisor allows multiple VMs to run on a single machine. Each VM includes a full copy of an operating system, the application, and necessary binaries and libraries — taking up tens of GBs. VMs can also be slow to boot.
Virtual machine architecture
Let’s assume there are a number of layers. When these layers are attached, they form a virtual machine.
The bottom layer of the virtual machine infrastructure is mostly the hardware of the virtual machine.
This hardware layer is mostly the pool of the required hardware to run the virtual machine. It consists mainly of Ram — it can be SSD (usually, it’s SSD) or even low-performance HDD, CPU, etc.
Above this layer, there runs a Host OS — usually Linux and sometimes Windows. Above this, there’s a layer known as the hypervisor layer. There are two types of hypervisor layers. One runs over the hardware layer, mainly used in the data centers, and one runs above the operating system, used in programs such as VMware or VirtualBox. Above this Hypervisor layer, there runs the block of guest OS. Say you want to run three different types of applications in complete isolation from each other — you would need to spin up three separate VMs. The hypervisor directly controls these three VMS.
But now imagine that the three VM had their OS — Linux or windows. For now, let’s say they had Linux operating systems, so each OS is roughly 700mb. We have to spin up three VMs, which occupy approximately 2.1GB of storage on our operating system. On top of that, each guest OS requires its own set of bin/libraries — Python Dependencies, Node modules, etc — to lay the groundwork to run the app. Now, finally, we have our Application layer on top of this, which will typically be the source code for the app you have built.
What is a Container? Containers are an abstraction at the app layer that package code and dependencies together. Multiple containers can run on the same machine and share their OS kernel with other containers, each running as isolated processes in userspace. Containers take up less space than VMs (container images are typically tens of MBs in size), can handle more applications, and require fewer VMs and operating systems.
Docker container architecture
Docker is not magic — it needs some base hardware over which it can run. So the first layer (hardware layer) is common to the virtual machine layer infrastructure. Over this, there’s a host OS. It can be any operating system capable of running Docker. Docker supports all the major Linux distributions and there are ways to run Docker on Windows machines and Macs.
Now for the third layer. There’s something interesting here. The Docker Daemon replaces this layer, which was the Hypervisor Layer in the virtual machine architecture. It’s a service that runs in the background and is responsible for running the Docker container.
Then the Bin/Libray resides in a container for the app and there is source code for the app. The Docker daemon manages all these layers of container. Thus we eliminate the need for a guest OS and we save the amount of memory that was occupied by it. We also save the load that was being put on the machine while running those VMs.
Here, each app is isolated from each other as it has been hosted in different containers while still being on the same host OS.