What do containers contain ?
Containers is the new buzzword around, just about everywhere, with Docker being the most popular one. In fact Docker has become the de facto container, so much so that, the word Docker has become synonymous with container. As per the Docker website, they have had 12 billion pulls of Docker as of last year. I’ve heard more than once that Docker will do to application delivery what Java did to programming. That’s quite a tall order but one that might just be true. So let’s peek into the container world, shall we, and see what goodies a container contains really ?
As per Docker:
A container image is a lightweight, stand-alone, executable package of a piece of software that includes everything needed to run it: code, runtime, system tools, system libraries, settings.
However in conversations, the most common description of a container you hear, is that it is a lightweight Virtual Machine (VM). It is close but not entirely accurate, architecturally speaking. Docker points out that the reason that containers are mainly perceived as lightweight containers is because of two fundamental similarities between Containers and VMs.
It’s easy to connect those dots as both technologies share some characteristics. Both are designed to provide an isolated environment in which to run an application. Additionally, in both cases that environment is represented as a binary artifact that can be moved between hosts. There may be other similarities, but these are the two biggest.
Although not sacrilegious to think of containers in terms of a VM, it is really more appropriate to think of containers as a way to package and deliver software in a portable manner that can run on any host as long as it container enabled. Bake an image once and run it anywhere!
Containers vs VMs
Containers and VMs are both vehicles for executing processes within a virtual construct. Very often this leads to the exercise of comparing them in a quest to decide on the question – which of the two is the most appropriate for your application ? With that in mind, let’s look at what is different between the two.
If I were asked to sum it up in one sentence it would be that (in terms of abstraction):
- Virtual Machines virtualize the hardware
- Containers virtualize the OS
You can see from the below figures that a container runs directly on the host OS and does not need an OS per container as it shares the OS among all the containers that reside on that host. A VM on the other hand runs on top of a virtualization agent called the hypervisor and each VM needs a fully independent OS. As a result, a VM is much more heavyweight in terms of resource usage and startup times. A container is much lighter with a smaller footprint and starts up in seconds compared to minutes for a VM. Given the small footprint, it is not unheard of to spin up 100s of containers per machine. VMs cannot scale to this rate.
Another difference (in principle really) is that VMs typically host a full stack of applications, more monolithic in nature – perhaps a LAMP stack and any other supplementary services on a single instance. Containers typically host only a single well defined application.
When comparing VMs to containers, the analogy that Docker uses is one of houses (VMs) to apartments (Containers). Both offer protection and isolation. However unlike VMs which are completely self contained and do not share resources, containers are built around shared infrastructure. Containers are built in a layered manner with each layer adding on only what is required over the previous and thus it is very flexible and lean vs the VMs which require a full blown OS and applications required to manage it, which might result in an unnecessarily bloated image.
A few other noteworthy points – Containers are ephemeral or transient in nature as compared to VMs. They are more portable and flexible as well.
So if the application is modular or composed of microservices then using containers is a no brainer. For monolithic applications, the answer is – it depends. The Docker documentation has a good checklist to use when deciding between containers or VMs per your needs. In reality hybrid approaches are common too – Containers running on VMs (especially when cloud based).
Containers and Microservices
A core principle of containers is that of the good old Unix philosophy – “Do one thing and do it well”. Docker documentation has this recommendation with regards to it :
Run only one process per container. In almost all cases, you should only run a single process in a single container. Decoupling applications into multiple containers makes it much easier to scale horizontally and reuse containers.
Staying true to this principle, a container should host a single service per container. Guess what else also lives and dies by this same principle ? That’s right, it’s microservices. Although it is not mandatory to run microservices in containers, they are complementary and a natural fit to containers. Containers establish boundaries around resources. The boundary leads to isolation, not only in terms of software but also in terms of teams and ownership. The boundary also helps define distinctly what it is that this container image represents in terms of service functionality. It goes without saying that it provides for independent deploys. All of these align perfectly with the principles of a microservice as well. A microservice also defines a boundary, is owned by a single team, provides a distinct well defined service and is independently deployed. So there really is no overhead in containerizing microservices and it makes a microservice architecture that much easier to manage operationally.
An interesting perspective on the synergy between microservices and containers is laid out in the book “Microservice Architecure, Aligning Principles, Practices and Culture “. In addition to recommending that microservices use containers for efficient devOps, the authors go as far as to say that containerization will in fact drive the adoption of microservices by enterprises rather than microservices leading to the adoption of containers. The reason being that containers make practical sense only when a monolith is broken down into independent components that can be run in individual containers vs trying to containerize a monolith application in its entirety in a single container.
The way we like to look at it, Docker containers and microservice architecture are two ends of the road that lead to the same ultimate goal of continuous delivery and operational efficiency. You may start at either end, as long as the desired goals are achieved.
Hosting one microservice per container is really the way to go. In addition to all the benefits discussed above, the container ecosystem is growing rapidly and maturing with wide support from the industry and opensource community. With container orchestration systems like Kubernetes, which Docker is also supporting now, we can also replicate, scale and orchestrate the containers readily and is a broad topic by itself, for another post.
Note that this article is part of the Microservices series. You can read the previous ones here : Prelude, Introduction, Evolution, Guiding Principles, Ubiquitous Language, Bounded Contexts, Communication Part 1, Communication Part2, Communication Part 3, Communication Part 4, Communication Part 5, Kafka, Time Sense
Borg, Omega and Kubernetes This is a really good paper from Google about the history and lessons learned in their containers journey
Container security is a topic of concern and this post from Google is a good place to start