Docker for Web Developers
A practical guide to using Docker to streamline your web development workflow and improve deployment consistency.
Gerrad Zhang
Wuhan, China
2 min read
Why Web Developers Should Learn Docker
Docker has become an essential tool for modern web development, offering numerous benefits:
- Consistent Environments: “It works on my machine” becomes a problem of the past
- Simplified Onboarding: New team members can set up development environments in minutes
- Isolation: Each project can have its own dependencies without conflicts
- Production Parity: Development environments closely mirror production
- Simplified Deployment: Package everything your application needs to run in a single container
Docker Fundamentals for Web Developers
Key Concepts
- Images: Read-only templates containing an OS, application code, and dependencies
- Containers: Running instances of images
- Dockerfile: Instructions for building an image
- Volumes: Persistent storage for containers
- Networks: How containers communicate
- Docker Compose: Tool for defining and running multi-container applications
Your First Dockerfile
Here’s a simple Dockerfile for a Node.js application:
# Use an official Node.js runtime as a base image
FROM node:16-alpine
# Set the working directory
WORKDIR /app
# Copy package.json and package-lock.json
COPY package*.json ./
# Install dependencies
RUN npm install
# Copy the rest of the application code
COPY . .
# Expose port 3000
EXPOSE 3000
# Command to run the application
CMD ["npm", "start"]
Building and Running
# Build an image
docker build -t my-node-app .
# Run a container
docker run -p 3000:3000 my-node-app
Docker Compose for Multi-Container Applications
Most web applications require multiple services (web server, database, cache, etc.). Docker Compose simplifies managing these with a single configuration file:
# docker-compose.yml
version: '3'
services:
# Node.js application
web:
build: .
ports:
- "3000:3000"
volumes:
- ./:/app
- /app/node_modules
environment:
- NODE_ENV=development
- DB_HOST=db
- DB_USER=postgres
- DB_PASSWORD=example
depends_on:
- db
- redis
# PostgreSQL database
db:
image: postgres:13
ports:
- "5432:5432"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: example
POSTGRES_DB: myapp
volumes:
- postgres_data:/var/lib/postgresql/data
# Redis cache
redis:
image: redis:6-alpine
ports:
- "6379:6379"
volumes:
postgres_data:
To start all services:
docker-compose up
Development Workflow with Docker
Hot Reloading
For a smoother development experience, configure your application for hot reloading:
# Development Dockerfile
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
# Don't copy code - we'll use a volume mount instead
EXPOSE 3000
# Use nodemon for auto-reloading
CMD ["npm", "run", "dev"]
Then in your docker-compose.yml:
services:
web:
build: .
volumes:
- ./:/app
- /app/node_modules # This is a trick to use node_modules from the container
# other configuration...
Debugging
For Node.js applications, enable the inspector:
services:
web:
command: ["node", "--inspect=0.0.0.0:9229", "server.js"]
ports:
- "3000:3000"
- "9229:9229" # Expose debug port
Common Tasks
# View logs
docker-compose logs -f web
# Open a shell in a running container
docker-compose exec web sh
# Run tests
docker-compose exec web npm test
# Restart a service
docker-compose restart web
Docker for Different Web Stacks
React Applications
# Build stage
FROM node:16-alpine as build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Production stage
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Python Django Applications
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
PHP Laravel Applications
FROM php:8.0-fpm
WORKDIR /var/www/html
# Install dependencies
RUN apt-get update && apt-get install -y \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
zip \
unzip
# Configure and install PHP extensions
RUN docker-php-ext-install pdo_mysql
# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
COPY . .
RUN composer install
CMD ["php", "artisan", "serve", "--host=0.0.0.0"]
Best Practices
Security
- Use specific image versions instead of
latest
- Never store secrets in images
- Run containers as non-root users when possible
- Use multi-stage builds to reduce image size
- Scan images for vulnerabilities
Performance
- Use .dockerignore to exclude unnecessary files
- Layer your Dockerfile efficiently
- Use Alpine-based images for smaller footprints
- Leverage build caching
Deployment Considerations
Container Registries
Store your images in a registry like Docker Hub, GitHub Container Registry, or AWS ECR:
# Tag image for a registry
docker tag my-app:latest username/my-app:latest
# Push to registry
docker push username/my-app:latest
Orchestration
For production deployments, consider using:
- Docker Swarm: Simple built-in orchestration
- Kubernetes: Advanced orchestration for complex applications
- AWS ECS/EKS: Managed container services