The Essence Of Docker In Modern Development

logo

Intro

When building software, we sometimes find ourselves in a confusing situation: our code works perfectly locally, but when we deploy it to a remote server, it breaks or some features don't work as expected. Sometimes, someone else might try to run your code on their local machine and encounter errors. They reach out to you, and when you test it again on your machine, it works perfectly. Frustrated, you naively exclaim, "But it works on my machine!" This doesn’t help, so you both spend hours debugging. After wasting precious time, you realize the issue was due to different OS versions, despite claims of 'no breaking changes.' It could be anything: your machine might be faster, or your friend's machine might be slower, it could be differences in dependency versions, and many other factors.

Docker solves this by providing a safe container for your code that guarantees it will run without issues, no matter where you decide to run it.

Here's a simple analogy to help you grasp the concept. Imagine you're at a beach and you build a sand house. It stands well on the sandy soil, but what happens if you move it to a smooth surface, like tile? The chances of the sand house standing as it did on the sandy beach are low because the textures of the two surfaces are different. The sandy soil is wet and has a lot of friction to hold the sand house together, but the tiles are mostly dry and smooth, so the sand house will struggle to find stability and eventually break.

Docker is like a magical box that you can build your sand house in and move it to any surface, ensuring that the integrity of your sand house is never compromised.

Docker uses containerization technology to achieve this. A Docker container includes your application and all of its dependencies, libraries, and configuration files needed to run it. This ensures that your application behaves the same way regardless of where it’s executed, whether it's on your local machine, a colleague's machine, or a production server.

Containers are lightweight, portable, and isolated from each other, allowing multiple containers to run on the same host without interfering with each other. This makes Docker a powerful tool for developing, testing, and deploying applications in a consistent and efficient manner.

I might have oversimplified this with the sand house analogy, but that's how I understood the essence of Docker.

Docker ensures that your code runs as expected in any environment by isolating it into a container that includes all the configurations and system requirements needed to keep your app running consistently anywhere.

How to Containerize a Node.js application

In this section, we'll see how a very simple Node.js application can be containerized, and the process we follow to achieve this is basically how it’s done for any type of Node.js app.

First things first, you have to install Docker on your local machine. Go to https://www.docker.com/get-started/

docker website

Click on the Download button to download the right Docker installer for your OS.

When the installer is successfully downloaded, run the installer and follow the steps to complete the installation on your machine. Docker did a great job in making the process as simple and intuitive as possible, so it should be straightforward.

After that, create a project folder for your Node.js app. You can name the folder anything. I'll name mine dockerize-101.

> mkdir dockerize-101
> cd dockerize-101

Next up, open the folder in your IDE and initialize a Node.js project with the following command:

npm init -y

Next, install express then create an index.js file and paste in the code below:

const express = require('express');

const app = express()

app.get('/', (req, res) => {
  res.status(200).json({
    message: 'Hello Docker'
  })
})

const PORT = process.env.PORT || 5000

app.listen(PORT, () => {
  console.log('Server running at Port', PORT)
})

This simply uses the express framework to create a server which listens at PORT 5000 and a GET endpoint that responds with {"message":"Hello Docker"} when called by the client. That's our app.

After that, open up the generated package.json file and add a start script which will be used to start up our server:

"scripts": {
   "start": "node index.js"
},

Setting Up Docker

  • Create a file in your project directory named Dockerfile and add the following:
FROM node:18-alpine

WORKDIR /app

COPY . .

RUN npm install

CMD [ "npm", "start" ]

EXPOSE 5000
  • Create a .dockerignore file and add this to it:
node_modules
  • Build your Image
docker build -t <image-name> .

You can replace <image-name> with anything. its just a human-readable tag for your image. i'll call mine getting-started.

  • Start your app conatiner
docker run -dp 127.0.0.1:5000:5000 getting-started
  • Confirm app container is running

You can confirm if your app is running by going to localhost:5000 or going to the Docker Desktop app and inspecting the Containers tab.

You can also check from the CLI by running this:

docker ps

If its running, you should see something like this:

ps

And there you have it. Your app is successfully containerized and can be run anywhere.

Summary

In this article, we explore the importance of Docker in modern software development. Docker helps eliminate the "works on my machine" problem by using containerization technology to create portable, consistent environments for running applications. We then provide a step-by-step guide on how to containerize a simple Node.js application, ensuring it runs seamlessly across different environments.