6 min read

Docker & Container Demystified

Docker & Container Demystified

Are you feeling like a fish out of water when it comes to Docker and Containers? Don't worry, you're not alone. Even some of the most tech-savvy folks can get lost in the sea of jargon and confusion. But fear not, my friend, because I'm here to help you navigate these uncharted waters and show you how to swim with the Docker school of fish.

Containers have become a game-changer in modern software development and deployment. They provide a lightweight, portable, and efficient way to package and run applications, regardless of the underlying infrastructure. And Docker, the leading container platform, has made it easier than ever to build, ship, and run containerized applications. In this blog, we'll explore the fundamentals of Docker and Containers, and how they can help you streamline your development and deployment workflows.

Alright, let's start by digging into some of the problems that pop up when you don't use a docker/container approach and how these technologies came to the rescue to solve those issues.

Problem 1

Let's say we have a web application project called "MyWebApp" developed by a team of 5 developers - John, Sarah, Tom, Lucy, and Michael. Each of them has their own local development environment set up on their personal computers to work on the project.

John uses a Windows 10 operating system, while Sarah and Tom use macOS, and Lucy and Michael use Ubuntu Linux. John prefers to use the IntelliJ IDEA IDE, while the rest of the team uses Visual Studio Code.

Now, in order to develop the MyWebApp project, each developer needs to have the required dependencies installed on their local machine. For example, the web application is built using Node.js and Angular framework, so each developer needs to have Node.js and Angular installed on their local machine. But the version of Node.js and Angular may differ based on each developer's preference or the requirements of the project.

Additionally, some developers may need to install other software tools, libraries, or plugins based on their specific tasks in the project. For example, John needs to use the Windows Subsystem for Linux (WSL) to run some Linux-specific scripts in the project, while Sarah needs to install a particular plugin in Visual Studio Code for debugging.

As you can see, setting up a local development environment for a team project can be a challenging task as each developer's environment may differ from each other in terms of dependencies, operating system, and other configurations. This can lead to compatibility issues, software conflicts, and other problems that can hamper the productivity of the team.

Now imagine there is a box where we can put all the necessary dependencies, libraries, and configurations required for the MyWebApp project. It is like a self-contained package that can run on any computer or operating system.

Instead of each developer having to set up their own local development environment, they can simply use the same box to work on the project. This ensures that everyone is working with the same set of tools and configurations, which reduces the chances of compatibility issues and software conflicts.

In the case of MyWebApp project, the box can have Node.js and Angular installed along with other required libraries and plugins. John can still use IntelliJ IDEA IDE and Sarah and Tom can still use Visual Studio Code since the box has everything they need to work on the project. This will give an added advantage of isolation as well. The box will run  in its own isolated environment, with its own set of dependencies and configurations. This means that if one developer's environment is misconfigured or has conflicts, it will not affect the rest of the team's development environment. In addition, since each box is self-contained, it can be easily moved from one environment to another without any compatibility issues. I should say it's not a box its a magic box! And this magic box is called container!

Problem 2

Suppose you have a web application that you want to deploy to multiple environments, such as development, testing, and production. Each environment has different requirements, configurations, and dependencies.

For example, in the development environment, you may want to use a local database such as SQLite, while in the testing and production environments, you may want to use a remote database such as MySQL or PostgreSQL. Similarly, in the development environment, you may want to use a lightweight web server such as Flask, while in the production environment, you may want to use a more robust web server such as Apache or Nginx.

In addition, each environment may require different versions of the dependencies, such as Python libraries, JavaScript frameworks, or system utilities. For example, in the development environment, you may want to use the latest version of a library for testing new features, while in the production environment, you may want to use a stable version for reliability.

Deploying the application to each of these environments can be a complex and error-prone process. You need to ensure that the dependencies are installed correctly, the configurations are set up properly, and the application is tested thoroughly. Any mistakes or inconsistencies in these steps can result in downtime, errors, or security vulnerabilities.

To manage these complexities, you may resort to creating multiple virtual machines, one for each environment. However, this approach can be resource-intensive, as each virtual machine requires its own operating system, disk space, and memory. Furthermore, updating or scaling these virtual machines can be time-consuming and error-prone.

Alternatively, you may try to manage the dependencies and configurations manually, by editing configuration files or running scripts. For example, imagine you have an application that requires a specific version of a certain library to function correctly. You manually install that library on your development machine, and then you copy the configuration files to your staging environment. However, over time, you may forget to update the configuration files or install updates to the library on the staging environment, resulting in inconsistencies between the environments. This can lead to errors, downtime, and other issues that can be difficult to troubleshoot.

Furthermore, manual configuration management can become tedious and time-consuming as the application scales and the number of environments increases. Keeping track of all the dependencies and configuration files across multiple environments can become a daunting task, and it's easy to miss important details or make mistakes.

Overall, manually managing dependencies and configurations is a risky and inefficient approach to application deployment, especially in complex environments with multiple variables to consider.

Now if we can use the magic box aka container we discussed in Problem 1 here as well, wouldn't it be great? Just use that magic box on every environment & all your manual responsibilities to sync the dependencies and configurations will go away!

So, we just talked about how containers are like these magical boxes that keep all our dependencies and configurations in one place, making it possible to run them anywhere. But, I realized that we haven't even talked about Docker yet. So, what is Docker exactly?

Think of Docker as a tool that helps us create and manage those magical containers we were just talking about. In other words, Docker provides us with a way to package up all of our code and dependencies into a single container, so that it can be easily deployed to any environment. So, while containers are the magical boxes that keep everything contained and portable, Docker is the magic wand that helps us create and manage those containers.

We can sum it up with the following example -

Imagine you're a street food vendor in India, and you want to make your famous dish - let's say it's pav bhaji. Now, to make this dish, you need a lot of ingredients - potatoes, tomatoes, onions, spices, bread rolls, and so on. And you also need some cooking tools - a stove, a pan, a spatula, and so on.

Now, imagine you're setting up your stall at a local fair or festival, and you want to make pav bhaji there. But you don't want to carry all those ingredients and cooking tools with you - it would be too heavy and cumbersome, and you may not have access to all the same ingredients at the fair.

So, what do you do? You pack everything you need into a single container - let's call it the "Pav Bhaji Container". In this container, you have all the ingredients, the cooking tools, and even some instructions on how to prepare the dish.

Now, when you arrive at the fair, you simply open the container, and everything you need is right there - no need to worry about finding the right ingredients or tools. You can quickly prepare your pav bhaji, serve it to the hungry customers, and hopefully make a good profit!

In this example, the container is like a self-contained, portable environment that includes everything you need to make your dish. And Docker is like the tool that helps you create and manage that container, making it easy to move it from one place to another.