Production process manager for Node.JS applications with a built-in load balancer.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
PM2 Docker integration for containerized Node.js applications. Provides container-optimized runtime modes, Dockerfile generation, and production-ready containerization features with proper signal handling and graceful shutdowns.
PM2 provides specialized binaries for Docker container environments.
# PM2 Runtime - Optimized for Docker containers
pm2-runtime <script|config> [options]
# PM2 Docker - Alternative container binary
pm2-docker <script|config> [options]
# Production container startup
pm2-runtime start ecosystem.config.js --env production
# Single process container
pm2-runtime app.js --name "web-app"
# Cluster mode in container
pm2-runtime app.js -i max --name "api-cluster"Key Features:
Generate optimized Dockerfiles for PM2 applications.
/**
* Generate Dockerfile for PM2 application
* @param script - Application script path
* @param options - Docker configuration options
* @returns Generated Dockerfile content
*/
function generateDockerfile(script: string, options?: DockerOptions): string;
/**
* Configure Docker mode for application
* @param script - Application script path
* @param options - Docker configuration options
* @param mode - Docker execution mode
* @returns Docker configuration
*/
function dockerMode(script: string, options?: DockerOptions, mode?: string): any;Usage Examples:
const pm2 = require('pm2');
// Generate Dockerfile
const dockerfile = pm2.generateDockerfile('app.js', {
nodeVersion: '18-alpine',
imageName: 'my-app',
fresh: true
});
console.log(dockerfile);
// Outputs complete Dockerfile content
// Configure Docker mode
const dockerConfig = pm2.dockerMode('app.js', {
nodeVersion: '18',
dockerdaemon: false
}, 'production');Configure PM2 applications for optimal container performance.
// ecosystem.config.js for Docker
module.exports = {
apps: [{
name: 'web-app',
script: 'app.js',
// Container-specific settings
container: true,
kill_timeout: 5000,
shutdown_with_message: true,
// Environment configuration
env: {
NODE_ENV: 'production',
PORT: 3000
},
// Cluster mode in container
instances: 'max',
exec_mode: 'cluster',
// Log configuration for containers
merge_logs: true,
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
// Container health and restart settings
max_memory_restart: '1G',
max_restarts: 3,
min_uptime: '10s'
}]
};FROM node:18-alpine
# Install PM2 globally
RUN npm install -g pm2
# Create app directory
WORKDIR /usr/src/app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production
# Copy application code
COPY . .
# Expose port
EXPOSE 3000
# Use PM2 runtime for container
CMD ["pm2-runtime", "start", "ecosystem.config.js", "--env", "production"]# Build stage
FROM node:18-alpine AS builder
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci --only=production
# Production stage
FROM node:18-alpine AS production
# Install PM2
RUN npm install -g pm2
# Create non-root user
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
WORKDIR /usr/src/app
# Copy dependencies from builder
COPY --from=builder /usr/src/app/node_modules ./node_modules
COPY --chown=nodejs:nodejs . .
USER nodejs
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD pm2 ping || exit 1
CMD ["pm2-runtime", "start", "ecosystem.config.js", "--env", "production"]# docker-compose.yml
version: '3.8'
services:
app:
build: .
container_name: my-pm2-app
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- PM2_PUBLIC_KEY=${PM2_PUBLIC_KEY}
- PM2_SECRET_KEY=${PM2_SECRET_KEY}
volumes:
- ./logs:/usr/src/app/logs
restart: unless-stopped
healthcheck:
test: ["CMD", "pm2", "ping"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
nginx:
image: nginx:alpine
ports:
- "80:80"
depends_on:
- app
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf// ecosystem.config.js for containers
module.exports = {
apps: [{
name: 'api-server',
script: 'server.js',
// Container optimizations
container: true,
kill_timeout: 5000,
shutdown_with_message: true,
wait_ready: true,
listen_timeout: 10000,
// Instance configuration
instances: process.env.WEB_CONCURRENCY || 1,
exec_mode: 'cluster',
// Memory and restart settings
max_memory_restart: process.env.WEB_MEMORY || '512M',
max_restarts: 3,
min_uptime: '10s',
// Environment variables
env: {
NODE_ENV: 'production',
PORT: process.env.PORT || 3000
},
// Logging for containers
merge_logs: true,
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
// Error handling
autorestart: true,
watch: false,
// Source map support
source_map_support: true
}]
};// app.js - Proper signal handling in containers
process.on('SIGTERM', () => {
console.log('SIGTERM received, shutting down gracefully');
server.close(() => {
console.log('Process terminated');
process.exit(0);
});
});
process.on('SIGINT', () => {
console.log('SIGINT received, shutting down gracefully');
server.close(() => {
process.exit(0);
});
});
// Send ready signal to PM2 when app is ready
if (process.send) {
process.send('ready');
}// health-check.js
const http = require('http');
const options = {
hostname: 'localhost',
port: process.env.PORT || 3000,
path: '/health',
timeout: 2000
};
const req = http.request(options, (res) => {
if (res.statusCode === 200) {
process.exit(0);
} else {
process.exit(1);
}
});
req.on('error', () => {
process.exit(1);
});
req.end();// ecosystem.config.js - Container logging
module.exports = {
apps: [{
name: 'app',
script: 'app.js',
// Forward logs to stdout/stderr for Docker
log_file: '/dev/null',
out_file: '/dev/stdout',
error_file: '/dev/stderr',
// Merge cluster logs
merge_logs: true,
// Log formatting
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
time: true
}]
};// Resource-aware container configuration
module.exports = {
apps: [{
name: 'app',
script: 'app.js',
// Scale based on container resources
instances: process.env.WEB_CONCURRENCY || Math.max(1, require('os').cpus().length - 1),
// Memory limits based on container
max_memory_restart: process.env.WEB_MEMORY || '512M',
// Container-specific settings
container: true,
kill_timeout: parseInt(process.env.KILL_TIMEOUT) || 5000,
env: {
NODE_ENV: 'production',
UV_THREADPOOL_SIZE: process.env.UV_THREADPOOL_SIZE || 4
}
}]
};FROM node:18-alpine
RUN npm install -g pm2
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["pm2-runtime", "app.js", "--name", "web-app", "-i", "max"]# docker-compose.yml
version: '3.8'
services:
web:
build: .
environment:
- NODE_ENV=production
deploy:
replicas: 3
worker:
build: .
command: ["pm2-runtime", "worker.js", "--name", "background-worker"]
environment:
- NODE_ENV=productionversion: '3.8'
services:
auth-service:
build: ./services/auth
command: ["pm2-runtime", "start", "ecosystem.config.js"]
api-service:
build: ./services/api
command: ["pm2-runtime", "start", "ecosystem.config.js"]
depends_on:
- auth-serviceinterface DockerOptions {
/** Docker image name */
imageName?: string;
/** Node.js version to use */
nodeVersion?: string;
/** Perform fresh installation */
fresh?: boolean;
/** Force Docker operations */
force?: boolean;
/** Docker daemon mode */
dockerdaemon?: boolean;
}
interface ContainerConfig {
/** Enable container mode */
container?: boolean;
/** Timeout for graceful shutdown */
kill_timeout?: number;
/** Use message-based shutdown */
shutdown_with_message?: boolean;
/** Wait for ready signal */
wait_ready?: boolean;
/** Timeout for listening */
listen_timeout?: number;
}# Start with PM2 runtime (recommended for containers)
pm2-runtime start app.js
# Start ecosystem file in container
pm2-runtime start ecosystem.config.js --env production
# Start with specific options
pm2-runtime start app.js --name web-app -i max --kill-timeout 5000
# Generate Dockerfile
pm2 ecosystem --dockerfile
# Container health check
pm2 pingInstall with Tessl CLI
npx tessl i tessl/npm-pm2