Dockerize Your First Nodejs App
Tags: docker, beginners, tutorial, node
Published: 2022-09-12 05:18:06

I've used docker a lot of times but containerizing an app felt a lot harder because of all those dockerfiles and docker compose instructions. In this article, I'll try to show you how you can containerize your NodeJS app easily.

## What is docker?
Now first things first, let me tell you what is docker and why one should use it. Docker is a software that uses OS-level virtualization to deliver software in packages called containers. In short, it's just an application that kind of gives you a virtual machine that you can deploy elsewhere, but the main difference between a virtual machine and a docker container is that a virtual machine is a full-fledged operating system running on a virtual environment, which means docker container will have a host OS and a guest OS for every virtual machine. On the other hand, docker containers are just mini virtual machines that share a host OS kernel, which makes them very lightweight. 

Now, why one should use it?

![Docker meme](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/klyqg8ys4goyg3cm7ws0.png)

You might've come across this meme, and that's the exact reason why we use docker. It helps you create applications without worrying about whether it's gonna work in a production environment or not. As long as it works inside the container, you can be sure that it will work anywhere.

## Getting started
Now let's start by creating our first container. For this article, we'll be using a simple nodejs authentication application with MySQL as the database. Here's how the app directory looks like:

![File directory](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bkpmxbr7s6svqc0rqtjo.png)
  
Notice the **docker-compose.yml** and **Dockerfile** in the end? These are the two main superheroes of this article :).

Dockerfile is a set of instructions to build images. You can think of it as manual instructions you might give if you're not using docker like running npm packages, running node app, etc.

Docker-compose.yml is used to run images. It specifies all the services, environment variables, etc. If you're familiar with the docker run command, it's the same thing only. However, instead of executing the docker run command every time in the terminal, you use docker-compose.yml.

Now let's start by creating our Dockerfile. Create a file with the name **Dockerfile** in the root directory of your app and paste the below content into it.

```dockerfile
FROM node:14
WORKDIR /app

COPY package.json .
COPY yarn.lock .

RUN yarn install

COPY . .

CMD ["yarn", "start"]
```

Let me go through each of these one-by-one.

* **FROM node:14**: This describes that your parent image is node version 14. 

* **WORKDIR /app**: This states that your working directory will be /app *inside the container.*
* **COPY package.json .**: It's pretty straightforward and it will just copy package.json to the working directory. The same goes for yarn.lock as well as **COPY. .** where we're giving the instructions to copy everything from the current directory to the working directory.
* **RUN yarn install**: The RUN instruction is used to run a Linux command inside your app. Here we're giving the instructions to execute the *yarn install* command (installs nodejs packages). If you use npm then you'll run **npm install** instead of **yarn install**.

* **CMD ["yarn", "start"]**: The CMD instruction specifies the default program that will be executed once the container runs.

So far so good. Let's create our docker-compose.yml file. 
```yml
version: "2"

services:
  mysql_container:
    container_name: <any custom name>
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: <mysql-root-password>
      MYSQL_DATABASE: <mysql-root-database>
    restart: always
    volumes:
      - mysql_db:/var/lib/mysql

  # API
  app:
    build: .
    ports:
      - 3000:3000
    depends_on:
      - mysql_container

volumes:
  mysql_db: {}

```
Make sure that you're indenting your docker-compose.yml properly. 

* **version: "2"**: States the docker version you're using. 
* **services**: It's the place where we define all the services and their configuration required for your node app to work. As stated earlier, for this article, I'm using a simple node authentication app with MySQL as the database. So here I've defined two services *mysql_container* and *app*. Let's go through them one by one.
    * **mysql_container**: Here I've defined the database. 
        * container_name: You can optionally give the container_name. It's just a custom name for your container.   
        * image: It states which image your service uses. In this case, I'm using MySQL so I've written that over there. If you're using any other database, say for example PostgreSQL or mongo, you can use that as well.  
        * environment: Here you define the environment variables that you put in the .env file. Different images require you to define different environment variables, so if you're using any other database, simply check the docs.
        * restart always: It makes sure that your container restarts when docker restarts or the app crashes.
        * volumes: Here you define the volumes your app is using. By default data in the container will remain until you stop it. After that, the data will be gone. To avoid that you use volumes. Here I've given the path as /var/lib/mysql which is the default DB location in the case of MySQL.

    * **app**: This is our main node app.
        * build: We've previously used dockerfile to give build instructions for our app. Here we're giving the path location to dockerfile. 
        * ports: It will map the host port to the container port. In short, it will expose port 3000 from the container. 
        * depends_on: Since we require a MySQL database before we run our app, here we will instruct that until mysql_container is not running don't run the app.

* **volumes**: Here we defined all the volumes we're using. 

So far so good. The last step is to run this command `sudo docker-compose -f docker-compose.yml up`. This will run our containerized application.

##Conclusion
Docker is one of the coolest things I've learned so far. In the beginning, it might be somewhat difficult to grasp all the concepts, but once you learn it'll make your life a lot easier.

Thank you for reading. I hope you enjoyed this article :).