Docker and Docker Compose for Professional Development Workflows
Master Docker Compose for enterprise development environments, covering multi-service orchestration, environment management, and team collaboration best practices.
Docker and Docker Compose for Professional Development Workflows
In enterprise development environments, consistency across local development, testing, and production is critical. Docker Compose provides the orchestration layer that enables teams to define, share, and run complex multi-service applications with a single command. This guide explores professional patterns for leveraging Docker Compose in enterprise development workflows.
Enterprise Docker Compose Architecture
Multi-Environment Configuration Strategy
# docker-compose.yml - Base configuration
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
args:
- NODE_ENV=development
volumes:
- .:/app
- /app/node_modules
environment:
- NODE_ENV=development
depends_on:
- database
- redis
- messaging
database:
image: postgres:15-alpine
environment:
POSTGRES_DB: ${DB_NAME:-enterprise_app}
POSTGRES_USER: ${DB_USER:-postgres}
POSTGRES_PASSWORD: ${DB_PASSWORD:-postgres}
volumes:
- postgres_data:/var/lib/postgresql/data
- ./database/init:/docker-entrypoint-initdb.d
ports:
- "5432:5432"
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis_data:/data
ports:
- "6379:6379"
messaging:
image: rabbitmq:3-management-alpine
environment:
RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER:-admin}
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASS:-admin}
volumes:
- rabbitmq_data:/var/lib/rabbitmq
ports:
- "5672:5672"
- "15672:15672"
volumes:
postgres_data:
redis_data:
rabbitmq_data:
networks:
default:
name: enterprise_network
Environment-Specific Overrides
# docker-compose.override.yml - Development overrides
version: '3.8'
services:
app:
ports:
- "3000:3000"
- "9229:9229" # Node.js debug port
environment:
- DEBUG=app:*
- LOG_LEVEL=debug
command: npm run dev
database:
environment:
POSTGRES_LOG_STATEMENT: all
POSTGRES_LOG_MIN_DURATION_STATEMENT: 0
# Additional development tools
pgadmin:
image: dpage/pgadmin4:latest
environment:
PGADMIN_DEFAULT_EMAIL: admin@company.com
PGADMIN_DEFAULT_PASSWORD: admin
ports:
- "8080:80"
depends_on:
- database
# docker-compose.prod.yml - Production-like configuration
version: '3.8'
services:
app:
build:
dockerfile: Dockerfile.prod
args:
- NODE_ENV=production
environment:
- NODE_ENV=production
- LOG_LEVEL=info
restart: unless-stopped
deploy:
replicas: 2
resources:
limits:
memory: 512M
cpus: '0.5'
database:
deploy:
resources:
limits:
memory: 1G
cpus: '1.0'
environment:
POSTGRES_SHARED_PRELOAD_LIBRARIES: pg_stat_statements
Advanced Multi-Service Configuration
Microservices Architecture
# docker-compose.microservices.yml
version: '3.8'
services:
# API Gateway
gateway:
build:
context: ./services/gateway
ports:
- "8000:8000"
environment:
- SERVICES_USER_URL=http://user-service:3001
- SERVICES_ORDER_URL=http://order-service:3002
- SERVICES_INVENTORY_URL=http://inventory-service:3003
depends_on:
- user-service
- order-service
- inventory-service
# User Service
user-service:
build:
context: ./services/user
environment:
- DATABASE_URL=postgresql://postgres:postgres@user-db:5432/users
- REDIS_URL=redis://redis:6379/0
depends_on:
- user-db
- redis
user-db:
image: postgres:15-alpine
environment:
POSTGRES_DB: users
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
volumes:
- user_db_data:/var/lib/postgresql/data
# Order Service
order-service:
build:
context: ./services/order
environment:
- DATABASE_URL=postgresql://postgres:postgres@order-db:5432/orders
- MESSAGE_QUEUE_URL=amqp://admin:admin@messaging:5672
depends_on:
- order-db
- messaging
order-db:
image: postgres:15-alpine
environment:
POSTGRES_DB: orders
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
volumes:
- order_db_data:/var/lib/postgresql/data
# Inventory Service
inventory-service:
build:
context: ./services/inventory
environment:
- DATABASE_URL=mongodb://mongo:27017/inventory
depends_on:
- mongo
mongo:
image: mongo:6
volumes:
- mongo_data:/data/db
# Shared services
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
messaging:
image: rabbitmq:3-management-alpine
environment:
RABBITMQ_DEFAULT_USER: admin
RABBITMQ_DEFAULT_PASS: admin
volumes:
- rabbitmq_data:/var/lib/rabbitmq
volumes:
user_db_data:
order_db_data:
mongo_data:
redis_data:
rabbitmq_data:
Development Tool Integration
# docker-compose.dev-tools.yml
version: '3.8'
services:
# Monitoring
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
grafana:
image: grafana/grafana:latest
ports:
- "3001:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana_data:/var/lib/grafana
- ./monitoring/grafana/dashboards:/etc/grafana/provisioning/dashboards
- ./monitoring/grafana/datasources:/etc/grafana/provisioning/datasources
# Log aggregation
elasticsearch:
image: elasticsearch:8.8.0
environment:
- discovery.type=single-node
- xpack.security.enabled=false
volumes:
- elasticsearch_data:/usr/share/elasticsearch/data
ports:
- "9200:9200"
kibana:
image: kibana:8.8.0
ports:
- "5601:5601"
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
depends_on:
- elasticsearch
# Development utilities
mailhog:
image: mailhog/mailhog:latest
ports:
- "1025:1025" # SMTP
- "8025:8025" # Web UI
adminer:
image: adminer:latest
ports:
- "8081:8080"
environment:
- ADMINER_DEFAULT_SERVER=database
volumes:
prometheus_data:
grafana_data:
elasticsearch_data:
Environment Management and Configuration
Environment Variable Management
# .env.example - Template for environment variables
# Database Configuration
DB_NAME=enterprise_app
DB_USER=postgres
DB_PASSWORD=postgres
DB_HOST=database
DB_PORT=5432
# Redis Configuration
REDIS_URL=redis://redis:6379/0
# Application Configuration
APP_PORT=3000
APP_ENV=development
LOG_LEVEL=debug
# External Services
AWS_ACCESS_KEY_ID=your_key_here
AWS_SECRET_ACCESS_KEY=your_secret_here
AWS_REGION=us-west-2
# Authentication
JWT_SECRET=your_jwt_secret_here
OAUTH_CLIENT_ID=your_oauth_client_id
OAUTH_CLIENT_SECRET=your_oauth_client_secret
# Feature Flags
FEATURE_NEW_UI=false
FEATURE_ANALYTICS=true
# .env.local - Local development overrides
APP_ENV=local
LOG_LEVEL=debug
DEBUG=app:*
# Local service URLs
EXTERNAL_API_URL=http://localhost:8000
WEBHOOK_URL=http://localhost:3000/webhooks
# Development-specific features
FEATURE_DEBUG_TOOLBAR=true
FEATURE_MOCK_EXTERNAL_SERVICES=true
Health Checks and Dependencies
# Enhanced service definitions with health checks
version: '3.8'
services:
app:
build: .
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
depends_on:
database:
condition: service_healthy
redis:
condition: service_healthy
database:
image: postgres:15-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
environment:
POSTGRES_DB: ${DB_NAME}
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
start_period: 10s
Professional Development Workflows
Makefile Integration
# Makefile for Docker Compose operations
.PHONY: help build up down restart logs clean test
# Default environment
ENV ?= development
help: ## Show this help message
@echo 'Usage: make [target] [ENV=environment]'
@echo ''
@echo 'Targets:'
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " %-15s %s\n", $$1, $$2}' $(MAKEFILE_LIST)
build: ## Build all services
docker-compose build
up: ## Start all services
docker-compose up -d
@echo "Services are starting up..."
@echo "Application will be available at http://localhost:3000"
@echo "Database admin at http://localhost:8080"
down: ## Stop all services
docker-compose down
restart: down up ## Restart all services
logs: ## Show logs for all services
docker-compose logs -f
logs-app: ## Show logs for app service only
docker-compose logs -f app
clean: ## Remove all containers, networks, and volumes
docker-compose down -v --remove-orphans
docker system prune -f
test: ## Run tests in container
docker-compose exec app npm test
test-integration: ## Run integration tests
docker-compose -f docker-compose.yml -f docker-compose.test.yml up --abort-on-container-exit test
shell: ## Open shell in app container
docker-compose exec app /bin/bash
db-shell: ## Open database shell
docker-compose exec database psql -U postgres -d enterprise_app
reset-db: ## Reset database (WARNING: destroys data)
docker-compose stop database
docker volume rm $$(docker-compose config | grep -A1 postgres_data | tail -1 | cut -d: -f1 | xargs)
docker-compose up -d database
# Environment-specific targets
dev: ## Start development environment
docker-compose -f docker-compose.yml -f docker-compose.override.yml up -d
prod: ## Start production-like environment
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
tools: ## Start development tools
docker-compose -f docker-compose.yml -f docker-compose.dev-tools.yml up -d
VS Code Development Container
// .devcontainer/devcontainer.json
{
"name": "Enterprise App Development",
"dockerComposeFile": ["../docker-compose.yml", "../docker-compose.override.yml"],
"service": "app",
"workspaceFolder": "/app",
"shutdownAction": "stopCompose",
"customizations": {
"vscode": {
"extensions": [
"ms-vscode.vscode-typescript-next",
"bradlc.vscode-tailwindcss",
"ms-vscode.vscode-json",
"ms-python.python",
"ms-vscode-remote.remote-containers"
],
"settings": {
"typescript.preferences.importModuleSpecifier": "relative",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}
}
},
"forwardPorts": [3000, 5432, 6379, 8080],
"portsAttributes": {
"3000": {
"label": "Application",
"onAutoForward": "openBrowser"
},
"8080": {
"label": "Database Admin"
}
},
"postCreateCommand": "npm install",
"postStartCommand": "npm run dev"
}
Testing and CI/CD Integration
Test Configuration
# docker-compose.test.yml
version: '3.8'
services:
test:
build:
context: .
dockerfile: Dockerfile.test
environment:
- NODE_ENV=test
- DATABASE_URL=postgresql://postgres:postgres@test-db:5432/test_db
- REDIS_URL=redis://test-redis:6379/1
depends_on:
- test-db
- test-redis
volumes:
- .:/app
- /app/node_modules
command: npm run test:ci
test-db:
image: postgres:15-alpine
environment:
POSTGRES_DB: test_db
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
tmpfs:
- /var/lib/postgresql/data
test-redis:
image: redis:7-alpine
tmpfs:
- /data
# Integration test service
integration-test:
build:
context: .
dockerfile: Dockerfile.test
environment:
- NODE_ENV=test
- API_BASE_URL=http://app:3000
depends_on:
- app
- database
command: npm run test:integration
CI/CD Pipeline Integration
# .github/workflows/ci.yml
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Create .env file
run: cp .env.example .env
- name: Run tests
run: |
docker-compose -f docker-compose.yml -f docker-compose.test.yml build
docker-compose -f docker-compose.yml -f docker-compose.test.yml run --rm test
- name: Run integration tests
run: |
docker-compose up -d app database redis
docker-compose -f docker-compose.yml -f docker-compose.test.yml run --rm integration-test
- name: Cleanup
run: docker-compose down -v
Performance and Optimization
Resource Management
# Resource limits and optimization
version: '3.8'
services:
app:
deploy:
resources:
limits:
memory: 512M
cpus: '0.5'
reservations:
memory: 256M
cpus: '0.25'
restart: unless-stopped
database:
deploy:
resources:
limits:
memory: 1G
cpus: '1.0'
command: >
postgres
-c shared_buffers=256MB
-c effective_cache_size=1GB
-c maintenance_work_mem=64MB
-c checkpoint_completion_target=0.9
-c wal_buffers=16MB
-c default_statistics_target=100
-c random_page_cost=1.1
-c effective_io_concurrency=200
Volume Optimization
# Optimized volume configuration
version: '3.8'
services:
app:
volumes:
# Bind mount source code for development
- type: bind
source: .
target: /app
# Named volume for node_modules (performance)
- type: volume
source: node_modules
target: /app/node_modules
# tmpfs for temporary files
- type: tmpfs
target: /tmp
tmpfs:
size: 100M
volumes:
node_modules:
driver: local
Security Best Practices
Network Security
# Network isolation and security
version: '3.8'
services:
app:
networks:
- frontend
- backend
database:
networks:
- backend
# No external ports exposed
redis:
networks:
- backend
reverse-proxy:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
networks:
- frontend
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true
Secrets Management
# Using Docker secrets
version: '3.8'
services:
app:
secrets:
- db_password
- jwt_secret
environment:
- DB_PASSWORD_FILE=/run/secrets/db_password
- JWT_SECRET_FILE=/run/secrets/jwt_secret
secrets:
db_password:
file: ./secrets/db_password.txt
jwt_secret:
file: ./secrets/jwt_secret.txt
Monitoring and Debugging
Application Monitoring
# docker-compose.monitoring.yml
version: '3.8'
services:
jaeger:
image: jaegertracing/all-in-one:latest
ports:
- "16686:16686"
- "14268:14268"
environment:
- COLLECTOR_OTLP_ENABLED=true
otel-collector:
image: otel/opentelemetry-collector:latest
command: ["--config=/etc/otel-collector-config.yml"]
volumes:
- ./monitoring/otel-collector-config.yml:/etc/otel-collector-config.yml
ports:
- "4317:4317" # OTLP gRPC receiver
- "4318:4318" # OTLP HTTP receiver
depends_on:
- jaeger
Best Practices Summary
- Environment Separation: Use override files for different environments
- Health Checks: Implement proper health checks for all services
- Resource Limits: Set appropriate CPU and memory limits
- Network Security: Use internal networks for backend services
- Volume Optimization: Use named volumes for performance-critical data
- Secrets Management: Never hardcode secrets in compose files
- Testing Integration: Include test configurations in your compose setup
- Monitoring: Implement comprehensive monitoring and logging
- Documentation: Maintain clear documentation for team members
- CI/CD Integration: Automate testing and deployment with compose
Conclusion
Docker Compose transforms complex multi-service applications into manageable, reproducible development environments. The patterns and practices outlined here provide a foundation for enterprise-grade development workflows that scale from individual developers to large distributed teams.
By implementing these professional Docker Compose patterns, teams can achieve consistency across environments, reduce onboarding time, and maintain high development velocity while ensuring production-like testing capabilities.