Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Shameel Uddin
Shameel Uddin

Posted on

     

Node.js Development Made Easy With Docker 🐳

Introduction

Inprevious article, we learned:

  • Basics of Docker
  • Docker Images
  • Docker Containers
  • Building Node.js Image and Running it in Container

It looked good (for basics) to have a separate environment for our node.js application but you will have to build an image and run it again after every little change you make.

What if you want to sync your development environment such that as soon as you make a change in your code, it is automatically reflected after you hit your API again? Sounds cool for the development environment, right? 🤩

Enter Bind Mounts

Official docs says,When you use a bind mount, a file or directory on the host machine is mounted into a container. The file or directory is referenced by its absolute path on the host machine. Read official detailshere.

In simpler terms, it synchronizes the application directory with the directory inside the container so that whatever change you make in your host machine is immediately reflected in your container.

Image description

This means if you change anything in your files, they will automatically be changed in the running container.

Nodemon and package.json

Since you are from node.js world, you would know that we have to usenodemon which monitors our files in the root directory and then restart node.js app as soon as file change is detected.

I had nodemon globally installed so I faced issue with the docker container, so please make sure that you havenodemon in yournode_modules by running this command:

npm install --save-dev nodemon
Enter fullscreen modeExit fullscreen mode

You will have it indevDependencies. Now you should editscripts as follows inpackage.json:

"scripts":{"start":"node index.js","dev":"nodemon -L index.js","test":"echo\"Error: no test specified\" && exit 1"},
Enter fullscreen modeExit fullscreen mode

Finally, yourpackage.json should look like this:

{"name":"docker","version":"1.0.0","description":"","main":"index.js","scripts":{"start":"node index.js","dev":"nodemon -L index.js","test":"echo\"Error: no test specified\" && exit 1"},"author":"","license":"ISC","dependencies":{"express":"^4.18.2"},"devDependencies":{"nodemon":"^3.0.1"}}
Enter fullscreen modeExit fullscreen mode

We are now done withpackage.json changes. Lets move towards updatingDockerfile

Updating Dockerfile

Before we had this fromprevious article,:

FROM node:12.18.3-alpine3.12WORKDIR /appCOPY package.json /appRUNnpminstallCOPY . /appEXPOSE 3000:3000CMD ["node", "index.js"]
Enter fullscreen modeExit fullscreen mode

Now since we have updatedpackage.json and since we want to run it in development environment so we have to run this command:

npmrundev
Enter fullscreen modeExit fullscreen mode

In order for this to be in Dockerfile, we have to replace last line like this:

CMD ["npm", "run", "dev"]
Enter fullscreen modeExit fullscreen mode

Overall Dockerfile should look like this:

FROM node:12.18.3-alpine3.12WORKDIR /appCOPY package.json /appRUNnpminstallCOPY . /appENV PORT 3000EXPOSE $PORTEXPOSE 3000:3000CMD ["npm", "run", "dev"]
Enter fullscreen modeExit fullscreen mode

We have also made these two changes:

ENV PORT 3000EXPOSE $PORT
Enter fullscreen modeExit fullscreen mode

We are now adding environment variable of3000 directly in ourDockerfile and exposing it.

Building Docker Image

Since now we have a change inpackage.json so we have to re-build our image from the command we learned earlier:

docker build-t shameel-node-image.
Enter fullscreen modeExit fullscreen mode

Running Docker Container

From previous article, we had learned this docker command:

docker run -p 3000:3000 -d --name shameel-node-app -d shameel-node-image
Enter fullscreen modeExit fullscreen mode

This runs docker container named asshameel-node-app fromshameel-node-image indetached mode andexposes internal port of container i.e,3000 to thehostMachine port of3000.

Now, you will need to use a new flag-v:

docker run -v <hostMachinePath>:<containerPath> -p 3000:3000 -d --name shameel-node-app -d shameel-node-image
Enter fullscreen modeExit fullscreen mode

You can give it like this if you are on windows:

docker run -v "D:\shameel-node-docker":/app -p 3000:3000 --name shameel-node-app shameel-node-image
Enter fullscreen modeExit fullscreen mode

You have to give absolute path ofhostMachine. In this case,D:\shameel-node-docker is the absolute path where my application exists in my windows machine.

But that makes our command too long. We need a solution which should be able to give us absolute path in a cleaner way.

In Windows CMD, you can get it using%cd% and in Linux Bash you should be able to get it with$(pwd)

For Bash

I tried it using Git Bash, I hope it should work in Bash in Linux as well.

$ docker run -v "$(pwd):/app" -p 3000:3000 -d --name shameel-node-app shameel-node-image
Enter fullscreen modeExit fullscreen mode

I got this output which means container started running:

Docker Output

For Windows CMD

I ran this command it worked like a charm in CMD:

docker run -v "%cd%:/app" -d -p 3000:3000 --name shameel-node-app shameel-node-image
Enter fullscreen modeExit fullscreen mode

Inspecting the Mount

You now have successfully mounted the location from your host machine to the container and would like to verify it.

To do that, the syntax of command is this:

docker inspect <conainer-name>
Enter fullscreen modeExit fullscreen mode

For my case, it becomes this:

docker inspect shameel-node-app
Enter fullscreen modeExit fullscreen mode

And then look forMounts from the entire output.

If you do not want to inspect everything and only focus onMount then run the command below:

docker inspect -f "{{ .Mounts }}" shameel-node-app
Enter fullscreen modeExit fullscreen mode

You should be able to see thebind path of your host machine to the container.

If you have Docker Desktop, you can select your container and click onBind mounts to check this out:

Docker Desktop Bind Mount

Avoid node_modules synchronization

Currently, if you deletenode_modules from your host machine. It will also be deleted from container.
This should not be a wanted behavior because we are already installingnode_modules in ourDockerfile. So, we have to come up with a way where wesynchronize everything other thannode_modules

We will have to utilize-v flag with more specific path.

I ran a command in CMD like this:

docker run -v "%cd%:/app" -v /app/node_modules -d -p 3000:3000 --name shameel-node-app shameel-node-image
Enter fullscreen modeExit fullscreen mode

Now from Docker Desktop, you can verify it as well:

Docker Dekstop Verify
Everything other thannode_modules isMOUNT.

node_modules are now installed fromnpm install command in ourDockerfile and are no longer synced to the host machine.

Verifying Development Environment

Currently we have this app:

App Screenshot

After making slight changes and saving it in the file as:

app.get('/',(_,res)=>{res.send('Hello Shameel! How are you?');});
Enter fullscreen modeExit fullscreen mode

You can check in below image that thenodemon restarted in Docker Desktop logs and as soon as we refresh the page, we should be able to see the reflected changes

Reflected Changes

You can check the logs in CLI from this command as well:

docker logs <container>
Enter fullscreen modeExit fullscreen mode

For me, it is:

docker logs shameel-node-app
Enter fullscreen modeExit fullscreen mode

docker logs

Why You Should Do Read Only Bind Mount

Currently, the mounting is dual-side. If you make any changes inapp directory in container, it will be reflected in your host machine.

It is dangerous because if somehow, someone got access to your container then the hacker can easily put something malicious in your main machine.

The only change in the command is addition of:ro which ensures that the mount isREAD ONLY.

Command in bash would look like this:

docker run -v "$(pwd):/app:ro" -p 3000:3000 -d --name shameel-node-app shameel-node-image
Enter fullscreen modeExit fullscreen mode

Command in CMD would look like this:

docker run -v "%cd%:/app:ro" -p 3000:3000 -d --name shameel-node-app shameel-node-image
Enter fullscreen modeExit fullscreen mode

Conclusion

In this blog, we learned how to make development in node.js easy with the help of docker by incorporating bind mounts and ensuring that our dev changes are reflected as soon as we save our file.

Happy coding and containerizing! 🐳✨

Follow me for more such content:
LinkedIn:https://www.linkedin.com/in/shameeluddin/
Github:https://github.com/Shameel123

Top comments(2)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
tbroyer profile image
Thomas Broyer
Developer and architect mainly interested in web development (frontend, Web APIs), web app security, build tools, Java, Kotlin, Gradle, etc.
  • Location
    Dijon, France
  • Joined

I don't get it, why don't you just

docker run --rm -it -v "$(pwd):/app" -w /app -p 3000:3000 node:12.18.3-alpine3.12 npm run dev
Enter fullscreen modeExit fullscreen mode

?

Why create your own container (that starts by copying things in the image, that actually won't be used)? (ok, you're using thenode_modules that you build once

Fwiw, that's the approach I use when I need to use old versions of Node (I only install LTS locally, as that should be enough for all my projects). And fornode_modules, I add-u "$(id -u):$(id -g)" to my command so I can runnpm ci from within the container and it writes to thenode_modules on my machine.

But I'm on Linux and not using Docker Desktop, so there's no such thing assynchronizing things, it's just a system mount with zero overhead.

CollapseExpand
 
lewisblakeney profile image
lewisblakeney
Tech Enthusiast
  • Location
    Atlanta,US
  • Work
    Full Stack Developer
  • Joined

Great breakdown of using Docker for Node.js development! This will definitely saveNode.js development services a lot of time and headaches. Looking forward to streamlining my workflow with this approach.

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Tech Enthusiast, eager to learn latest trends of digital world!
  • Education
    Masters in Computer and Information Engineering
  • Work
    Software Engineer
  • Joined

More fromShameel Uddin

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp