CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-pm2

Production process manager for Node.JS applications with a built-in load balancer.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

docker-integration.mddocs/

Docker Integration

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.

Capabilities

Container Runtime Modes

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:

  • Proper PID 1 signal handling
  • Graceful container shutdown
  • Log forwarding to stdout/stderr
  • No daemon mode (foreground execution)
  • Container health check support

Dockerfile Generation

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');

Container Configuration

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'
  }]
};

Docker Examples

Basic Dockerfile with PM2

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"]

Multi-stage Dockerfile

# 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 Integration

# 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

Container-Optimized Ecosystem File

// 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
  }]
};

Container Best Practices

1. Signal Handling

// 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');
}

2. Health Checks

// 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();

3. Log Management

// 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
  }]
};

4. Resource Limits

// 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
    }
  }]
};

Container Deployment Patterns

1. Single Container Pattern

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"]

2. Multi-Container Pattern

# 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=production

3. Microservices Pattern

version: '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-service

Core Types

interface 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;
}

CLI Container Commands

# 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 ping

Install with Tessl CLI

npx tessl i tessl/npm-pm2

docs

cli-commands.md

configuration.md

docker-integration.md

index.md

module-management.md

monitoring.md

process-management.md

typescript-definitions.md

version-control.md

tile.json