Docker for Development Environments
Set up consistent development environments using Docker containers for any project or team. Master Docker for development workflows.
Docker for Development Environments
Docker revolutionizes development by providing consistent, isolated environments that work identically across different machines and operating systems. This guide covers everything you need to know about using Docker for development.
Why Docker for Development?
Benefits
- Consistency: Same environment on all machines
- Isolation: No conflicts between projects
- Reproducibility: Easy to recreate exact environment
- Team Collaboration: Everyone works with identical setup
- Easy Onboarding: New team members can start immediately
- Cross-Platform: Works on Windows, macOS, and Linux
Common Use Cases
- Microservices Development: Each service in its own container
- Database Development: Isolated database instances
- Testing: Consistent test environments
- CI/CD: Reproducible build environments
- Legacy Applications: Modernize old applications
Basic Docker Setup
Installation
# Ubuntu/Debian
sudo apt update
sudo apt install docker.io docker-compose
sudo systemctl start docker
sudo systemctl enable docker
# Add user to docker group
sudo usermod -aG docker $USER
# macOS (using Homebrew)
brew install --cask docker
# Windows
# Download Docker Desktop from docker.com
Basic Commands
# Check Docker version
docker --version
docker-compose --version
# Run hello world
docker run hello-world
# List running containers
docker ps
# List all containers
docker ps -a
# List images
docker images
# Remove containers
docker rm <container_id>
# Remove images
docker rmi <image_id>
Development Dockerfile
Node.js Development
# Dockerfile
FROM node:18-alpine
# Set working directory
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci
# Copy source code
COPY . .
# Expose port
EXPOSE 3000
# Start development server
CMD ["npm", "run", "dev"]
Python Development
# Dockerfile
FROM python:3.11-slim
# Set working directory
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y \
gcc \
&& rm -rf /var/lib/apt/lists/*
# Copy requirements
COPY requirements.txt .
# Install Python dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Copy source code
COPY . .
# Expose port
EXPOSE 8000
# Start development server
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
Multi-Stage Development
# Multi-stage Dockerfile
FROM node:18-alpine AS base
WORKDIR /app
COPY package*.json ./
RUN npm ci
FROM base AS development
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]
FROM base AS production
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]
Docker Compose for Development
Basic Compose File
# docker-compose.yml
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
volumes:
- .:/app
- /app/node_modules
environment:
- NODE_ENV=development
depends_on:
- db
- redis
db:
image: postgres:15
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: password
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
postgres_data:
Development Override
# docker-compose.override.yml
version: '3.8'
services:
web:
volumes:
- .:/app
- /app/node_modules
environment:
- DEBUG=true
- LOG_LEVEL=debug
command: npm run dev
db:
ports:
- "5432:5432"
environment:
- POSTGRES_DB=myapp_dev
Advanced Development Patterns
Hot Reloading
# Dockerfile with hot reload
FROM node:18-alpine
WORKDIR /app
# Install nodemon globally
RUN npm install -g nodemon
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
# Use nodemon for hot reloading
CMD ["nodemon", "src/index.js"]
Volume Mounting
# docker-compose.yml
services:
web:
build: .
volumes:
# Mount source code
- .:/app
# Exclude node_modules
- /app/node_modules
# Mount specific files
- ./config:/app/config
ports:
- "3000:3000"
Environment Variables
# docker-compose.yml
services:
web:
build: .
environment:
- NODE_ENV=development
- DATABASE_URL=postgresql://user:password@db:5432/myapp
- REDIS_URL=redis://redis:6379
env_file:
- .env.development
Database Development
PostgreSQL Setup
# docker-compose.yml
services:
db:
image: postgres:15
environment:
POSTGRES_DB: myapp
POSTGRES_USER: developer
POSTGRES_PASSWORD: password
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
adminer:
image: adminer
ports:
- "8080:8080"
depends_on:
- db
volumes:
postgres_data:
MySQL Setup
# docker-compose.yml
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: myapp
MYSQL_USER: developer
MYSQL_PASSWORD: password
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
volumes:
mysql_data:
Microservices Development
Service Architecture
# docker-compose.yml
version: '3.8'
services:
api-gateway:
build: ./api-gateway
ports:
- "3000:3000"
depends_on:
- user-service
- order-service
user-service:
build: ./user-service
ports:
- "3001:3000"
depends_on:
- user-db
order-service:
build: ./order-service
ports:
- "3002:3000"
depends_on:
- order-db
user-db:
image: postgres:15
environment:
POSTGRES_DB: users
POSTGRES_USER: user
POSTGRES_PASSWORD: password
order-db:
image: postgres:15
environment:
POSTGRES_DB: orders
POSTGRES_USER: user
POSTGRES_PASSWORD: password
Development Tools Integration
VS Code Integration
// .vscode/settings.json
{
"docker.defaultRegistryPath": "localhost:5000",
"docker.showStartPage": false,
"docker.containers.sortBy": "CreatedTime"
}
Debugging
# Dockerfile with debugging
FROM node:18-alpine
WORKDIR /app
# Install debugging tools
RUN npm install -g node-inspector
COPY package*.json ./
RUN npm ci
COPY . .
# Expose debug port
EXPOSE 9229
# Start with debugging
CMD ["node", "--inspect=0.0.0.0:9229", "src/index.js"]
Logging
# docker-compose.yml
services:
web:
build: .
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
Performance Optimization
Multi-Stage Builds
# Multi-stage build for production
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM node:18-alpine AS runtime
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
Layer Caching
# Optimize layer caching
FROM node:18-alpine
WORKDIR /app
# Copy package files first (for better caching)
COPY package*.json ./
RUN npm ci
# Copy source code last
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
Development Workflows
Git Hooks
#!/bin/sh
# .git/hooks/pre-commit
# Build Docker image
docker build -t myapp:dev .
# Run tests in container
docker run --rm myapp:dev npm test
if [ $? -ne 0 ]; then
echo "Tests failed. Commit aborted."
exit 1
fi
CI/CD Integration
# .github/workflows/docker.yml
name: Docker Build
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build Docker image
run: docker build -t myapp:${{ github.sha }} .
- name: Run tests
run: docker run --rm myapp:${{ github.sha }} npm test
Troubleshooting
Common Issues
# Container won't start
docker logs <container_id>
# Permission issues
sudo chown -R $USER:$USER .
# Port conflicts
docker-compose down
docker-compose up -d
# Clean up
docker system prune -a
Debugging Commands
# Enter running container
docker exec -it <container_id> /bin/bash
# Check container logs
docker logs -f <container_id>
# Inspect container
docker inspect <container_id>
# Check resource usage
docker stats
Best Practices
Security
# Use non-root user
FROM node:18-alpine
# Create app user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
# Set user
USER nextjs
WORKDIR /app
COPY --chown=nextjs:nodejs . .
Resource Limits
# docker-compose.yml
services:
web:
build: .
deploy:
resources:
limits:
memory: 512M
cpus: '0.5'
reservations:
memory: 256M
cpus: '0.25'
Conclusion
Docker for development environments provides consistency, isolation, and reproducibility that significantly improves team collaboration and development workflows. By following the patterns and practices outlined in this guide, you can create robust, maintainable development environments that work seamlessly across different machines and team members.
The key to successful Docker development is understanding the balance between containerization benefits and development convenience, choosing the right patterns for your team's needs, and maintaining good practices for security and performance.