Table of Contents
Introduction
When it comes to running Node.js applications in production, there are multiple options each with their own strengths and considerations. Docker and PM2 are two popular choices for deploying Node.js apps. This tutorial explores what each tool offers, with practical examples and comparisons to aid in determining which might suit your production needs better.
What is Docker?
Docker is a containerization platform that enables developers to package applications into containers—standardized executable components combining app source code with the operating system (OS) libraries and dependencies required to run that code in any environment.
Working with Docker
Basic Example: packaging a Node.js application into a Docker container.
FROM node:14
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 8080
CMD [ "node", "app.js" ]
This Dockerfile does the following:
- Sets the base image as ‘node:14’
- Creates a working directory in the container
- Copies package files and installs dependencies
- Copies the rest of the app’s source code
- Exposes port 8080 to the host system
- Defines the command to run the app using Node.js
What is PM2?
PM2 is a production process manager for Node.js applications with a built-in load balancer. It allows you to keep applications alive forever, reload them without downtime, and facilitate common DevOps tasks.
Working with PM2
Basic Example: starting a Node.js application with PM2.
pm2 start app.js
Comparing Capacity and Portability
Docker containers encapsulate the whole runtime environment, making them portable across different systems. In contrast, PM2 is an application-level process manager which requires the system environment to be prepared separately.
Advanced Use-Case Examples
PM2: Using cluster mode to scale an application across multiple CPU cores.
pm2 start app.js -i max
This command allows the Node.js app to balance load across all CPU cores available.
Docker: Scaling a containerized app across hosts with Docker Swarm or Kubernetes.
docker service create --replicas 3 -p 80:8080 --name my-app my-node-app
This example creates multiple microservices and balances the load across them.
Docker and PM2 in Harmony
You can use both Docker and PM2 in tandem. Here’s a complex compose file using Docker and letting PM2 manage the Node.js app within the container.
version: '3'
services:
nodejs-app:
build: .
ports:
- "80:8080"
command: pm2-runtime start ecosystem.config.js
The ‘command’ overrides the default Docker CMD with PM2, effectively utilizing PM2’s features inside the container.
Operational Considerations
Docker ensures consistency across environments but requires container management infrastructure. PM2 offers a simpler operational approach but lacks the complete isolation and control that comes with containerization.
Resource Efficiency
Containers often increase overhead due to the inclusion of a full OS in the image. In comparison, PM2 manages the Node.js process directly allowing for potentially better resource usage.
Monitoring and Management
Docker and PM2 also differ in how they monitor and manage applications. Docker focuses on container health, while PM2 provides more detailed application-specific metrics.
Complex Example for Node.js App Using Docker and PM2
FROM node:14
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 8080
COPY ecosystem.config.js .
CMD [ "pm2-runtime", "start", "ecosystem.config.js" ]
The build process copies an ecosystem configuration file into the image and PM2-runtime as the main process manager instead of directly invoking ‘node’.
Conclusion
Choosing between Docker and PM2 is not straightforward. Docker excels in creating consistent environments and scaling across hosts. PM2’s strength lies in simplifying deployments through process management and enabling practical operational solutions. Your choice will depend on several factors, including your team’s expertise, your existing infrastructure, the complexity of your application, and specific use cases.
In practice, many choose to employ both by running a PM2 process manager inside Docker containers to combine the benefits of both methods. Consider the requirements of your Node.js application and the nature of your production environment to make the best choice between Docker, PM2, or leveraging the strengths of both tools in unison.