Even in discussions with people pretty familiar with Docker, I find many are convinced it is only needed for those with significant scaling issues. It's true that Docker is fantastic for scaling services to any level, and it can be ideal for microservice architectures. But those aren’t the only valuable use cases for it.
In this article, I’ll present the value of Docker from the opposite perspective. Rather than the scaling up use case, let's talk about the case for scaling down.
Monoliths vs. Microservices Separation of Concerns
I work for a nonprofit organization called SIL International where I lead our IT Application Development team. As the IT department, we're responsible for several dozen applications used primarily by an internal user base distributed all over the globe. As a result, many of the applications we develop use the same technologies.
Since we have a very small budget (as most nonprofits do), we found it cheapest and most convenient to run many of our applications on the same servers. This led to a tangled messes of monolithic servers that ran several web applications, their databases, and other random services on the same server.
By today’s standards, everyone would agree that is a bad way to operate.
Since one application would have problems and affect other applications, we decided to invest in separating our concerns and move each application to its own set of servers. At the same time, we thought it would be more cost effective for us to move to the cloud rather than run and manage our own data centers. After some price comparisons and consulting with other nonprofits, we decided to go with Amazon and their OpsWorks service to help with automation.
Initially this was great. We moved several of the applications to their own “stacks” in OpsWorks, and everyone was happy. Our developers enjoyed the automated deployments we were able to achieve, and our Ops folks were happy to not support the servers and to have the apps separated. However, this turned out to be more costly than we anticipated, as well as a poor use of resources.
With a small user base distributed across all timezones, we saw a consistently low level of server utilization. Each of our OpsWorks stacks included one elastic load balancer, one NAT server, one micro EC2 instance, and one micro RDS instance. This issue was compounded because we also wanted a staging environment, so each app really got two of these stacks. We’d be fine sharing some of the resources for a staging environment, but with OpsWorks, each stack went into its own virtual private network, so the resources were segmented away from others.
With one year reserved pricing, this configuration cost almost $800 per stack or $1600 per app. While it solved our separation concern, it started to get costly and felt wasteful as our servers sat nearly idle 24/7.
Wouldn’t it be nice if there was a way we could keep our apps separated yet take better advantage of the resources available to us?
Like good nerds, when we caught wind of the Docker buzz a couple years ago, we started checking it out. Everything sounded great, but it didn’t seem applicable to us because we don’t have scaling issues, and most of our applications were not using a microservice architecture. Eventually, we realized that the means by which Docker can scale up so well could just as easily be used to scale down. Thus began our move to Docker.
Now that we’re running many of our apps with Docker on AWS using their EC2 Container Service, our average application uses between 1/6 to 1/4 of a micro instance for compute and memory and runs just fine. We now have the added benefit of running a second instance of each application behind a load balancer for improved availability with minimal cost.
So we’re getting much better utilization of the servers we’re paying for, AND we’re able to separate our applications to the degree we wanted. We’re now able to run a cluster of Docker host servers in a single virtual private network so we can share services where appropriate and separate where needed.
For example, my team’s staging cluster has a single elastic load balancer, a single NAT instance, a single RDS instance, and four small EC2 instances to support 19 applications. All that costs about $1200 a year. So the per app cost for staging is roughly $63. That is a LOT better than $800 for a dedicated OpsWorks stack.
In our production environment, each app gets a dedicated elastic load balancer and RDS instance to avoid single points of failure. So the per app cost goes up a little, but it is still less than it was with dedicated stacks because they can share a NAT instance.
Not only are we saving money now, we have the benefit of redundant instances for increased availability.
It's Not Just About Money
While I understand that money talks, and changes like adopting Docker will most certainly include costs, there are other intangible reasons to consider it.
As an employee of a nonprofit, I work for the organization because I believe in its mission, not because the pay is good. But as a nonprofit, my organization also has the motivation and freedom to explore new technologies to find ways to improve our services and reduce costs. It is this motivation and freedom that leads the company to investing in its employees in a way I’ve never experienced before, coming from a large tech company in Silicon Valley.
As a developer, I love to learn and try new things, and as a manager I want to give my staff the ability to do the same. So I believe not only is there opportunity to save money by adopting Docker like we have, there is also the opportunity to invest in employee personal growth by encouraging them to learn something as valuable as Docker.