docker-compose
Generate and modify Docker Compose configurations for development and production. Use this when asked to add services, configure Docker, or set up the infrastructure.
Works with
---
name: docker-compose
description: Generate and modify Docker Compose configurations for development and production. Use this when asked to add services, configure Docker, or set up the infrastructure.
license: MIT
---
# Docker Compose Configuration
Generate Docker Compose configurations following project conventions.
## File Structure
```
docker/
├── docker-compose.yml # Production (all services)
├── docker-compose.dev.yml # Development (DB only)
├── docker-compose.test.yml # Testing (ephemeral)
├── Dockerfile.backend # Spring Boot build
├── Dockerfile.frontend # React + Nginx build
├── nginx/
│ ├── nginx.conf # Main Nginx config
│ └── default.conf # Server config
└── init-db/
└── 01-init.sql # Database initialization
```
## Development Configuration
### docker-compose.dev.yml
```yaml
version: "3.9"
services:
postgres:
image: postgres:16-alpine
container_name: app-postgres-dev
environment:
POSTGRES_DB: ${POSTGRES_DB:-myapp}
POSTGRES_USER: ${POSTGRES_USER:-myapp}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-myapp}
ports:
- "5432:5432"
volumes:
- postgres_dev_data:/var/lib/postgresql/data
- ./init-db:/docker-entrypoint-initdb.d:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-myapp} -d ${POSTGRES_DB:-myapp}"]
interval: 10s
timeout: 5s
retries: 5
volumes:
postgres_dev_data:
```
---
## Production Configuration
### docker-compose.yml
```yaml
version: "3.9"
services:
postgres:
image: postgres:16-alpine
container_name: app-postgres
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init-db:/docker-entrypoint-initdb.d:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- backend-network
backend:
build:
context: ../backend
dockerfile: ../docker/Dockerfile.backend
container_name: app-backend
environment:
SPRING_PROFILES_ACTIVE: prod
DATABASE_URL: jdbc:postgresql://postgres:5432/${POSTGRES_DB}
DATABASE_USERNAME: ${POSTGRES_USER}
DATABASE_PASSWORD: ${POSTGRES_PASSWORD}
JWT_SECRET: ${JWT_SECRET}
JWT_EXPIRATION: ${JWT_EXPIRATION:-86400000}
depends_on:
postgres:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
restart: unless-stopped
networks:
- backend-network
- frontend-network
frontend:
build:
context: ../frontend
dockerfile: ../docker/Dockerfile.frontend
args:
VITE_API_URL: ${VITE_API_URL:-/api}
container_name: app-frontend
ports:
- "80:80"
- "443:443"
depends_on:
backend:
condition: service_healthy
restart: unless-stopped
networks:
- frontend-network
networks:
backend-network:
driver: bridge
frontend-network:
driver: bridge
volumes:
postgres_data:
```
---
## Additional Services
### Redis (Cache / Session)
```yaml
redis:
image: redis:7-alpine
container_name: app-redis
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
ports:
- "6379:6379"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- backend-network
volumes:
redis_data:
```
Backend environment addition:
```yaml
environment:
# ... existing
SPRING_REDIS_HOST: redis
SPRING_REDIS_PORT: 6379
SPRING_REDIS_PASSWORD: ${REDIS_PASSWORD}
```
### MinIO (Object Storage / S3-compatible)
```yaml
minio:
image: minio/minio:latest
container_name: app-minio
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-admin}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-admin123}
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio_data:/data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
restart: unless-stopped
networks:
- backend-network
volumes:
minio_data:
```
### Mailhog (Email Testing)
```yaml
mailhog:
image: mailhog/mailhog:latest
container_name: app-mailhog
ports:
- "1025:1025" # SMTP
- "8025:8025" # Web UI
restart: unless-stopped
networks:
- backend-network
```
Backend environment addition:
```yaml
environment:
SPRING_MAIL_HOST: mailhog
SPRING_MAIL_PORT: 1025
```
### Elasticsearch (Search)
```yaml
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
container_name: app-elasticsearch
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ports:
- "9200:9200"
volumes:
- elasticsearch_data:/usr/share/elasticsearch/data
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:9200/_cluster/health || exit 1"]
interval: 30s
timeout: 10s
retries: 5
restart: unless-stopped
networks:
- backend-network
volumes:
elasticsearch_data:
```
### RabbitMQ (Message Queue)
```yaml
rabbitmq:
image: rabbitmq:3-management-alpine
container_name: app-rabbitmq
environment:
RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER:-guest}
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD:-guest}
ports:
- "5672:5672" # AMQP
- "15672:15672" # Management UI
volumes:
- rabbitmq_data:/var/lib/rabbitmq
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "check_running"]
interval: 30s
timeout: 10s
retries: 5
restart: unless-stopped
networks:
- backend-network
volumes:
rabbitmq_data:
```
---
## Dockerfiles
### Dockerfile.backend
```dockerfile
# Build stage
FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /app
# Copy Maven wrapper and pom.xml
COPY .mvn .mvn
COPY mvnw pom.xml ./
# Download dependencies (cached layer)
RUN ./mvnw dependency:go-offline -B
# Copy source code
COPY src src
# Build the application
RUN ./mvnw package -DskipTests -B
# Extract layers for better caching
RUN java -Djarmode=layertools -jar target/*.jar extract
# Runtime stage
FROM eclipse-temurin:21-jre-alpine
# Security: run as non-root user
RUN addgroup -g 1001 app && adduser -u 1001 -G app -D app
WORKDIR /app
# Copy extracted layers
COPY --from=builder /app/dependencies/ ./
COPY --from=builder /app/spring-boot-loader/ ./
COPY --from=builder /app/snapshot-dependencies/ ./
COPY --from=builder /app/application/ ./
# Change ownership
RUN chown -R app:app /app
USER app
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s \
CMD wget -q --spider http://localhost:8080/actuator/health || exit 1
ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]
```
### Dockerfile.frontend
```dockerfile
# Build stage
FROM node:22-alpine AS builder
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci
# Copy source code
COPY . .
# Build arguments for environment variables
ARG VITE_API_URL=/api
# Build the application
RUN npm run build
# Runtime stage
FROM nginx:alpine
# Copy built files
COPY --from=builder /app/dist /usr/share/nginx/html
# Copy Nginx configuration
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
# Security headers
RUN rm /etc/nginx/conf.d/default.conf.default 2>/dev/null || true
EXPOSE 80
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget -q --spider http://localhost/ || exit 1
CMD ["nginx", "-g", "daemon off;"]
```
---
## Nginx Configuration
### nginx/default.conf
```nginx
upstream backend {
server backend:8080;
keepalive 32;
}
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# Compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied any;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:;" always;
# API proxy
location /api {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# Buffer settings
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
}
# WebSocket support (if needed)
location /ws {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
# Static assets caching
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# SPA fallback
location / {
try_files $uri $uri/ /index.html;
}
# Health check endpoint
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}
```
---
## Environment File
### .env.example
```bash
# ===========================================
# PostgreSQL
# ===========================================
POSTGRES_DB=myapp
POSTGRES_USER=myapp
POSTGRES_PASSWORD=changeme_in_production
# ===========================================
# Backend (Spring Boot)
# ===========================================
JWT_SECRET=your-256-bit-secret-key-must-be-at-least-32-characters-long
JWT_EXPIRATION=86400000
# ===========================================
# Frontend (Vite)
# ===========================================
VITE_API_URL=/api
# ===========================================
# Optional Services
# ===========================================
# Redis
REDIS_PASSWORD=changeme
# MinIO
MINIO_ROOT_USER=admin
MINIO_ROOT_PASSWORD=admin123
# RabbitMQ
RABBITMQ_USER=guest
RABBITMQ_PASSWORD=guest
```
---
## Useful Commands
```bash
# Development
docker compose -f docker/docker-compose.dev.yml up -d
docker compose -f docker/docker-compose.dev.yml down
docker compose -f docker/docker-compose.dev.yml logs -f postgres
# Production
docker compose -f docker/docker-compose.yml up -d --build
docker compose -f docker/docker-compose.yml down
# Logs
docker compose -f docker/docker-compose.yml logs -f backend
docker compose -f docker/docker-compose.yml logs -f --tail=100
# Shell access
docker exec -it app-postgres psql -U myapp -d myapp
docker exec -it app-backend sh
# Cleanup
docker compose -f docker/docker-compose.yml down -v # Remove volumes too
docker system prune -a # Remove all unused images
```More DevOps & Infrastructure skills
azure-ai
microsoft/azure-skills
Use for Azure AI: Search, Speech, OpenAI, Document Intelligence. Helps with search, vector/hybrid search, speech-to-text, text-to-speech, transcription, OCR. WHEN: AI Search, query search, vector search, hybrid search, semantic search, speech-to-text, text-to-speech, transcribe, OCR, convert text to speech.
appinsights-instrumentation
microsoft/azure-skills
Guidance for instrumenting webapps with Azure Application Insights. Provides telemetry patterns, SDK setup, and configuration references. WHEN: how to instrument app, App Insights SDK, telemetry patterns, what is App Insights, Application Insights guidance, instrumentation examples, APM best practices.
azure-storage
microsoft/azure-skills
Azure Storage Services including Blob Storage, File Shares, Queue Storage, Table Storage, and Data Lake. Answers questions about storage access tiers (hot, cool, cold, archive), when to use each tier, and tier comparison. Provides object storage, SMB file shares, async messaging, NoSQL key-value, and big data analytics. Includes lifecycle management. USE FOR: blob storage, file shares, queue storage, table storage, data lake, upload files, download blobs, storage accounts, access tiers, storage tiers, hot cool cold archive, storage tier comparison, when to use storage tiers, lifecycle management, Azure Storage concepts. DO NOT USE FOR: SQL databases, Cosmos DB (use azure-prepare), messaging with Event Hubs or Service Bus (use azure-messaging).

