Heroku is a great solution for developing and deploying applications with minimal fuss. Depending on your needs and priorities, however, a Docker-based CI/CD pipeline might work even better. This article discusses the benefits of migrating from Heroku to Docker, then explains how to make the move.
Heroku vs. Docker
Heroku runs on dynos which they describe as “a lightweight container running a single suer-specified command”. In essence, Heroku abstracts the container away from the user and puts a sandbox up around what it can do. Docker is an opensource container standard that can run just about anywhere. With Docker you get infinitely more flexibility and portability because the user controls the underlying container rather than having that defined by Heroku.
Again, I want to emphasize that I’m not anti-Heroku. Heroku made life much easier for a lot of developers when it debuted a decade ago. It was the first major platform to deliver “application-centric” development by freeing developers from all of the hassles that come with maintaining and provisioning infrastructure. With Heroku, you can push your code out from Git into a pre-provisioned environment with just a few commands.
However, like any platform, Heroku has some limitations. The two big ones are price and inflexible deployment.
You can’t do an apples-to-apples comparison between Heroku and a Docker-based alternative. Heroku and Docker are not the same thing, and there’s no straightforward way to compare the cost of deploying a given number of apps via Heroku to what it would cost to do the same thing using Docker.
But if you’re weighing the price of Heroku’s PaaS against what it would cost to set up a Docker stack on a public cloud, or, even more conveniently, use a Containers-as-a-Service, or CaaS, solution for deploying apps via Docker, there’s a decent chance you’ll find Heroku to be the costlier option. For example, Heroku charges $25/month for a standard Dyno, which has 512 megabytes of memory and one CPU. AWS’s t2.nano instance, which happens to have exactly the same amount of resources, costs only $4.75/month.
Again, this is not an apples-to-apples comparison. The AWS t2.nano instance just gives you infrastructure, which you can use to set up your own app deployment environment. Heroku gives you a load of features in addition to the infrastructure. Plus, I haven’t mentioned storage costs. But the point is that if you’re working on a tight budget, you might get a better deal by paying just for hosting, then setting up your own app deployment pipeline using Docker and a compatible CI/CD platform.
Heroku bundles an app delivery pipeline with the infrastructure required to host it. That’s great if you like one-stop shopping and don’t mind hosting your delivery chain on Heroku’s public PaaS.
It’s a big drawback, however, if you would rather run the delivery pipeline on-premises, or on a private cloud. The most privacy you can get from Heroku is Private Spaces, which basically means running Heroku not with normal Heroku servers, but with network isolation. That’s very different from the privacy (and compliance) benefits you get from keeping things on your own local servers.
When it comes to deployment flexibility, then, Heroku is pretty inflexible. It’s certainly much less flexible than a delivery pipeline built using Docker, which you can run on a public cloud, a private cloud, an on-premises server or even just your local workstation (not that you should do that in production). Heck, you can even now run Docker on Raspberry Pi if you want to.
I’m not saying the Heroku model is flawed. For many users, a hosted, fully managed delivery pipeline is a great value, especially for developers who want to focus just on their apps and nothing else, which is exactly what Heroku is designed to let them do. But if you want more flexibility in how you deploy your delivery pipeline, Heroku’s a poor choice.
From Heroku to Docker
You might be wondering why anyone is still using Heroku at all. If Docker is generally more cost-effective and flexible than Heroku, why didn’t developers migrate to Docker in droves when Docker came out in 2013?
The answer is that Docker was much harder to set up than Heroku, and that is now only beginning to change. In contrast, Heroku is a turnkey solution. You don’t have to spend time building your pipeline or provisioning your infrastructure.
However, as the Docker ecosystem has expanded over the past few years, the road for migrating from Heroku to Docker has become much smoother. In fact, there are now multiple possible roads to get from Heroku to Docker without hitting traffic jams. (That’s the last time I’ll use the road metaphor.)
Let’s take a look at what the possibilities for moving from Heroku to Docker look like today.
The first and probably most obvious approach is to build a Docker-based delivery chain from scratch. There’s nothing stopping you from doing this, and one of the benefits is that you can choose to use whichever components you want for your stack. The choice of integration server, orchestrator, hosting infrastructure and so on is up to you. But, of course, the big drawback is that you have to build all of this yourself. The fact that this DIY approach used to be the only way to migrate from Heroku to Docker is why not everyone migrated from Heroku to Docker three years ago.
A second, more user-friendly option is Dokku, one of the earliest Docker-based alternatives to Heroku. Dokku is a Docker-based PaaS that basically lets you do the same thing as Heroku, but on the infrastructure of your choosing (including on-premises or in the cloud). It’s free, and it’s pretty easy to set up.
So what’s not to love? Mostly the fact that Dokku is not designed for large, distributed environments. Yes, there are ways to scale out Dokku, but once you start investing time and energy in these tricks, you might as well build your own Docker delivery pipeline from scratch. Dokku also has no official user-friendly web interface for administration, which is not ideal (although third-party interfaces exist). Last but not least, Dokku only works on Ubuntu, which is fine if you like Ubuntu (I happen to), but it could be a limitation if you like keeping your deployment options flexible.
CaaS + Docker-Ready CI/CD
The third possible migration path involves combining general-purpose Containers-as-a-Service (or CaaS) platforms, which provide a turnkey solution for setting up Docker-compatible infrastructure, with Dockerized CI/CD pipelines built using platforms like Codefresh. The maturation of both of these kinds of platforms over the past couple of years is what has really changed to make Heroku-to-Docker migration easy.
CaaS platforms let you set up a Docker stack very easily, complete with an orchestrator, registry and everything else you need to deploy your containerized apps. There are now lots of CaaS options available, from AWS ECS and Azure Container Service to OpenShift and Rancher. Some run in the cloud, some run on-premises, and some can run in both places. What this means is that CaaS provides an easy, flexible and free replacement for the infrastructure part of Heroku’s PaaS.
Meanwhile, Docker-ready pipeline management platforms like Codefresh replace the other half of Heroku’s functionality. They let you push code from GitHub repositories with very little effort and deploy it as Docker containers. Then, your CaaS provides a fuss-free solution for running those containers.
Let me say one more time that I like Heroku, and I think Heroku still serves an important niche. But the advent of Docker-based delivery pipelines that are both easy to build and easy to use has narrowed Heroku’s niche. If you’re still using Heroku, it’s worth taking a moment to step back and consider whether the alternative discussed here might be a better fit for your needs.