Docker and Containerization
Docker enables consistent, reproducible application deployment across development, testing, and production environments. Learn to containerize Node.js applications and manage containers effectively.
Challenge
Section titled “Challenge”Containerize a Node.js application with Docker, optimize images for production, and implement best practices for container management and orchestration.
Explanation
Section titled “Explanation”What is Docker?
Section titled “What is Docker?”Docker is a containerization platform that packages applications and their dependencies into isolated containers:
- Images: Read-only templates containing application code and dependencies
- Containers: Running instances of images with isolated filesystems
- Registries: Centralized repositories for storing and sharing images
- Layers: Stackable filesystem layers in Docker images for efficiency
Key Concepts
Section titled “Key Concepts”Dockerfile: Instructions to build Docker images Docker Compose: Multi-container orchestration Container Registry: Storage for Docker images (Docker Hub, ECR, GCR) Volume: Persistent data storage for containers Network: Communication between containers
Code Examples
Section titled “Code Examples”1. Basic Dockerfile for Node.js
Section titled “1. Basic Dockerfile for Node.js”# Multi-stage buildFROM node:18-alpine AS builder
WORKDIR /appCOPY package*.json ./RUN npm ci --only=production
# Production stageFROM node:18-alpine
WORKDIR /app
# Install dumb-init for proper signal handlingRUN apk add --no-cache dumb-init
# Copy from builderCOPY --from=builder /app/node_modules ./node_modulesCOPY . .
EXPOSE 3000ENV NODE_ENV=production
# Use dumb-init to handle signals properlyENTRYPOINT ["dumb-init", "--"]CMD ["node", "server.js"]2. Development Dockerfile
Section titled “2. Development Dockerfile”FROM node:18-alpine
WORKDIR /app
# Install development dependenciesRUN apk add --no-cache build-base python3 git
COPY package*.json ./RUN npm install
COPY . .
EXPOSE 3000
# Development server with hot reloadCMD ["npm", "run", "dev"]3. Docker Compose Setup
Section titled “3. Docker Compose Setup”version: '3.9'
services: app: build: context: . dockerfile: Dockerfile container_name: nodejs-app ports: - "3000:3000" environment: NODE_ENV: production DATABASE_URL: postgresql://user:password@db:5432/appdb REDIS_URL: redis://cache:6379 depends_on: - db - cache volumes: - ./logs:/app/logs restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s
db: image: postgres:15-alpine container_name: postgres-db environment: POSTGRES_USER: user POSTGRES_PASSWORD: password POSTGRES_DB: appdb volumes: - postgres_data:/var/lib/postgresql/data ports: - "5432:5432"
cache: image: redis:7-alpine container_name: redis-cache ports: - "6379:6379" volumes: - redis_data:/data
volumes: postgres_data: redis_data:4. Optimized Production Dockerfile
Section titled “4. Optimized Production Dockerfile”FROM node:18-alpine AS depsWORKDIR /appCOPY package*.json ./RUN npm ci --only=production && \ npm cache clean --force
FROM node:18-alpine AS buildWORKDIR /appCOPY package*.json ./RUN npm ci
COPY . .RUN npm run build
FROM node:18-alpineWORKDIR /app
RUN apk add --no-cache \ dumb-init \ curl
COPY --from=deps /app/node_modules ./node_modulesCOPY --from=build /app/dist ./distCOPY --from=build /app/package*.json ./
ENV NODE_ENV=productionEXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD curl -f http://localhost:3000/health || exit 1
ENTRYPOINT ["dumb-init", "--"]CMD ["node", "dist/server.js"]5. Docker Build and Push
Section titled “5. Docker Build and Push”#!/bin/bash
# Build variablesIMAGE_NAME="myapp"IMAGE_TAG="latest"REGISTRY="docker.io"DOCKER_USER="username"
# Build imagedocker build -t $IMAGE_NAME:$IMAGE_TAG -f Dockerfile .
# Tag for registrydocker tag $IMAGE_NAME:$IMAGE_TAG $REGISTRY/$DOCKER_USER/$IMAGE_NAME:$IMAGE_TAG
# Login to registry (use --password-stdin for security)echo $DOCKER_PASSWORD | docker login -u $DOCKER_USER --password-stdin $REGISTRY
# Push imagedocker push $REGISTRY/$DOCKER_USER/$IMAGE_NAME:$IMAGE_TAG
# Clean updocker logout $REGISTRY6. Container Runtime Configuration
Section titled “6. Container Runtime Configuration”const express = require('express');const app = express();
// Graceful shutdown handlingprocess.on('SIGTERM', gracefulShutdown);process.on('SIGINT', gracefulShutdown);
function gracefulShutdown() { console.log('SIGTERM received, shutting down gracefully'); server.close(() => { console.log('HTTP server closed'); process.exit(0); });
// Force shutdown after timeout setTimeout(() => { console.error('Could not close connections, forcefully shutting down'); process.exit(1); }, 30000);}
const server = app.listen(3000, () => { console.log('Server running on port 3000');});
// Health check endpointapp.get('/health', (req, res) => { res.status(200).json({ status: 'healthy' });});
app.get('/ready', (req, res) => { // Check database connection, cache, etc. res.status(200).json({ ready: true });});Best Practices
Section titled “Best Practices”-
Use Alpine Images
- Smaller image size
- Fewer security vulnerabilities
- Faster download and startup times
-
Multi-Stage Builds
- Separate build and runtime stages
- Reduce final image size
- Improve layer caching efficiency
-
Security
- Use specific version tags, not latest
- Run as non-root user
- Scan images for vulnerabilities
- Use secrets management for sensitive data
-
Performance Optimization
- Minimize layer count
- Use .dockerignore to exclude unnecessary files
- Leverage layer caching
- Compress images
-
Container Orchestration
- Use health checks
- Implement graceful shutdown
- Set resource limits
- Use restart policies
Real-World Applications
Section titled “Real-World Applications”- Microservices Deployment: Package each service independently
- CI/CD Pipeline: Automate image building and deployment
- Development Environment: Consistent environment across teams
- Cloud Migration: Portable applications across cloud providers
- Scaling: Easy horizontal scaling in Kubernetes