Docker is all the rage these days and no matter how much you read about it — you just don't see its purpose.
Many articles compare Docker with Virtual Machines (VMs) and how it's more lightweight and faster than a VM. But that doesn't tell you much if a VM is alien to you, let alone never used one.
The hype is so big though — surely Docker is not just for people coming from the world of VMs? (Hint: it's not)
There's a ton of buzz words being thrown around too — "standardisation", "encapsulation", "isolation", "agility", "accelerated workflows", "integrated development pipeline" — and the list goes on and on. What does all of this mean? And how does it apply to you and the applications you're working on?
Wouldn't it be nice if you could assess a situation and be able to tell if Docker is overkill or just the right tool for the job?
If only you could understand the exact problems Docker tries to solve. Problems that aren't alien to your world. Problems you've experienced yourself.
In this article, I'll illustrate how Docker might benefit you. Without buzz words. Using terminology from your vocabulary and clear language that you can understand.
I'm not going to list a bunch of features and let you figure out which real-world problems they solve. Instead, I'm going to flip it around and portray the situations where Docker comes into play.
Perhaps some of them will resonate with you and maybe, just maybe, you'll start using Docker in your projects and will love and rave about it like everyone else. Or perhaps not, and that's totally fine.
Most developers run into errors at some point when they try to deploy their application. The majority of these problems stem from imparity between the development and production environment.
I can't deploy my app
A module seems to be missing
There's some vague errors with node-gyp and node-sass
Babel modules didn't install
Everything is yelling at me and I don't know what to do
I'm deep in dependency hell
We write applications that are deployed in environments much different than that of our laptop. If all cloud servers were running on MacBook Pros and macOS (sorry Windows devs 😘), then Docker would probably not exist.
The reality is different, however, and servers in the cloud have different requirements than a modern laptop that needs to be slim, lightweight and look fashionable. Even if you're developing on a PC running Ubuntu, you're bound to have different dependencies and configurations than the environment your application will live in. Your laptop will never be an exact copy of the production server.
In addition to that, your Node.js application likely depends directly or indirectly on native C++ addons. These are compiled into binaries that are specific to the operating system, system architecture and Node.js version. Therefore, copying the node_modules folder from your machine to the production server will usually not work. You need to install your dependencies on the production server so they'll compile for the right environment.
In companies where the person deploying the application is different from the one who has developed it, the problems around deployment are magnified. The sysadmin/DevOps blames the developer for providing him with a shitty application that doesn't work, and this causes friction between the two roles.
Docker solves this problem by wrapping your application and everything it needs in a self-contained image. Docker images are portable and can easily be sent to the production server, or other developers, that can run your application with a single command. Regardless of the host environment, your app will just work.
For the same reasons you shouldn't mix tequila with beer when drinking alcohol — you shouldn't run applications with overlapping dependencies on the same server.
I'm not talking about dependencies inside the node_modules folder since that problem is already solved by NPM. I'm referring to dependencies your application relies on outside of the NPM ecosystem. Node.js, MongoDB/PostgreSQL, Redis, ImageMagick and other libraries installed on the operating system.
Mixing these together will cause you such a massive headache that you wished you got on a plane to your cloud provider's data centre, found the physical hardware where your application lives, and banged it to pieces with a hammer. (Disclaimer: You didn't get the idea from me)
Ok. Let's say you're working on a new application.
You're using the latest Node.js version because it comes with all the great language features. The app is ready to be witnessed by the outside world, and you want to deploy it on the VPS you have already bought. On that server, however, you already have an application running that uses an older Node.js version.
Ideally, you'd upgrade the Node.js version on the server and move on — but that might break the legacy app. Also for many possible legitimate reasons, you're stuck with the older Node.js version for now.
How do you deploy a new application that relies on a different Node.js version than the one already present?
You can use a Node.js version manager, and that will work. What if they also rely on different versions of MongoDB? Or Redis? You can use version managers for those as well or solve the problem with some bash-fu. However, we're at a point where this starts to become a fragile mess that will make you pull your hair out sooner or later.
Docker makes it trivial to run many applications on a single server without them ever interfering with each other's dependencies. Each application is entirely self-contained and isn't aware of the world outside of its own container. Therefore, installing and updating dependencies is as easy as if you would have a single application running on the server.
This approach also keeps your operating system clean when you decide to remove an app later on. When you no longer need an application, you simply delete its image, and you won't be left behind with any temporary or configuration files on your host.
Every developer that has deployed an application receiving traffic from the outside world has at least once worried about hackers getting into the system.
Making your application accessible by your users means that hackers will try to find ways to exploit any vulnerabilities they can find.
Depending on the severity of the hack, the intruder could get ungranted access to the server. When that happens, it's game over. Everything on that server — ssh keys, databases, environment variables and other applications will be easy prey for the hacker.
When your application runs in an isolated container, the damage is at least controlled.
Your application doesn't have direct access to other containers or the filesystem on the host operating system. It can only reach within the boundaries of its own container, and as far as it's concerned, there is nothing beyond that.
This doesn't mean you don't have to follow security best practices — that you should always do. Nor does it mean bad things can't happen when your application runs in a container.
What it means is that if your house catches fire, at least the other houses are far enough, so the whole neighbourhood doesn't have to burn down. The insurance company is happy.
An intruder getting into your containerised app is like a thief landing on an island without a way to reach other islands (applications), or mainland (host).
If you haven't experienced any problems with deployment at all and you're satisfied with your current process, then it's totally fine not to use Docker.
If you're using a PaaS like Heroku and you're happy with it, keep rockin'.
You don't have to follow the hype by any means, and you don't have fix what's not broken.
Just remember in what situations Docker might come in as a handy tool. And when you find yourself in a similar situation, you'll know to reach for it.
If you have already experienced some of these pains, then you know what to do. Get up to speed with Docker and fix your deployment process, so you have more time building features that matter 💫.