What is Docker?

The elixir for Dependency Hell

Yevgeniy Zhitomirskiy
7 min readApr 12, 2019

Docker, you say?

Before we dive into what Docker is, it’s important to first understand what a software application is. Without getting too deep into the weeds, a software “app” is just computer code. To run an app locally on your computer, you need to have the app’s dependencies installed on your machine. Often times in the software engineering world, some programs depend on others. So what’s the problem with these app dependencies, you might ask? It turns out, they can be quite cumbersome! To help get a clearer picture about how Docker combats dependency issues and drives modern software development, let’s imagine the following scenario:

Dependency Hell

Jack and Jill are software developers (“devs”) who write software both as a hobby and a profession. A common practice for devs who want to share an app they built is to store the code for their app in a code repository, such as https://github.com and include instructions on how to run that app.

Over a random weekend, Jack decides to write a small app and send it over to Jill so that she can run it locally and provide feedback. He shares the app code via Github and invites Jill to try it out. Jill notices that the instructions Jack included on his Github page ask the user to install a few dependencies to run Jack’s app: “To run my app, you need MySQL version 8.0 installed on your laptop”. “Not a problem!” says Jill, as she checks to see what version of MySQL she has installed on her machine. But low and behold, Jill has version 5.7. If she tries to run Jack’s app with her current version of MySQL, it won’t work! Bummer. So Jill spends some time finding and installing version 8.0 and eventually gets Jack’s app to run smoothly on her machine. This, of course, is a simplified example. What if Jack’s app was more robust and was dependent on Jill having specific versions of Ruby 2.5.5, MySQL 5.6, JavaScript 6, and Python 2.7.16 installed on the user’s machine?! Devs often refer to this situation as Dependency Hell. This is a bottleneck for the dev being able to share his/her work with others because the user needs to waste extra time installing specific versions of software which can quickly become a tangled mess. (Not everyone’s computer is configured the same!)

(source)

But it works on my machine!

In today’s world, devs not only tackle dependency hell at home but also in the workplace. Software engineers working for companies like Netflix, for example, face challenges with dependencies on a much larger scale; specifically related to deployment environments. You can think of environments as separate isolated spaces to run code in (such as a laptop or a server). When you visit https://netflix.com to watch re-runs of The Office, you (the user) are interacting with the live (production) environment. If you wanted to develop a new feature for the Netflix application, you wouldn’t go messing around with the production environment; what if your new code breaks something and the whole app goes down?

According to Wikipedia, Google’s 2010 revenue was $29.321 billion. Given that figure, they would lose, on average, $55,785.77 for every minute they are down. (source)

Thus, you would first work on your new feature in a playground, “development” environment, get it to pass code tests, and then push that code to “production” (given that everything works…) for live users to interact with. Now you might ask: what are the chances that these two environments (dev and prod) are configured exactly the same? Who knows for sure? Going back to our previous example, let’s play out another scenario (one that can be severely detrimental to a business):

Let’s imagine that Jack works as a software developer for Netflix and is tasked with implementing a new feature. He writes the code and it runs smoothly on his laptop in the development environment. Jack is proud of his work and everyone is excited to push his new feature to the production environment so that the live users can have a better experience with the app. “Ship it!” yells Jack’s manager. So Jack happily deploys his code to production — except something goes terribly wrong… everything breaks! Panic rushes through Jack’s body; a trickle of sweat rolls down his spine. “I broke production — but how could it be? IT WORKED ON MY MACHINE!” (This phrase is all too familiar in the software development field.)

(source)

So what exactly happened here? Turns out, there was a mismatch between the dev and prod environments; the version of Python in dev was 2.6.9 but 3.7.3 in prod. And Jack’s new feature strictly depended on Python being 2.6.9 for the code to work properly! This hypothetical scenario is actually quite common in today’s world, from small local projects to large scale apps that we all use today. What if Jack wrote an app that works on Mac/Linux machines and wants to share it with Jill, but Jill has a Windows PC? How much time must Jill waste to figure out how to configure her machine properly to run Jack’s app?

If only there was some way for devs to share their apps with everyone else without having to worry about Dependency Hell and it’s ugly cousin “It works on my machine!” syndrome. Is it possible to achieve a consistent standard format for sharing and running apps?

You bet there is. Enter Docker!

(source)

Docker in Layman’s Terms — Containers 101

Docker is the world’s leading software containerization platform. That’s a mouthful, let’s maybe take it down a notch and try again? Docker is a software tool that simplifies creating, deploying, and running applications. Docker accomplishes this feat by leveraging the power of containers. So what the heck are containers then, you might ask? Again, without getting into the weeds, containers are application code grouped with the application’s dependencies. With their help, a developer like Jack can bundle his app with everything required to get it up and running and to send it to others as one final package.

TL;DR -> containers give you instant application portability!

So Docker manages these application containers; if Jack and Jill both have Docker installed on their machines, then Jill can run Jack’s app on her machine as consistently as Jack can on his own. (EVEN THOUGH JACK HAS A MAC AND JILL HAS A PC!)

Docker in the Weeds — What’s The Magic?

For Jack to utilize the power of Docker, all he has to do is write a small file and add it to his application code: the Dockerfile. The Dockerfile is like a set of instructions for getting Jack’s app up and running inside a container. When executed correctly, these instructions build a Docker image that satisfies the dependencies for Jack’s app. So Jack notes down every step needed to get his app running and adds them to his Dockerfile:

  • Step 1: Copy this file requirements.conf from Jack’s desktop to the Docker image.
  • Step 2: Then, install MySQL 8.0 on the image.
  • Step 3: Finally, run this command exec nginx -g “daemon off;” on the image.

And just like that, Jack’s Dockerfile is complete. Great! But what’s next? How does the Dockerfile help Jill to run Jack’s app on her laptop?

docker build, docker push, docker run

Following the creation of the Dockerfile, Jack can run this command:

docker build . -t jacks-app:1.0

to execute the instructions in the Dockerfile and build his app’s Docker image (tagged version 1.0).

Jack can then run this command:

docker push jacks-dockerhub-repo/jacks-app:1.0

to push his built image to a public Docker Image repository (similar to Github) called Dockerhub so that others can discover it.

And finally, Jill (who has Docker installed on her laptop) can run this command:

docker run jacks-dockerhub-repo/jacks-app:1.0

to:

  1. Pull down Jack’s Docker image to her laptop.
  2. Start a container based off of that image and have Jack’s app running locally. (without having to install his app’s dependencies because they were already pre-baked into Jack’s Docker image.)

So going back to the nightmarish situation over at Netflix; assuming that Docker is installed both on his machine and Netflix’s production environment, Jack should have no problem deploying his app to live users! It doesn’t just work on Jack’s machine — it works everwhere that Docker is installed. Catastrophe avoided!

Play Tetris in Seconds!

Let’s check out an example to highlight the awesome power of Docker.

This is the code, Dockerfile, and Docker image for a Tetris app that I found on the internet (source/credit):

Try it for yourself

  1. Install Docker.
  2. Open the Terminal (Mac/Linux) or Command Prompt / PowerShell (Windows) applications.
  3. Type in this command and hit Enter:
docker run -d -p 80:80 uzyexe/tetris

4. Open a web browser like Google Chrome.

5. Navigate to:

http://localhost

6. Enjoy Tetris in minutes! (don’t forget to hit the Spacebar and arrow key to play the game)

7. When you’re done, type in this command and hit Enter to clean up:

docker kill $(docker ps -a | awk '{print $1}')

And there you have it folks; Docker in all it’s glory. This powerful tool is revolutionizing modern software development by helping developers to escape dependency hell, eliminate “It works on my machine!” syndrome, and speed up application delivery time.

Enjoyed the story?

Feel free to check out one of my other posts “What is DevOps?

--

--

Yevgeniy Zhitomirskiy

DevOps/SRE Engineer with a passion for automation, CICD, Infrastructure-as-Code, and cloud architectures