DEV Community

Cover image for Dockerize a Node.js app with VS Code
Vladislav Guleaev
Vladislav Guleaev

Posted on • Updated on

Dockerize a Node.js app with VS Code

Hello dear coder, welcome to my tech articles series dedicated to Node.js and Docker. Hope you enjoy!

Problem:

You have never used Docker before and you are a JavaScript developer. You want to understand how to use containers together with Node. Lets’ go!

1. Setup

In this tutorial I will be using my favorite editor Visual Studio Code. You will also need Nodejs and Docker installed. In my case I’m using Windows, so I got Docker for Windows from here.

Next command creates a new folder with name test-node-app, then creates npm package file and opens folder in VS Code.

mkdir test-node-app && cd test-node-app && npm init -y && code .
Enter fullscreen mode Exit fullscreen mode

Also please install express to create a server.

npm i express
Enter fullscreen mode Exit fullscreen mode

2. Create basic Node app

Open package.json file and modify it like this:

{
 "name": "test-node-app",
 "version": "1.0.0",
 "description": "",
 "main": "server.js",
 "scripts": {
   "start": "node server.js",
   "test": "echo \"Error: no test specified\" && exit 1"
 },
 "keywords": [],
 "author": "",
 "license": "ISC",
 "dependencies": {
   "express": "^4.17.1"
  }
}
Enter fullscreen mode Exit fullscreen mode

Now add new file with name server.js:

Super basic basic basic app is ready. Now let’s test it locally. Run this command inside app folder:

npm start
Enter fullscreen mode Exit fullscreen mode

You should see following in the console and will be able to access the server on the link http://localhost:8080/

3. Prepare Docker file

To build our image we need a docker file. Create a file with name Dockerfile

touch Dockerfile
Enter fullscreen mode Exit fullscreen mode

And paste this inside:

FROM node:8

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
COPY package*.json ./

RUN npm install

# Bundle app source
COPY . .

EXPOSE 8080

CMD [ "npm", "start" ]
Enter fullscreen mode Exit fullscreen mode

This file tells docker to download Node.js of version 8, create directory for the app, copy there package.json files, run npm install for node_modules, tells which port this app wants to use and finally runs it with npm start.

Uhhh.. a lot yeah? 😮

We will also need a file called .dockerignore. Create and paste following inside:

node_modules
npm-debug.log
Enter fullscreen mode Exit fullscreen mode

4. Build an Docker image

First of all, build our image with this command.

docker build -t test-node-app .
Enter fullscreen mode Exit fullscreen mode

Wait until it finishes and now we can see new image created.

docker images
Enter fullscreen mode Exit fullscreen mode

If you are using VS Code, you can install a very nice Docker extension. It adds a button to side panel which opens Docker explorer. Here you can see all available images and containers. From there you can run, stop and remove containers which is pretty useful.

If you want to remove an image run this:

docker rmi <image id>
Enter fullscreen mode Exit fullscreen mode

5. Run Docker container (finally)

Time to run a container based on our image (our application in isolated environment). The important thing is that we need to tell docker how to map the port. Now we run our container and map 8080 port to 49165.

docker run -p 49165:8080 -d test-node-app
Enter fullscreen mode Exit fullscreen mode

Which means we can now access the app by this url http://localhost:49165/

There is another very useful command to see all running containers:

docker ps
Enter fullscreen mode Exit fullscreen mode

You can stop container by right click in VS Code Docker Extension or by this command:

docker stop <container id>
Enter fullscreen mode Exit fullscreen mode

Now if you run docker ps again you will not see your container running. If you want to see stopped containers you need to add —all flag to the command like this:

docker ps -a
Enter fullscreen mode Exit fullscreen mode

If you still have some questions you can easy refer to official documentation here.


🚀 If you read something interesting from that article, please like and follow me for more posts. Thank you dear coder! 😏

Discussion (21)

Collapse
bassemmohamed profile image
Bassem Ibrahim👨‍💻🇪🇬

Great article 👏, I remember wanting to dockerize a NodeJS server before. I managed to do it, but I struggled with the mysql database.

Ummm, Interesting topic for a future article maybe? Just saying 🖐️😂

Collapse
vguleaev profile image
Vladislav Guleaev Author

I plan to do the same but with MongoDb :) thank you for the feedback

Collapse
quinncuatro profile image
Henry Quinn

What exactly are you having problems with, @Bassem?

Collapse
bassemmohamed profile image
Bassem Ibrahim👨‍💻🇪🇬

I read about it online for a while first. Everyone was saying that it is better to have the database as a standalone image. So I got myself an Ubuntu MySQL dockerfile off the internet to create that DB image.

Now I have 2 images, one for the NodeJS server and another for MySql DB.

But, I can't connect them both. I even tried accessing the database using phpmyadmin from outside the docker container and failed.

In my docker-compose, I created a network, set both images on the same network. and added the links: - db:db to make the backend server depend on the database.

I know that the network is fine. because I have a third frontend server image and it can communicate with the backend successfully.

Thread Thread
quinncuatro profile image
Henry Quinn

For the PHPMyAdmin bit, are you exposing a port on the DB image? If you put two images on a Docker network like that, they just talk to everything on that network. You have to explicitly expose a port to have that container talk to anything "local" not on that network.

Thread Thread
quinncuatro profile image
Henry Quinn

For the Node -> DB bit, do you mind sharing your docker-compose.yaml and the connection string you're using in your Node container?

Thread Thread
bassemmohamed profile image
Bassem Ibrahim👨‍💻🇪🇬

Yeah sure, No problem!

version: "2"

networks:
  app-tier:
    driver: bridge

services:
  # Mysql database
  frostdb:
    image: frost/db
    hostname: frostdb

    networks:
      - app-tier
    ports:
      - "3306:3306"

  # NodeJS backend server
  frostback:
    image: frost/back
    hostname: frostback

    networks:
      - app-tier
    links:
      - frostdb:frostdb
    depends_on:
      - frostdb
    ports:
      - "49160:8080"

  # Frontend server
  frostgui:
    image: frost/gui
    hostname: frostgui

    links:
      - frostback:frostback
    ports:
      - "49170:3000"

I think that I am exposing ports using the "3306:3306". and for the backend config, I have a .env file

NODE_ENV=development

DB_TYPE=mysql
DB_NAME=frost
DB_HOST=localhost
DB_USER=USER
DB_PASSWORD=PASS
DB_PORT=3306

Actually, I have no idea what the username/password for the DB should be. But that's not the issue anyway according to the logs.

Thread Thread
quinncuatro profile image
Henry Quinn

You're correct that you're exposing port 3306.

Your ENV file looks good, but what about the line of code that's using those ENV variables?

Thread Thread
Sloan, the sloth mascot
Comment deleted
bassemmohamed profile image
Bassem Ibrahim👨‍💻🇪🇬

I am using a package called Sequelize for connecting to the DB and here is how :

const url = `${process.env.DB_TYPE}://${process.env.DB_USER}:${
      process.env.DB_PASSWORD
    }@${process.env.DB_HOST}:${process.env.DB_PORT}/${process.env.DB_NAME}`;
    this.db = new Sequelize(url, {
      define: {
        charset: "utf8mb4",
        collate: "utf8mb4_general_ci",
        timestamps: true
      }
    });

Running docker-compose up produces this error :

Unhandled rejection SequelizeConnectionRefusedError: connect ECONNREFUSED 127.0.0.1:3306

Could it be that the DB is not yet up and running?

Thread Thread
quinncuatro profile image
Henry Quinn • Edited on

I mean, could be. Have you tried using Kitematic or docker exec -it <container name> /bin/bash?

Also, what is your output for docker ps -a when you have your compose file spun up?

Edit: I see a couple things that could be at fault here, but I want to see the answer to those two questions before I take a stab at it. ^

Thread Thread
quinncuatro profile image
Henry Quinn

I'd consider updating your docker-compose.yaml to version 3.x and use the container_name item to force a name on your container.

Then, in your ENV file, use whatever you set that container_name to DB_HOST. I understand why you're trying to use localhost, but if all of these containers are on one Docker network, they'll want to refer to each other by their container names.

Thread Thread
bassemmohamed profile image
Bassem Ibrahim👨‍💻🇪🇬

I feel like i need to have a better understanding of docker.

Definitely will try doing that and will update you.

Thread Thread
quinncuatro profile image
Henry Quinn

We all start somewhere, my dude. :)

Collapse
vguleaev profile image
Vladislav Guleaev Author

Hello man, I created next part of series, you should see it 🖐️

Collapse
bassemmohamed profile image
Bassem Ibrahim👨‍💻🇪🇬

Will do, definitely 👍

Collapse
pclewisnz profile image
pclewisnz

I failed at the second hurdle. Some pre-requisite knowledge that you have not explained. For a topic that appeared to be aimed at new docker user and using Windows system with VS Code as I have, I did not expect to be stumped so soon. I have reviewed a lot of tutorials and I have found ever one of them to be missing vital information (some are outright wrong). The effort you have gone to here looked promising so I have signed up to this site just to see if you still monitor this old topic and might have a response.
Here is the issue:
In the opening paragraph you write:
"Next command creates a new folder with name test-node-app, then creates npm package file and opens folder in VS Code.
mkdir test-node-app && cd test-node-app && npm init -y && code ."

Where do you type that? the syntax is wrong for powershell or command prompt and WSL doesn't know about npm so there must be some other pre-requsite knowledge or something missing in the Setup section.

Using powershell and appropriate commands to achieve the same as the linux style command line intends I have been able to continue. Perhaps though I am misisng something really important. Do you assume for example that the reader has already installed a unix VM and that they are running from that shell?

Collapse
quinncuatro profile image
Henry Quinn

Was there anything specific to VSCode in here?

Collapse
vguleaev profile image
Vladislav Guleaev Author

Only Docker Extension and command line

Collapse
quinncuatro profile image
Henry Quinn

Word, I was gonna say I love VSCode but nothing about the editor really does any Docker stuff for me besides the Quake terminal. I have the Docker extension but it doesn't really add anything for me.

Collapse
angusin profile image
Miguel Viñas • Edited on

Thank you so much for the article!