Docker Development Environment Setup Guide - Complete Manual 2025

DockerDocker ComposeDevelopment EnvironmentContainersDevOpsVirtualization

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

  1. 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
  2. Installation Steps

    # Enable WSL 2
    wsl --install
    
    # Download and install Docker Desktop
    # Download installer from official website and execute
    

Docker Desktop Installation on macOS

  1. System Requirements

    • macOS 11.0 or later
    • Apple Silicon (M1/M2/M3) or Intel processor
    • Minimum 4GB RAM
  2. 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

  1. Avoid Root User

    # Create non-root user
    RUN addgroup -g 1001 -S nodejs
    RUN adduser -S nodejs -u 1001
    USER nodejs
    
  2. Use Minimal Base Images

    # Lightweight Alpine Linux based image
    FROM node:20-alpine
    
  3. 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

  1. Environment Consistency

    • Use identical container images across development, testing, and production
    • Solve "works on my machine" problems
    • Complete dependency management
  2. Improved Development Efficiency

    • Drastically reduce setup time for new developers
    • Easy launch of complex environments with Docker Compose
    • Instant feedback through hot reloading
  3. Scalability and Portability

    • Easy horizontal scaling
    • Portability across cloud providers
    • Support for microservices architecture
  4. Resource Efficiency

    • Lightweight compared to VMs
    • Fast startup times
    • Efficient use of system resources

Cons

  1. Learning Curve

    • Need to learn Docker concepts and commands
    • Understanding of networking and security required
    • Troubleshooting skills necessary
  2. Increased Complexity

    • May be overkill for small projects
    • Debugging can become complex
    • Image size management required
  3. Security Considerations

    • Proper configuration required
    • Image vulnerability management
    • Complexity of secret management
  4. Performance Overhead

    • Slight performance degradation compared to native execution
    • I/O performance impact from storage drivers
    • File system sync delays on Windows/macOS

References

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