Getting Started with Docker for Web Developers
A comprehensive guide to containerizing your web applications with Docker. Development workflows, production deployment, and enterprise best practices.
Getting Started with Docker for Web Developers
Streamlining development and deployment with containerization
Containerization has revolutionized web development deployment. At UN-Habitat, Docker transformed our deployment pipeline from hours to minutes, serving 12 global cities reliably.
Why Docker Matters
Docker solves fundamental problems that plague modern development teams.
Every development team faces the same core challenges that Docker was designed to solve.
Before Docker
Development teams struggled with multiple pain points:
- Environment inconsistencies between dev/staging/production
- Dependency conflicts across applications
- Complex setup for new team members
- Scaling challenges across different servers
These issues caused countless hours of debugging and frustration. The famous "it works on my machine" problem plagued teams globally.
After Docker
Docker eliminated these issues entirely:
- "It works on my machine" eliminated through consistent environments
- Deployment time: Hours → Minutes with automated pipelines
- Developer onboarding: Days → Hours with simple container setup
- Infrastructure scaling: Predictable and automated across platforms
The transformation was immediate and dramatic across development workflows.
Docker Fundamentals
Containers vs Virtual Machines
# Traditional VM (heavy, slow)
VM:
- Full OS (2-3GB)
- Hypervisor overhead
- Slow startup (minutes)
# Docker Container (lightweight, fast)
Container:
- Shared OS kernel
- App + dependencies only
- Fast startup (seconds)
Essential Docker Commands
# Images and containers
docker images # List images
docker ps # Running containers
docker ps -a # All containers
# Building and running
docker build -t myapp . # Build image
docker run -p 3000:3000 myapp # Run container
docker stop container_id # Stop container
Dockerizing a Next.js Application
1. Create Dockerfile
# Multi-stage build for production
FROM node:18-alpine AS base
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM node:18-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:18-alpine AS runtime
WORKDIR /app
COPY --from=base /app/node_modules ./node_modules
COPY --from=build /app/.next ./.next
COPY --from=build /app/public ./public
COPY package*.json ./
EXPOSE 3000
CMD ["npm", "start"]
2. Docker Compose Setup
# docker-compose.yml
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
depends_on:
- redis
redis:
image: redis:alpine
ports:
- "6379:6379"
3. Environment Configuration
# .dockerignore
node_modules
.git
.env.local
README.md
Production Best Practices
Multi-Stage Builds
# Optimize image size and security
FROM node:18-alpine AS deps
# Install dependencies only
FROM node:18-alpine AS builder
# Build application
FROM node:18-alpine AS runner
# Runtime with minimal footprint
Security Hardening
# Use non-root user
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
USER nextjs
# Minimize attack surface
COPY --from=builder --chown=nextjs:nodejs /app/.next ./
Health Checks
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/api/health || exit 1
Development Workflow
Local Development
# Start development environment
docker-compose up -d
# View logs
docker-compose logs -f web
# Execute commands in container
docker-compose exec web npm test
CI/CD Integration
# GitHub Actions example
- name: Build and push Docker image
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: myapp:latest
Performance Optimization
Image Size Reduction
# Use Alpine Linux (smaller base)
FROM node:18-alpine
# Multi-stage builds to exclude dev dependencies
# Copy only production files
Caching Strategies
# Leverage Docker layer caching
COPY package*.json ./
RUN npm ci --only=production
# Copy application code last
COPY . .
Common Issues and Solutions
Port Conflicts
# Check running containers
docker ps
# Use different ports
docker run -p 3001:3000 myapp
Volume Mounting
# Persist data with volumes
volumes:
- ./data:/app/data
- node_modules:/app/node_modules
Environment Variables
# Pass environment variables
docker run -e NODE_ENV=production myapp
# Use .env files
docker run --env-file .env myapp
Monitoring and Debugging
Container Logs
# View logs
docker logs container_name
docker logs -f container_name # Follow logs
# Debug running container
docker exec -it container_name sh
Resource Usage
# Monitor resource usage
docker stats
# Inspect container details
docker inspect container_name
Scaling with Docker
Horizontal Scaling
# Scale services
version: '3.8'
services:
web:
build: .
deploy:
replicas: 3
Load Balancing
# Add nginx load balancer
nginx:
image: nginx:alpine
ports:
- "80:80"
depends_on:
- web
Production Deployment
Container Registries
# Push to Docker Hub
docker tag myapp username/myapp:latest
docker push username/myapp:latest
# Deploy to production
docker pull username/myapp:latest
docker run -d -p 80:3000 username/myapp:latest
Orchestration
Docker containers work excellently with:
- Kubernetes for enterprise orchestration
- Docker Swarm for simpler clustering
- AWS ECS/Fargate for managed containers
- Vercel/Railway for serverless containers
Results at UN-Habitat
Deployment Improvements
- Build time: 15 minutes → 3 minutes
- Deployment reliability: 85% → 99.5%
- Environment consistency: Eliminated config drift
- Team productivity: 40% faster development cycles
Operational Benefits
- Predictable scaling for traffic spikes
- Simplified rollbacks with image versioning
- Reduced infrastructure costs through better resource utilization
- Enhanced security through container isolation
Next Steps
- Start small: Containerize one application
- Learn compose: Multi-container applications
- Implement CI/CD: Automated builds and deployments
- Monitor usage: Container metrics and logging
- Scale up: Orchestration with Kubernetes or cloud services
Conclusion
Docker transforms how we build, ship, and run applications. By containerizing your applications, you gain consistency, portability, and scalability that modern web development demands.
The investment in learning Docker pays dividends in development velocity, deployment reliability, and operational simplicity. Start with a simple containerization project and gradually adopt more advanced patterns as your expertise grows.
This guide provides the foundation for containerizing web applications effectively, based on real-world experience deploying mission-critical systems at UN-Habitat.
Anmol Manchanda
AI-Assisted Developer & Technical Architect