Docker Development Environment Setup Guide - Complete Manual 2025
Guide
Docker Development Environment Setup Guide - Complete Manual 2025
Overview
Docker is a technology that provides consistent execution environments from development to production by packaging applications into lightweight, portable units called containers. As of 2025, the latest version of Docker Desktop includes features such as WSL 2 integration, GPU support, and enhanced security capabilities that significantly improve developer productivity. This guide covers practical procedures from setting up a development environment using Docker and Docker Compose to managing multi-container applications.
Details
Installing Docker
Docker Desktop Installation on Windows
-
System Requirements
- Windows 10 64-bit: Pro, Enterprise, Education (Build 19041 or higher)
- Windows 11 64-bit: Home, Pro, Enterprise, Education
- WSL 2 enabled
- Hardware virtualization support
-
Installation Steps
# Enable WSL 2 wsl --install # Download and install Docker Desktop # Download installer from official website and execute
Docker Desktop Installation on macOS
-
System Requirements
- macOS 11.0 or later
- Apple Silicon (M1/M2/M3) or Intel processor
- Minimum 4GB RAM
-
Installation Steps
# Install using Homebrew brew install --cask docker # Launch Docker Desktop open /Applications/Docker.app
Installation on Linux
# For Ubuntu/Debian
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
# For RHEL/CentOS/Fedora
sudo yum update
sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
# Verify installation
docker --version
docker compose version
Basic Docker Concepts
Images and Containers
- Image: Read-only template containing all files and metadata needed to run an application
- Container: Executable instance created from an image
- Registry: Repository for storing and distributing Docker images (e.g., Docker Hub)
Volumes and Networks
- Volume: Storage for persisting and sharing data between containers
- Network: Virtual network for managing communication between containers
- Bridge Network: Default network driver
Dockerfile Best Practices
Creating Efficient Dockerfiles
# syntax=docker/dockerfile:1
# Using multi-stage builds
FROM node:20-alpine AS base
WORKDIR /app
# Optimizing dependency caching
FROM base AS deps
COPY package*.json ./
RUN npm ci --only=production
# Development stage
FROM base AS dev
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["npm", "run", "dev"]
# Production stage
FROM base AS production
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NODE_ENV=production
CMD ["node", "app.js"]
Security Best Practices
-
Avoid Root User
# Create non-root user RUN addgroup -g 1001 -S nodejs RUN adduser -S nodejs -u 1001 USER nodejs
-
Use Minimal Base Images
# Lightweight Alpine Linux based image FROM node:20-alpine
-
Managing Secrets
# Using secrets during build RUN --mount=type=secret,id=npm_token \ NPM_TOKEN=$(cat /run/secrets/npm_token) \ npm ci
Building Development Environments with Docker Compose
Basic compose.yaml
services:
# Web application
web:
build:
context: .
target: dev
ports:
- "3000:3000"
volumes:
- ./:/app
- /app/node_modules
environment:
- NODE_ENV=development
- DEBUG=true
depends_on:
- db
- redis
# Database
db:
image: postgres:16-alpine
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_USER: myapp
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
POSTGRES_DB: myapp_dev
secrets:
- db_password
# Cache
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:
secrets:
db_password:
file: ./secrets/db_password.txt
Auto-reload with Compose Watch
services:
web:
build: .
develop:
watch:
# Auto-sync source code
- action: sync
path: ./src
target: /app/src
# Rebuild on package.json changes
- action: rebuild
path: package.json
# Restart on config file changes
- action: sync+restart
path: ./config
target: /app/config
Managing Multi-Container Applications
Managing Environment-Specific Configurations
# compose.yaml (base configuration)
services:
web:
image: myapp:latest
depends_on:
- db
# compose.override.yaml (development, auto-applied)
services:
web:
build: .
volumes:
- '.:/code'
ports:
- 8080:80
environment:
DEBUG: 'true'
# compose.prod.yaml (production)
services:
web:
ports:
- 80:80
environment:
PRODUCTION: 'true'
Using Multiple Compose Files
# Start development environment
docker compose up -d
# Start production environment
docker compose -f compose.yaml -f compose.prod.yaml up -d
# Specify environment file
docker compose --env-file .env.production up -d
Production Considerations
Implementing Health Checks
services:
web:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
Setting Resource Limits
services:
web:
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
Logging and Monitoring
services:
web:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
labels: "service=web"
Pros & Cons
Pros
-
Environment Consistency
- Use identical container images across development, testing, and production
- Solve "works on my machine" problems
- Complete dependency management
-
Improved Development Efficiency
- Drastically reduce setup time for new developers
- Easy launch of complex environments with Docker Compose
- Instant feedback through hot reloading
-
Scalability and Portability
- Easy horizontal scaling
- Portability across cloud providers
- Support for microservices architecture
-
Resource Efficiency
- Lightweight compared to VMs
- Fast startup times
- Efficient use of system resources
Cons
-
Learning Curve
- Need to learn Docker concepts and commands
- Understanding of networking and security required
- Troubleshooting skills necessary
-
Increased Complexity
- May be overkill for small projects
- Debugging can become complex
- Image size management required
-
Security Considerations
- Proper configuration required
- Image vulnerability management
- Complexity of secret management
-
Performance Overhead
- Slight performance degradation compared to native execution
- I/O performance impact from storage drivers
- File system sync delays on Windows/macOS
References
- Docker Official Documentation
- Docker Hub
- Docker Compose Documentation
- Docker Desktop
- Dockerfile Best Practices
- Docker Security Best Practices
Examples
Basic Node.js Application
# Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
# compose.yaml
services:
app:
build: .
ports:
- "3000:3000"
environment:
NODE_ENV: production
Python Flask Application
# Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
# compose.yaml
services:
web:
build: .
ports:
- "5000:5000"
environment:
FLASK_ENV: development
volumes:
- ./:/app
Full-Stack Application
# compose.yaml
services:
frontend:
build: ./frontend
ports:
- "3000:3000"
depends_on:
- backend
backend:
build: ./backend
ports:
- "8000:8000"
environment:
DATABASE_URL: postgresql://user:pass@db:5432/mydb
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 10s
timeout: 5s
retries: 5
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- frontend
- backend
volumes:
db_data:
Development Environment Automation
#!/bin/bash
# dev-setup.sh
# Copy environment file
cp .env.example .env
# Build Docker images
docker compose build
# Start and initialize database
docker compose up -d db
sleep 5
docker compose exec db psql -U postgres -c "CREATE DATABASE myapp_dev;"
# Start application
docker compose up -d
# Show logs
docker compose logs -f
CI/CD Pipeline Integration
# .github/workflows/docker.yml
name: Docker CI/CD
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build and test
run: |
docker compose build
docker compose run --rm app npm test
- name: Push to registry
run: |
echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
docker compose push