Containers are simple, but harder to explain. Fundamentally, containers are a virtualization technology and they share a lot of common ground with virtual machines, however the biggest difference between the two is where the abstraction occurs.
A VM hypervisor exposes a set of virtualized hardware components like a virtual network card, a virtual hard disk, a virtual graphics processing unit, virtual RAM, and so on. These virtual components can then be used to create virtual machines on which an operating system can be installed just as if it was being installed on real hardware. Virtual machines enable versatility for a given set of hardware. A single physical computer can run potentially dozens of different operating systems at the same time and then run apps within those virtual machines. For instance, a Mac running VMWare Fusion can simultaneously run Linux and Windows while the guest OS is Mac OS.
Containers on the other hand move the abstraction up to the operating system level. Instead of providing virtual hardware, containers provide a virtual kernel. The virtual kernel provides all the API’s that applications use to run such as a file system, memory management, an API for device I/O and so on. The tradeoff with containers to virtual machines is that an application running in a container is specific to the kernel being exposed, be it the Windows kernel, the Linux kernel, or the Mac OS kernel. Usually, this tradeoff is not a showstopper for applications.
How do I choose?
Explaining the technical differences between Containers and VM’s is helpful because it gives context to some of the fundamental differences between VM’s and containers. Because containers do not contain an operating system, they can be rather small. Likewise, they can be easily scaled and distributed. The advantage of containers is that users can get better application density for a given environment because it eliminates the need for a multiplicity of operating systems on the same system. Likewise, they start very quickly because they do not have to boot an operating system.
Sometimes the choice to use containers or virtual machines isn’t completely wrapped up in its intended use. There a myriad of other factors that can influence a decision that relate to corporate culture, existing infrastructure, familiarity with one or the other, and so on. Barring these sorts of factors, there are Scope, Size, and Scale.
Scope – One of the key decision points for when to or not to use containers is the nature of the application. Containers are aimed at applications that are not necessarily particular to the environment they are running in. There are some use cases for containers wherein the containers are tailored for the given environment, but the mainstream use cases are for those that seek to run an application anywhere regardless of the infrastructure. So, applications such as embedded systems, infrastructure, and so on are usually not a good case for containers. Using containers for things like web services, web applications, small databases, caching services, network daemons and so on are ideal.
Size – Size is another important factor for containers. By Size, we’re talking about the size of the application in terms of compute resources. Applications range from things that can run on minimal compute resources such as a Raspberry Pi to applications that require multiple, multi-core computers with hundreds of gigs of RAM. Docker is more ideal for applications that do not need more than a single machine to run and even more so when the application can perform well on a computer hosting potentially dozens of other apps. One area where containers have found wide spread usage is in the area of microservices. In the container context, each container runs a single service and nothing more. Each service can be scaled horizontally quickly with containers. On the other end of the spectrum would be something like database clusters, which require multiple machines.
Service Model – One of the biggest paradigm shifts from virtual machines to containers concenrs which service model is used to deploy and manage environments. Virtual machines are typically managed through some sort of orchestration tools like VMWare vShpere. These orchestration services typically are responsible for creating VM and may provide tooling for migrating these to other environments and so on. But these orchestrators though don’t do much in terms of application management or supporting CI/CD pipelines with DevOps. This is mainly because these orchestrators are aimed more at the operations side of things, which has traditionally been to just keep things up and running indefinitely then patch as needed. Modern service models though decouple much of the patching away from the operations side and puts it in the lap of the development side of the most IT operations. Containers enable development to patch software independent of the underlying infrastructure, which means that containers can be deployed at a quick cadence relatively speaking. Doing so means that high levels of automation can be built into application delivery and maintenance.
Example Use Cases
With these three major factors in mind, containers shine whenever the contained app is small and automation is high. Virtual Machines shine whenever an app is large. Naturally though, it’s not always clear and sometimes either one can be a good solution depending on the context.
VM use cases:
Infrastructure – Narrow in Scope, Low in Automation, Large in Size — By their nature, VM’s can do things at the (virtual) hardware level that would be tough for a container to do. This means that they can be used to create network infrastructure, such as firewalls, routers, switches, SAN,’s NAS’s, WAF’s, IDP’s IDS’s general purpose servers, among many other things. Many companies these days are providing “virtual appliances” that are essentially purpose build VM’s that do one or more of the aforementioned tasks.
Container Environment Hosts – Medium in Scope, Low in Automation, Large in Size — Containers need a guest OS to run. While a container environment can run on bare-metal hardware, VM’s are probably more common for setting up container environments. Container environments for production loads usually requires a cluster of machines spread across infrastructure.
Databases– Large in Scope, Medium in Automation, Large in Size — Virtual machines are most certainly going to be more useful for running demanding applications such as large databases or even database clusters. Little benefit will be seen from using containers in such a case because such applications will consume all or most of the resources of a virtual machine, while containers aim at improving density with multiple apps on the same host.
Container use cases:
Modernizing legacy apps – Medium in Scope, Medium in Automation, Medium in Size — Containers enable applications to run consistently across a wide array of environments because containers carry with them the libraries and binaries needed to run an application. Containerizing legacy apps means that apps can take advantage of modern DevOps pipelines.
Microservices – Wide in Scope, High in Automation, Small in Size — Microservices are easily realized with containers because containers are good at adherring to the single responsibility principal.
Web Apps/Web Services — Wide in Scope, High in Automation, Medium in Size — Web Apps and Web Services like those that typically support N-Tier apps play nicely in containers too. A container might host a suite of these services, but they like Microservices can scale rapidly and can also take advantage of DevOps pipelines.
Choosing when to use or not to use containers is not always a clear choice. The bottom line is to keep in mind what one needs to accomplish and take into the considerations that appropriate. It’s not always easy, but objectifying the decision can help bring clarity to the picture.