Development Workflow
Docker transforms development workflows by providing consistent, reproducible environments. This lesson covers practical patterns for using Docker in daily development.
Local Development Setup
Project Structure
myproject/
├── docker-compose.yml # Development stack
├── docker-compose.override.yml # Local overrides
├── docker-compose.prod.yml # Production config
├── Dockerfile # Application image
├── .dockerignore # Build exclusions
├── .env # Default environment
├── .env.local # Local overrides (gitignored)
└── src/ # Application code
Development Compose File
# docker-compose.yml
services:
app:
build:
context: .
target: development
volumes:
- .:/app
- /app/node_modules
ports:
- "3000:3000"
environment:
NODE_ENV: development
depends_on:
- db
- redis
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: dev
POSTGRES_DB: myapp_dev
volumes:
- postgres-data:/var/lib/postgresql/data
ports:
- "5432:5432"
redis:
image: redis:alpine
ports:
- "6379:6379"
volumes:
postgres-data:
Multi-Target Dockerfile
# Base stage
FROM node:18-alpine AS base
WORKDIR /app
COPY package*.json ./
# Development stage
FROM base AS development
RUN npm install
COPY . .
CMD ["npm", "run", "dev"]
# Build stage
FROM base AS builder
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM base AS production
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
USER node
CMD ["node", "dist/index.js"]
Hot Reload
Enable live code updates without rebuilding:
Node.js with nodemon
services:
app:
build:
target: development
volumes:
- ./src:/app/src
environment:
- CHOKIDAR_USEPOLLING=true # For some systems
// package.json
{
"scripts": {
"dev": "nodemon --watch src src/index.js"
}
}
React/Vite
services:
frontend:
build:
target: development
volumes:
- ./src:/app/src
ports:
- "5173:5173"
environment:
- CHOKIDAR_USEPOLLING=true
Python with Flask
services:
api:
build: .
volumes:
- ./app:/app/app
environment:
- FLASK_DEBUG=1
command: flask run --host=0.0.0.0 --reload
Daily Development Commands
Starting Work
# Start all services
docker compose up -d
# Start with rebuild
docker compose up -d --build
# View logs
docker compose logs -f app
# Check status
docker compose ps
During Development
# Run tests
docker compose exec app npm test
# Run specific test
docker compose exec app npm test -- --grep "user"
# Run linter
docker compose exec app npm run lint
# Install new dependency
docker compose exec app npm install lodash
docker compose exec app npm install -D jest
# Run database migrations
docker compose exec app npm run migrate
Debugging
# Shell into container
docker compose exec app sh
# View container logs
docker compose logs -f app
# Inspect container
docker inspect myproject_app_1
# Check environment
docker compose exec app env
# Run one-off command
docker compose run --rm app npm run db:seed
Ending Work
# Stop services (keep data)
docker compose stop
# Stop and remove (keep volumes)
docker compose down
# Complete cleanup (removes volumes)
docker compose down -v
Database Management
Migrations
services:
app:
depends_on:
db:
condition: service_healthy
db:
image: postgres:15
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
# Run migrations
docker compose exec app npm run migrate
# Create migration
docker compose exec app npm run migrate:create add_users
# Rollback
docker compose exec app npm run migrate:rollback
Seeding Data
services:
db:
volumes:
- postgres-data:/var/lib/postgresql/data
- ./seeds:/docker-entrypoint-initdb.d:ro
# Manual seed
docker compose exec app npm run db:seed
# Reset database
docker compose down -v
docker compose up -d
docker compose exec app npm run migrate
docker compose exec app npm run db:seed
Database Access
# Connect to PostgreSQL
docker compose exec db psql -U postgres -d myapp_dev
# Export database
docker compose exec db pg_dump -U postgres myapp_dev > backup.sql
# Import database
docker compose exec -T db psql -U postgres myapp_dev < backup.sql
Testing Workflow
Running Tests
services:
test:
build:
target: development
command: npm test
environment:
NODE_ENV: test
DATABASE_URL: postgresql://postgres:test@db-test:5432/test
depends_on:
- db-test
db-test:
image: postgres:15
environment:
POSTGRES_PASSWORD: test
POSTGRES_DB: test
tmpfs:
- /var/lib/postgresql/data # Fast, ephemeral
# Run all tests
docker compose run --rm test
# Run with coverage
docker compose run --rm test npm run test:coverage
# Watch mode
docker compose run --rm test npm run test:watch
Integration Tests
# Start dependencies
docker compose up -d db redis
# Run integration tests
docker compose run --rm app npm run test:integration
# Cleanup
docker compose down
Debugging in Docker
Remote Debugging Node.js
services:
app:
ports:
- "3000:3000"
- "9229:9229" # Debug port
command: node --inspect=0.0.0.0:9229 src/index.js
VS Code launch.json:
{
"type": "node",
"request": "attach",
"name": "Docker: Attach",
"port": 9229,
"address": "localhost",
"localRoot": "${workspaceFolder}",
"remoteRoot": "/app"
}
Debugging Python
services:
app:
ports:
- "5000:5000"
- "5678:5678" # Debug port
command: python -m debugpy --listen 0.0.0.0:5678 app.py
Multiple Environments
Override Files
# docker-compose.override.yml (automatically loaded)
services:
app:
volumes:
- .:/app
ports:
- "3000:3000"
command: npm run dev
# Development (default)
docker compose up
# Production preview
docker compose -f docker-compose.yml -f docker-compose.prod.yml up
# Testing
docker compose -f docker-compose.yml -f docker-compose.test.yml up
IDE Integration
VS Code Dev Containers
// .devcontainer/devcontainer.json
{
"name": "My Project",
"dockerComposeFile": "../docker-compose.yml",
"service": "app",
"workspaceFolder": "/app",
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
],
"forwardPorts": [3000]
}
Team Onboarding
Quick Start Script
#!/bin/bash
# scripts/setup.sh
echo "Setting up development environment..."
# Copy environment file
cp .env.example .env.local
# Build and start services
docker compose up -d --build
# Wait for database
echo "Waiting for database..."
sleep 5
# Run migrations
docker compose exec app npm run migrate
# Seed data
docker compose exec app npm run db:seed
echo "Setup complete! Visit http://localhost:3000"
README Instructions
## Getting Started
1. Install Docker Desktop
2. Clone repository
3. Run `./scripts/setup.sh`
4. Visit http://localhost:3000
## Daily Commands
- Start: `docker compose up -d`
- Stop: `docker compose stop`
- Logs: `docker compose logs -f app`
- Tests: `docker compose exec app npm test`
Key Takeaways
- Use bind mounts for live code reloading
- Separate development, test, and production configurations
- Use health checks for proper service ordering
- Create scripts to simplify common workflows
- Document setup for team onboarding
- Use IDE integration for seamless development
- Keep production parity - same images, different configs

