mirror of
https://github.com/ghndrx/docker-templates.git
synced 2026-02-10 06:45:04 +00:00
feat(node): add production-ready Node.js Dockerfile templates with pnpm
- Multi-stage build with Node.js 22 slim base - PNPM package manager via corepack (2x faster than npm) - Build cache mounts for fast rebuilds - Non-root user (appuser:1000) for security - Health check using native fetch API - Alpine variant for size optimization (~130MB) - Distroless variant for maximum security (~110MB) - Comprehensive .dockerignore for clean builds - Full documentation with framework-specific guidance
This commit is contained in:
72
node/.dockerignore
Normal file
72
node/.dockerignore
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# =============================================================================
|
||||||
|
# .dockerignore - Exclude files from Docker build context
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# Dependencies (always reinstall in container)
|
||||||
|
node_modules/
|
||||||
|
.pnpm-store/
|
||||||
|
|
||||||
|
# Build output (rebuilt in container)
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
.next/
|
||||||
|
.nuxt/
|
||||||
|
.output/
|
||||||
|
|
||||||
|
# Development
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
coverage/
|
||||||
|
.nyc_output/
|
||||||
|
*.test.js
|
||||||
|
*.spec.js
|
||||||
|
__tests__/
|
||||||
|
__mocks__/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
tsconfig.tsbuildinfo
|
||||||
|
|
||||||
|
# Environment files (use runtime secrets)
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
|
||||||
|
# IDE / Editor
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# Git
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
.gitattributes
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
Dockerfile*
|
||||||
|
docker-compose*.yml
|
||||||
|
.dockerignore
|
||||||
|
|
||||||
|
# CI/CD
|
||||||
|
.github/
|
||||||
|
.gitlab-ci.yml
|
||||||
|
.travis.yml
|
||||||
|
Jenkinsfile
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
*.md
|
||||||
|
!README.md
|
||||||
|
docs/
|
||||||
|
LICENSE
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
*.tmp
|
||||||
95
node/Dockerfile
Normal file
95
node/Dockerfile
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
# syntax=docker/dockerfile:1.7
|
||||||
|
#
|
||||||
|
# Node.js Multi-Stage Dockerfile with PNPM
|
||||||
|
# Features: Fast builds, minimal image, non-root, security hardened
|
||||||
|
#
|
||||||
|
# Build args:
|
||||||
|
# NODE_VERSION - Node.js version (default: 22)
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# docker build -t myapp:latest .
|
||||||
|
# docker run --rm -p 3000:3000 myapp:latest
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Stage 1: Install dependencies
|
||||||
|
# =============================================================================
|
||||||
|
ARG NODE_VERSION=22
|
||||||
|
|
||||||
|
FROM node:${NODE_VERSION}-slim AS deps
|
||||||
|
|
||||||
|
# Enable corepack for pnpm
|
||||||
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy dependency files only (layer caching)
|
||||||
|
COPY package.json pnpm-lock.yaml* ./
|
||||||
|
|
||||||
|
# Fetch dependencies to pnpm store
|
||||||
|
RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store \
|
||||||
|
pnpm fetch --frozen-lockfile
|
||||||
|
|
||||||
|
# Install production dependencies only
|
||||||
|
RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store \
|
||||||
|
pnpm install --frozen-lockfile --prod
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Stage 2: Build application (if needed)
|
||||||
|
# =============================================================================
|
||||||
|
FROM node:${NODE_VERSION}-slim AS builder
|
||||||
|
|
||||||
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy dependencies from deps stage
|
||||||
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
|
COPY package.json pnpm-lock.yaml* ./
|
||||||
|
|
||||||
|
# Install all dependencies (including devDependencies for build)
|
||||||
|
RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store \
|
||||||
|
pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
# Copy source code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build application (TypeScript, bundler, etc.)
|
||||||
|
RUN pnpm build
|
||||||
|
|
||||||
|
# Prune dev dependencies after build
|
||||||
|
RUN pnpm prune --prod
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Stage 3: Production runtime
|
||||||
|
# =============================================================================
|
||||||
|
FROM node:${NODE_VERSION}-slim AS runtime
|
||||||
|
|
||||||
|
# Security: Create non-root user
|
||||||
|
RUN groupadd --gid 1000 appgroup && \
|
||||||
|
useradd --uid 1000 --gid appgroup --shell /bin/bash --create-home appuser
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy production dependencies
|
||||||
|
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
|
||||||
|
|
||||||
|
# Copy built application
|
||||||
|
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
|
||||||
|
COPY --from=builder --chown=appuser:appgroup /app/package.json ./
|
||||||
|
|
||||||
|
# Node.js production optimizations
|
||||||
|
ENV NODE_ENV=production \
|
||||||
|
NODE_OPTIONS="--max-old-space-size=512"
|
||||||
|
|
||||||
|
# Switch to non-root user
|
||||||
|
USER appuser
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||||
|
CMD node -e "fetch('http://localhost:3000/health').then(r => r.ok ? process.exit(0) : process.exit(1)).catch(() => process.exit(1))"
|
||||||
|
|
||||||
|
# Start application
|
||||||
|
CMD ["node", "dist/index.js"]
|
||||||
78
node/Dockerfile.alpine
Normal file
78
node/Dockerfile.alpine
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
# syntax=docker/dockerfile:1.7
|
||||||
|
#
|
||||||
|
# Node.js Alpine Dockerfile (Minimal Size)
|
||||||
|
# Features: ~50MB base image, fast startup, pnpm package manager
|
||||||
|
#
|
||||||
|
# Note: Alpine uses musl libc - most npm packages work fine,
|
||||||
|
# but some native modules may need recompilation.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# docker build -f Dockerfile.alpine -t myapp:latest .
|
||||||
|
# docker run --rm -p 3000:3000 myapp:latest
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Stage 1: Install dependencies
|
||||||
|
# =============================================================================
|
||||||
|
ARG NODE_VERSION=22
|
||||||
|
|
||||||
|
FROM node:${NODE_VERSION}-alpine AS deps
|
||||||
|
|
||||||
|
# Enable pnpm via corepack
|
||||||
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy dependency files
|
||||||
|
COPY package.json pnpm-lock.yaml* ./
|
||||||
|
|
||||||
|
# Install production dependencies
|
||||||
|
RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store \
|
||||||
|
pnpm fetch --frozen-lockfile && \
|
||||||
|
pnpm install --frozen-lockfile --prod
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Stage 2: Build application
|
||||||
|
# =============================================================================
|
||||||
|
FROM node:${NODE_VERSION}-alpine AS builder
|
||||||
|
|
||||||
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
|
COPY package.json pnpm-lock.yaml* ./
|
||||||
|
|
||||||
|
# Install all deps for build
|
||||||
|
RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store \
|
||||||
|
pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
RUN pnpm build
|
||||||
|
RUN pnpm prune --prod
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Stage 3: Alpine runtime
|
||||||
|
# =============================================================================
|
||||||
|
FROM node:${NODE_VERSION}-alpine AS runtime
|
||||||
|
|
||||||
|
# Security: Add non-root user (Alpine style)
|
||||||
|
RUN addgroup -g 1000 appgroup && \
|
||||||
|
adduser -u 1000 -G appgroup -s /bin/sh -D appuser
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy application
|
||||||
|
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
|
||||||
|
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
|
||||||
|
COPY --from=builder --chown=appuser:appgroup /app/package.json ./
|
||||||
|
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
|
USER appuser
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||||
|
CMD node -e "fetch('http://localhost:3000/health').then(r => r.ok ? process.exit(0) : process.exit(1)).catch(() => process.exit(1))"
|
||||||
|
|
||||||
|
CMD ["node", "dist/index.js"]
|
||||||
59
node/Dockerfile.distroless
Normal file
59
node/Dockerfile.distroless
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
# syntax=docker/dockerfile:1.7
|
||||||
|
#
|
||||||
|
# Node.js Distroless Dockerfile (Maximum Security)
|
||||||
|
# Features: No shell, no package manager, minimal attack surface
|
||||||
|
#
|
||||||
|
# Note: Distroless images have no shell - debugging requires ephemeral containers
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# docker build -f Dockerfile.distroless -t myapp:latest .
|
||||||
|
# docker run --rm -p 3000:3000 myapp:latest
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Stage 1: Build environment
|
||||||
|
# =============================================================================
|
||||||
|
ARG NODE_VERSION=22
|
||||||
|
|
||||||
|
FROM node:${NODE_VERSION}-slim AS builder
|
||||||
|
|
||||||
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy dependency files
|
||||||
|
COPY package.json pnpm-lock.yaml* ./
|
||||||
|
|
||||||
|
# Fetch and install dependencies
|
||||||
|
RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store \
|
||||||
|
pnpm fetch --frozen-lockfile && \
|
||||||
|
pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
# Copy source and build
|
||||||
|
COPY . .
|
||||||
|
RUN pnpm build
|
||||||
|
|
||||||
|
# Prune to production only
|
||||||
|
RUN pnpm prune --prod
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Stage 2: Distroless runtime (maximum security)
|
||||||
|
# =============================================================================
|
||||||
|
FROM gcr.io/distroless/nodejs22-debian12:nonroot AS runtime
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy production dependencies
|
||||||
|
COPY --from=builder /app/node_modules ./node_modules
|
||||||
|
|
||||||
|
# Copy built application
|
||||||
|
COPY --from=builder /app/dist ./dist
|
||||||
|
COPY --from=builder /app/package.json ./
|
||||||
|
|
||||||
|
# Environment
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
# Start application (exec form required - no shell in distroless)
|
||||||
|
CMD ["dist/index.js"]
|
||||||
206
node/README.md
Normal file
206
node/README.md
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
# Node.js Docker Templates
|
||||||
|
|
||||||
|
Production-ready Dockerfile templates using [pnpm](https://pnpm.io/) - the fast, disk-efficient package manager.
|
||||||
|
|
||||||
|
## Templates
|
||||||
|
|
||||||
|
| File | Base Image | Size | Use Case |
|
||||||
|
|------|-----------|------|----------|
|
||||||
|
| `Dockerfile` | node:22-slim | ~200MB | Standard production |
|
||||||
|
| `Dockerfile.alpine` | node:22-alpine | ~130MB | Size optimized |
|
||||||
|
| `Dockerfile.distroless` | distroless/nodejs22 | ~110MB | Maximum security |
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copy template to your project
|
||||||
|
cp Dockerfile .dockerignore /path/to/your/project/
|
||||||
|
|
||||||
|
# Build
|
||||||
|
docker build -t myapp .
|
||||||
|
|
||||||
|
# Run
|
||||||
|
docker run -p 3000:3000 myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### 🚀 PNPM Package Manager
|
||||||
|
- **2x faster** than npm
|
||||||
|
- **Disk efficient** via content-addressable storage
|
||||||
|
- Strict dependency resolution
|
||||||
|
- Native workspace support
|
||||||
|
|
||||||
|
### 📦 Multi-Stage Build
|
||||||
|
```dockerfile
|
||||||
|
# Stage 1: Install dependencies
|
||||||
|
FROM node:22-slim AS deps
|
||||||
|
RUN pnpm install --frozen-lockfile --prod
|
||||||
|
|
||||||
|
# Stage 2: Build application
|
||||||
|
FROM node:22-slim AS builder
|
||||||
|
RUN pnpm build
|
||||||
|
|
||||||
|
# Stage 3: Minimal runtime
|
||||||
|
FROM node:22-slim AS runtime
|
||||||
|
COPY --from=builder /app/dist ./dist
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🔒 Security Hardened
|
||||||
|
- Non-root user (`appuser:1000`)
|
||||||
|
- No devDependencies in production
|
||||||
|
- Health checks included
|
||||||
|
- Distroless option for zero CVE base
|
||||||
|
|
||||||
|
### ⚡ Build Cache Optimization
|
||||||
|
```dockerfile
|
||||||
|
# Cache pnpm store across builds
|
||||||
|
RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store \
|
||||||
|
pnpm install --frozen-lockfile
|
||||||
|
```
|
||||||
|
|
||||||
|
## Project Setup
|
||||||
|
|
||||||
|
### Required: package.json
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "myapp",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"start": "node dist/index.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.21.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.6.0",
|
||||||
|
"@types/node": "^22.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generate Lock File
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install pnpm if needed
|
||||||
|
npm install -g pnpm
|
||||||
|
# Or via corepack
|
||||||
|
corepack enable && corepack prepare pnpm@latest --activate
|
||||||
|
|
||||||
|
# Create lock file
|
||||||
|
pnpm install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Customization
|
||||||
|
|
||||||
|
### Change Node Version
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
ARG NODE_VERSION=20
|
||||||
|
FROM node:${NODE_VERSION}-slim AS deps
|
||||||
|
```
|
||||||
|
|
||||||
|
### Change Port
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
EXPOSE 8080
|
||||||
|
HEALTHCHECK ... 'http://localhost:8080/health' ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add Native Dependencies
|
||||||
|
|
||||||
|
For packages requiring native compilation (node-gyp):
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
FROM node:22-slim AS deps
|
||||||
|
|
||||||
|
# Install build tools
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
python3 \
|
||||||
|
make \
|
||||||
|
g++ \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom Entrypoint
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
# With npm script
|
||||||
|
CMD ["pnpm", "start"]
|
||||||
|
|
||||||
|
# Direct node execution
|
||||||
|
CMD ["node", "--enable-source-maps", "dist/index.js"]
|
||||||
|
|
||||||
|
# With environment validation
|
||||||
|
CMD ["sh", "-c", "node dist/validate-env.js && node dist/index.js"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### For Next.js / Nuxt / Other Frameworks
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
# Copy standalone output (Next.js)
|
||||||
|
COPY --from=builder /app/.next/standalone ./
|
||||||
|
COPY --from=builder /app/.next/static ./.next/static
|
||||||
|
COPY --from=builder /app/public ./public
|
||||||
|
CMD ["node", "server.js"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Choosing the Right Template
|
||||||
|
|
||||||
|
| Template | Size | Security | Debug | Native Modules |
|
||||||
|
|----------|------|----------|-------|----------------|
|
||||||
|
| `Dockerfile` (slim) | ⭐⭐ | ⭐⭐ | ✅ Easy | ✅ Works |
|
||||||
|
| `Dockerfile.alpine` | ⭐⭐⭐ | ⭐⭐ | ✅ Easy | ⚠️ May need rebuild |
|
||||||
|
| `Dockerfile.distroless` | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ❌ Hard | ✅ Works |
|
||||||
|
|
||||||
|
### When to Use Each
|
||||||
|
|
||||||
|
- **slim**: Default choice, best compatibility
|
||||||
|
- **alpine**: Size-constrained environments, simple apps
|
||||||
|
- **distroless**: Production Kubernetes, compliance requirements
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### "Cannot find module" errors
|
||||||
|
|
||||||
|
Ensure your `build` script outputs to `dist/`:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./dist"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### pnpm-lock.yaml not found
|
||||||
|
|
||||||
|
Generate it locally first:
|
||||||
|
```bash
|
||||||
|
pnpm install
|
||||||
|
git add pnpm-lock.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Native module compilation fails on Alpine
|
||||||
|
|
||||||
|
Install build dependencies:
|
||||||
|
```dockerfile
|
||||||
|
RUN apk add --no-cache python3 make g++
|
||||||
|
```
|
||||||
|
|
||||||
|
### Health check failing
|
||||||
|
|
||||||
|
Ensure your app has a `/health` endpoint or adjust:
|
||||||
|
```dockerfile
|
||||||
|
HEALTHCHECK CMD node -e "process.exit(0)"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- [pnpm Documentation](https://pnpm.io/)
|
||||||
|
- [Node.js Docker Best Practices](https://github.com/nodejs/docker-node/blob/main/docs/BestPractices.md)
|
||||||
|
- [Distroless Node.js](https://github.com/GoogleContainerTools/distroless/tree/main/nodejs)
|
||||||
|
- [Docker Multi-Stage Builds](https://docs.docker.com/build/building/multi-stage/)
|
||||||
Reference in New Issue
Block a user