Docker containers provide a similar service to virtual machines, providing an isolated environment for applications to run in, but they are basically two different technologies. We discuss the differences and what makes Docker so useful.
What makes Docker so useful?
The main purpose of a virtual machine is to partition a large server into smaller pieces. The important part is that it isolates processes running on each virtual machine. For example, your hosting provider may have a 32-core machine and divide it into eight 4-core virtual machines that it sells to different customers. This reduces the cost for everyone, and they are great if you are running many processes or need full SSH access to the underlying hardware.
But if you only run one app, you can use more resources than necessary. In order to run the individual app, the hypervisor must spin up an entire guest operating system, which means that the 32-core machine runs eight copies of Ubuntu. In addition, you have virtual machine overhead for each instance.
Docker presents a better solution. Docker containers offer insulation free of charge for virtual machines. Each container runs in its own environment, divided by Linux namespaces, but the important thing is that the code in the containers runs directly on the machine. There is no emulation or virtualization involved.
There is still a bit of overhead due to networking and interfaces with the host system, but applications in Docker usually run close to metal speeds and really much faster than your average VPS. You do not have to run eight copies of Ubuntu, just one, which makes it cheap to run multiple Docker containers on one host. Services such as AWS Elastic Container Service and GCP’s Cloud Run provide ways to run individual containers without providing an underlying server.
Containers package all the dependencies that your app needs to run, including libraries and binaries that the operating system uses. You can run a CentOS container on an Ubuntu server; they both use the Linux kernel, and the only difference is the included binaries and libraries for the operating system.
The main difference with Docker containers is that you generally do not have SSH access to the container. However, you do not need exactly that – the configuration is handled by the container file itself, and if you want to make updates, you must press a new version of the container.
Since this configuration all happens in code, you can use version control as Git for your server software. Because your container is a single image, it makes it easy to track different buildings of your container. With Docker, your development environment will be exactly the same as your production environment, and also the same as everyone else’s development environment, which alleviates the problem of “my machine is broken!”
If you want to add another server to your cluster, you do not have to worry about reconfiguring the server and reinstalling all the dependencies you need. Once you have built a container, you can easily spin up a hundred instances of that container without much configuration. This also allows for very simple automatic scaling, which can save a lot of money.
Disadvantages of Docker
Of course, Docker does not replace virtual machines at any time. They are two different technologies, and virtual machines still have plenty of advantages.
Networks are generally more involved. On a virtual machine, you usually have dedicated network hardware exposed directly to you. You can easily configure firewalls, configure applications to listen on certain ports, and run complex workloads such as load balancing with HAProxy. On Docker, since all containers run on the same host, this is often a little more complicated. Usually, however, container-specific services such as AWS’s Elastic Container Service and GCP’s Cloud Run will provide this network as part of their service.
Performance on non-native operating systems is still on par with virtual machines. You can not run a Linux container on a Windows host machine, so Docker for Windows actually uses a Windows Linux World Cup subsystem to handle running containers. Docker essentially provides a layer of abstraction on top of the virtual machine in this case.
Persistent data is also a bit complicated. Docker containers are designed to be stateless. This can be fixed with volume brackets that mount a catalog of values in the container and services such as ECS allow you to mount shared volumes. However, it does not affect the storage of data on a regular server, and you do not really want to try to run a production database in Docker.