Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:28:55 +08:00
commit 11d1aa68c0
9 changed files with 3148 additions and 0 deletions

View File

@@ -0,0 +1,643 @@
## 🚨 CRITICAL GUIDELINES
### Windows File Path Requirements
**MANDATORY: Always Use Backslashes on Windows for File Paths**
When using Edit or Write tools on Windows, you MUST use backslashes (`\`) in file paths, NOT forward slashes (`/`).
**Examples:**
- ❌ WRONG: `D:/repos/project/file.tsx`
- ✅ CORRECT: `D:\repos\project\file.tsx`
This applies to:
- Edit tool file_path parameter
- Write tool file_path parameter
- All file operations on Windows systems
### Documentation Guidelines
**NEVER create new documentation files unless explicitly requested by the user.**
- **Priority**: Update existing README.md files rather than creating new documentation
- **Repository cleanliness**: Keep repository root clean - only README.md unless user requests otherwise
- **Style**: Documentation should be concise, direct, and professional - avoid AI-generated tone
- **User preference**: Only create additional .md files when user specifically asks for documentation
---
# Azure Service Emulators for Local Development (2025)
## Overview
This skill provides comprehensive knowledge of Azure service emulators available as Docker containers for local development in 2025.
## Available Azure Emulators
### 1. Azurite (Azure Storage Emulator)
**Official replacement for Azure Storage Emulator (deprecated)**
**Image:** `mcr.microsoft.com/azure-storage/azurite:latest`
**Supported Services:**
- Blob Storage
- Queue Storage
- Table Storage
**Configuration:**
```yaml
services:
azurite:
image: mcr.microsoft.com/azure-storage/azurite:latest
container_name: azurite
command: azurite --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 --loose
ports:
- "10000:10000" # Blob service
- "10001:10001" # Queue service
- "10002:10002" # Table service
volumes:
- azurite-data:/data
restart: unless-stopped
```
**Standard Development Connection String:**
```
DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://azurite:10000/devstoreaccount1;QueueEndpoint=http://azurite:10001/devstoreaccount1;TableEndpoint=http://azurite:10002/devstoreaccount1;
```
**Features:**
- Cross-platform (Windows, Linux, macOS)
- Written in Node.js/JavaScript
- Supports latest Azure Storage APIs
- Persistence to disk
- Compatible with Azure Storage Explorer
- `--loose` flag for relaxed validation (useful for local development)
**2025 API Version Support:**
- Latest release (v3.35.0) targets 2025-11-05 API version
- Blob service: 2025-11-05
- Queue service: 2025-11-05
- Table service: 2025-11-05 (preview)
- RA-GRS support for geo-redundant replication testing
**CLI Usage:**
```bash
# Install via npm (alternative to Docker)
npm install -g azurite
# Run with custom location
azurite --location /path/to/data --debug /path/to/debug.log
```
**Application Integration:**
```javascript
// Node.js with @azure/storage-blob
const { BlobServiceClient } = require('@azure/storage-blob');
const connectionString = process.env.AZURITE_CONNECTION_STRING;
const blobServiceClient = BlobServiceClient.fromConnectionString(connectionString);
```
```csharp
// .NET with Azure.Storage.Blobs
using Azure.Storage.Blobs;
var connectionString = Environment.GetEnvironmentVariable("AZURITE_CONNECTION_STRING");
var blobServiceClient = new BlobServiceClient(connectionString);
```
### 2. Azure SQL Server 2025
**Latest SQL Server with AI features**
**Image:** `mcr.microsoft.com/mssql/server:2025-latest`
**2025 Features:**
- Built-in Vector Search for AI similarity queries
- Semantic Queries alongside traditional full-text search
- Optimized Locking (TID Locking, LAQ)
- Native JSON and RegEx support
- Fabric Mirroring integration
- REST API support
**Configuration:**
```yaml
services:
sqlserver:
image: mcr.microsoft.com/mssql/server:2025-latest
container_name: sqlserver
environment:
- ACCEPT_EULA=Y
- MSSQL_PID=Developer
- MSSQL_SA_PASSWORD_FILE=/run/secrets/sa_password
secrets:
- sa_password
ports:
- "1433:1433"
volumes:
- sqlserver-data:/var/opt/mssql
- ./init:/docker-entrypoint-initdb.d
healthcheck:
test: ["CMD-SHELL", "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P $$MSSQL_SA_PASSWORD -Q 'SELECT 1' -C || exit 1"]
interval: 10s
timeout: 3s
retries: 3
start_period: 10s
deploy:
resources:
limits:
cpus: '2'
memory: 4G
reservations:
cpus: '1'
memory: 2G
networks:
- backend
security_opt:
- no-new-privileges:true
restart: unless-stopped
secrets:
sa_password:
file: ./secrets/sa_password.txt
volumes:
sqlserver-data:
driver: local
```
**Connection String:**
```
Server=sqlserver;Database=MyApp;User Id=sa;Password=YourStrong!Passw0rd;TrustServerCertificate=True;
```
**Important Notes:**
- **Azure SQL Edge retired September 30, 2025** - Use SQL Server 2025 instead
- Use `mssql-tools18` for TLS 1.3 support (`-C` flag trusts certificate)
- Developer edition is free for non-production use
- Supports arm64 via Rosetta 2 on macOS
**Vector Search Example (2025 Feature):**
```sql
-- Create vector index for AI similarity search
CREATE TABLE Documents (
Id INT PRIMARY KEY,
Content NVARCHAR(MAX),
ContentVector VECTOR(1536)
);
-- Perform similarity search
SELECT TOP 10 Id, Content
FROM Documents
ORDER BY VECTOR_DISTANCE(ContentVector, @queryVector);
```
**2025 vnext-preview Features:**
- Entirely Linux-based emulator (cross-platform: x64, ARM64, Apple Silicon)
- No virtual machines required on Apple Silicon or Microsoft ARM
- Changefeed support (April 2025+)
- Document TTL (Time-to-Live) support
- OpenTelemetry V2 support
- API for NoSQL in gateway mode
- Currently in preview (active development)
**Image:** `mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview`
### 3. Cosmos DB Emulator
**NoSQL database emulator**
**Image:** `mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview`
**Configuration:**
```yaml
services:
cosmosdb:
image: mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview
container_name: cosmosdb
environment:
- AZURE_COSMOS_EMULATOR_PARTITION_COUNT=10
- AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE=true
- AZURE_COSMOS_EMULATOR_IP_ADDRESS_OVERRIDE=127.0.0.1
ports:
- "8081:8081" # Data Explorer
- "10251:10251"
- "10252:10252"
- "10253:10253"
- "10254:10254"
volumes:
- cosmos-data:/data/db
deploy:
resources:
limits:
cpus: '2'
memory: 4G
networks:
- backend
restart: unless-stopped
```
**Emulator Endpoint:**
```
https://localhost:8081
```
**Emulator Key (Standard):**
```
C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==
```
**Data Explorer:**
Access at `https://localhost:8081/_explorer/index.html`
**Application Integration:**
```javascript
// Node.js with @azure/cosmos
const { CosmosClient } = require('@azure/cosmos');
const endpoint = 'https://localhost:8081';
const key = process.env.COSMOS_EMULATOR_KEY;
const client = new CosmosClient({ endpoint, key });
```
```csharp
// .NET with Microsoft.Azure.Cosmos
using Microsoft.Azure.Cosmos;
var endpoint = "https://localhost:8081";
var key = Environment.GetEnvironmentVariable("COSMOS_EMULATOR_KEY");
var client = new CosmosClient(endpoint, key);
```
**Limitations:**
- Performance not representative of production
- Limited to single partition for local development
- Certificate trust required (self-signed)
**2025 Official Azure Service Bus Emulator:**
- Released as official Docker container
- Linux-based emulator with cross-platform support
- Requires SQL Server Linux as dependency
- Supports AMQP protocol (port 5672)
- Connection string format with UseDevelopmentEmulator=true
- Current limitations: No JMS protocol, no partitioned entities, no AMQP Web Sockets
**Official Emulator Image:** `mcr.microsoft.com/azure-messaging/servicebus-emulator:latest`
**Connection String:**
```
Endpoint=sb://host.docker.internal;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;
```
### 4. Azure Service Bus Emulator
**Message queue emulator**
**Note:** Official emulator has limited Docker support. Use RabbitMQ as alternative.
**Official Emulator (Preview):**
```yaml
services:
servicebus-sql:
image: mcr.microsoft.com/mssql/server:2025-latest
environment:
- ACCEPT_EULA=Y
- MSSQL_SA_PASSWORD=ServiceBus123!
volumes:
- servicebus-sql-data:/var/opt/mssql
servicebus:
image: mcr.microsoft.com/azure-messaging/servicebus-emulator:latest
depends_on:
- servicebus-sql
environment:
- ACCEPT_EULA=Y
- SQL_SERVER=servicebus-sql
- SQL_SA_PASSWORD=ServiceBus123!
ports:
- "5672:5672" # AMQP
networks:
- backend
```
**RabbitMQ Alternative (Recommended):**
```yaml
services:
rabbitmq:
image: rabbitmq:3.14-alpine
container_name: rabbitmq
ports:
- "5672:5672" # AMQP
- "15672:15672" # Management UI
environment:
- RABBITMQ_DEFAULT_USER=admin
- RABBITMQ_DEFAULT_PASS=admin123
volumes:
- rabbitmq-data:/var/lib/rabbitmq
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "ping"]
interval: 30s
timeout: 10s
retries: 3
networks:
- backend
restart: unless-stopped
```
### 5. PostgreSQL (Azure Database for PostgreSQL)
**Image:** `postgres:16.6-alpine`
**Configuration:**
```yaml
services:
postgres:
image: postgres:16.6-alpine
container_name: postgres
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password
- POSTGRES_DB=myapp
secrets:
- postgres_password
ports:
- "5432:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
- ./init:/docker-entrypoint-initdb.d
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 3s
retries: 3
deploy:
resources:
limits:
cpus: '1'
memory: 2G
networks:
- backend
security_opt:
- no-new-privileges:true
restart: unless-stopped
```
**Extensions:**
Match Azure PostgreSQL Flexible Server extensions:
```sql
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pg_trgm";
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
```
### 6. MySQL (Azure Database for MySQL)
**Image:** `mysql:9.2`
**Configuration:**
```yaml
services:
mysql:
image: mysql:9.2
container_name: mysql
environment:
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql_root_password
- MYSQL_DATABASE=myapp
- MYSQL_USER=appuser
- MYSQL_PASSWORD_FILE=/run/secrets/mysql_password
secrets:
- mysql_root_password
- mysql_password
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
- ./init:/docker-entrypoint-initdb.d
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD"]
interval: 10s
timeout: 3s
retries: 3
deploy:
resources:
limits:
cpus: '1'
memory: 2G
networks:
- backend
security_opt:
- no-new-privileges:true
restart: unless-stopped
```
### 7. Redis (Azure Cache for Redis)
**Image:** `redis:7.4-alpine`
**Configuration:**
```yaml
services:
redis:
image: redis:7.4-alpine
container_name: redis
command: >
redis-server
--appendonly yes
--requirepass ${REDIS_PASSWORD}
--maxmemory 512mb
--maxmemory-policy allkeys-lru
ports:
- "6379:6379"
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
interval: 10s
timeout: 3s
retries: 3
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
networks:
- backend
security_opt:
- no-new-privileges:true
restart: unless-stopped
```
### 8. Application Insights Alternative (Jaeger + Grafana)
**OpenTelemetry-compatible observability stack**
```yaml
services:
jaeger:
image: jaegertracing/all-in-one:latest
container_name: jaeger
ports:
- "16686:16686" # UI
- "14268:14268" # HTTP collector
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP
environment:
- COLLECTOR_OTLP_ENABLED=true
networks:
- monitoring
restart: unless-stopped
grafana:
image: grafana/grafana:latest
container_name: grafana
ports:
- "3001:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana-data:/var/lib/grafana
networks:
- monitoring
restart: unless-stopped
```
## Complete Azure Stack Example
```yaml
services:
# Application Services
frontend:
build: ./frontend
ports: ["3000:3000"]
networks: [frontend]
depends_on:
backend:
condition: service_healthy
backend:
build: ./backend
ports: ["8080:8080"]
networks: [frontend, backend]
depends_on:
sqlserver:
condition: service_healthy
redis:
condition: service_started
azurite:
condition: service_started
# Databases
sqlserver:
image: mcr.microsoft.com/mssql/server:2025-latest
environment:
- ACCEPT_EULA=Y
- MSSQL_PID=Developer
- MSSQL_SA_PASSWORD=${MSSQL_SA_PASSWORD}
ports: ["1433:1433"]
volumes: [sqlserver-data:/var/opt/mssql]
networks: [backend]
healthcheck:
test: ["CMD-SHELL", "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P $$MSSQL_SA_PASSWORD -Q 'SELECT 1' -C"]
interval: 10s
postgres:
image: postgres:16.6-alpine
environment:
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
ports: ["5432:5432"]
volumes: [postgres-data:/var/lib/postgresql/data]
networks: [backend]
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 10s
# Cache
redis:
image: redis:7.4-alpine
command: redis-server --requirepass ${REDIS_PASSWORD}
ports: ["6379:6379"]
volumes: [redis-data:/data]
networks: [backend]
# Storage
azurite:
image: mcr.microsoft.com/azure-storage/azurite:latest
command: azurite --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 --loose
ports: ["10000:10000", "10001:10001", "10002:10002"]
volumes: [azurite-data:/data]
networks: [backend]
# NoSQL
cosmosdb:
image: mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview
ports: ["8081:8081"]
volumes: [cosmos-data:/data/db]
networks: [backend]
# Monitoring
jaeger:
image: jaegertracing/all-in-one:latest
ports: ["16686:16686", "4317:4317"]
networks: [monitoring]
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true
monitoring:
driver: bridge
volumes:
sqlserver-data:
postgres-data:
redis-data:
azurite-data:
cosmos-data:
```
## Best Practices
1. **Use health checks** - Ensure dependencies are ready before app starts
2. **Network isolation** - Keep databases on internal backend network
3. **Resource limits** - Prevent emulators from consuming all system resources
4. **Persistence** - Use named volumes for data that should survive restarts
5. **Secrets management** - Use Docker secrets or environment files
6. **Version pinning** - Use specific tags, not `latest`
7. **Security hardening** - Drop capabilities, run as non-root where possible
8. **Documentation** - Document differences between emulators and Azure services
## Known Limitations
- **Performance**: Emulators are slower than Azure services
- **Scale**: Single-instance only, no clustering
- **Features**: Some Azure-specific features unavailable locally
- **SSL/TLS**: Self-signed certificates require trust configuration
- **Azure AD**: Authentication not replicated locally
- **Networking**: VNets, Private Endpoints not available
## Migration Checklist
When moving from Azure to Docker emulators:
- [ ] Replace Azure Storage connection strings with Azurite
- [ ] Update SQL Server connection strings (remove Azure-specific options)
- [ ] Configure Cosmos DB with emulator endpoint and key
- [ ] Replace Service Bus with RabbitMQ or emulator
- [ ] Set up alternative for Application Insights
- [ ] Update authentication (remove Azure AD dependencies)
- [ ] Configure network isolation
- [ ] Test all integrations
- [ ] Document feature parity gaps
- [ ] Create init scripts for sample data
## References
- [Azurite Documentation](https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azurite)
- [SQL Server 2025 in Docker](https://learn.microsoft.com/en-us/sql/linux/quickstart-install-connect-docker)
- [Cosmos DB Emulator](https://learn.microsoft.com/en-us/azure/cosmos-db/local-emulator)
- [Service Bus Emulator](https://learn.microsoft.com/en-us/azure/service-bus-messaging/test-locally-with-service-bus-emulator)

View File

@@ -0,0 +1,860 @@
## 🚨 CRITICAL GUIDELINES
### Windows File Path Requirements
**MANDATORY: Always Use Backslashes on Windows for File Paths**
When using Edit or Write tools on Windows, you MUST use backslashes (`\`) in file paths, NOT forward slashes (`/`).
**Examples:**
- ❌ WRONG: `D:/repos/project/file.tsx`
- ✅ CORRECT: `D:\repos\project\file.tsx`
This applies to:
- Edit tool file_path parameter
- Write tool file_path parameter
- All file operations on Windows systems
### Documentation Guidelines
**NEVER create new documentation files unless explicitly requested by the user.**
- **Priority**: Update existing README.md files rather than creating new documentation
- **Repository cleanliness**: Keep repository root clean - only README.md unless user requests otherwise
- **Style**: Documentation should be concise, direct, and professional - avoid AI-generated tone
- **User preference**: Only create additional .md files when user specifically asks for documentation
---
# Docker Compose Patterns for Production (2025)
## Overview
This skill documents production-ready Docker Compose patterns and best practices for 2025, based on official Docker documentation and industry standards.
## File Format Changes (2025)
**IMPORTANT:** The `version` field is now **obsolete** in Docker Compose v2.42+.
**Correct (2025):**
```yaml
services:
app:
image: myapp:latest
```
**Incorrect (deprecated):**
```yaml
version: '3.8' # DO NOT USE
services:
app:
image: myapp:latest
```
## Multiple Environment Strategy
### Pattern: Base + Environment Overrides
**compose.yaml (base):**
```yaml
services:
app:
build:
context: ./app
dockerfile: Dockerfile
environment:
- NODE_ENV=production
restart: unless-stopped
```
**compose.override.yaml (development - auto-loaded):**
```yaml
services:
app:
build:
target: development
volumes:
- ./app/src:/app/src:cached
environment:
- NODE_ENV=development
- DEBUG=*
ports:
- "9229:9229" # Debugger
```
**compose.prod.yaml (production - explicit):**
```yaml
services:
app:
build:
target: production
deploy:
replicas: 3
resources:
limits:
cpus: '1'
memory: 512M
restart_policy:
condition: on-failure
max_attempts: 3
```
**Usage:**
```bash
# Development (auto-loads compose.override.yaml)
docker compose up
# Production
docker compose -f compose.yaml -f compose.prod.yaml up -d
# CI/CD
docker compose -f compose.yaml -f compose.ci.yaml up --abort-on-container-exit
```
## Environment Variable Management
### Pattern: .env Files per Environment
**.env.template (committed to git):**
```bash
# Database
DB_HOST=sqlserver
DB_PORT=1433
DB_NAME=myapp
DB_USER=sa
# DB_PASSWORD= (set in actual .env)
# Redis
REDIS_HOST=redis
REDIS_PORT=6379
# REDIS_PASSWORD= (set in actual .env)
# Application
NODE_ENV=production
LOG_LEVEL=info
```
**.env.dev:**
```bash
DB_PASSWORD=Dev!Pass123
REDIS_PASSWORD=redis-dev-123
NODE_ENV=development
LOG_LEVEL=debug
```
**.env.prod:**
```bash
DB_PASSWORD=${PROD_DB_PASSWORD} # From CI/CD
REDIS_PASSWORD=${PROD_REDIS_PASSWORD}
NODE_ENV=production
LOG_LEVEL=info
```
**Load specific environment:**
```bash
docker compose --env-file .env.dev up
```
## Security Patterns
### Pattern: Run as Non-Root User
```yaml
services:
app:
image: node:20-alpine
user: "1000:1000" # UID:GID
read_only: true
tmpfs:
- /tmp
- /app/.cache
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE # Only if binding to ports < 1024
security_opt:
- no-new-privileges:true
```
**Create user in Dockerfile:**
```dockerfile
FROM node:20-alpine
# Create app user
RUN addgroup -g 1000 appuser && \
adduser -D -u 1000 -G appuser appuser
# Set ownership
WORKDIR /app
COPY --chown=appuser:appuser . .
USER appuser
```
### Pattern: Secrets Management
**Docker Swarm secrets (production):**
```yaml
services:
app:
secrets:
- db_password
- api_key
secrets:
db_password:
file: ./secrets/db_password.txt
api_key:
external: true # Managed by Swarm
```
**Access secrets in application:**
```javascript
// Read from /run/secrets/
const fs = require('fs');
const dbPassword = fs.readFileSync('/run/secrets/db_password', 'utf8').trim();
```
**Development alternative (environment):**
```yaml
services:
app:
environment:
- DB_PASSWORD_FILE=/run/secrets/db_password
```
## Health Check Patterns
### Pattern: Comprehensive Health Checks
**HTTP endpoint:**
```yaml
services:
web:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 3s
retries: 3
start_period: 40s
```
**Database ping:**
```yaml
services:
postgres:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER"]
interval: 10s
timeout: 3s
retries: 3
```
**Custom script:**
```yaml
services:
app:
healthcheck:
test: ["CMD", "node", "/app/scripts/healthcheck.js"]
interval: 30s
timeout: 3s
retries: 3
start_period: 40s
```
**healthcheck.js:**
```javascript
const http = require('http');
const options = {
hostname: 'localhost',
port: 8080,
path: '/health',
timeout: 2000
};
const req = http.request(options, (res) => {
process.exit(res.statusCode === 200 ? 0 : 1);
});
req.on('error', () => process.exit(1));
req.on('timeout', () => {
req.destroy();
process.exit(1);
});
req.end();
```
## Dependency Management
### Pattern: Ordered Startup with Conditions
```yaml
services:
web:
depends_on:
database:
condition: service_healthy
redis:
condition: service_started
migration:
condition: service_completed_successfully
database:
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 10s
redis:
# No health check needed, just wait for start
migration:
image: myapp:latest
command: npm run migrate
restart: "no" # Run once
depends_on:
database:
condition: service_healthy
```
## Network Isolation Patterns
### Pattern: Three-Tier Network Architecture
```yaml
services:
nginx:
image: nginx:alpine
networks:
- frontend
ports:
- "80:80"
api:
build: ./api
networks:
- frontend
- backend
database:
image: postgres:16-alpine
networks:
- backend # No frontend access
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # No external access
```
### Pattern: Service-Specific Networks
```yaml
services:
web-app:
networks:
- public
- app-network
api:
networks:
- app-network
- data-network
postgres:
networks:
- data-network
redis:
networks:
- data-network
networks:
public:
driver: bridge
app-network:
driver: bridge
internal: true
data-network:
driver: bridge
internal: true
```
## Volume Patterns
### Pattern: Named Volumes for Persistence
```yaml
services:
database:
volumes:
- db-data:/var/lib/postgresql/data # Persistent data
- ./init:/docker-entrypoint-initdb.d:ro # Init scripts (read-only)
- db-logs:/var/log/postgresql # Logs
volumes:
db-data:
driver: local
driver_opts:
type: none
o: bind
device: /mnt/data/postgres # Host path
db-logs:
driver: local
```
### Pattern: Development Bind Mounts
```yaml
services:
app:
volumes:
- ./src:/app/src:cached # macOS optimization
- /app/node_modules # Don't overwrite installed modules
- app-cache:/app/.cache # Named volume for cache
```
**Volume mount options:**
- `:ro` - Read-only
- `:rw` - Read-write (default)
- `:cached` - macOS performance optimization (host authoritative)
- `:delegated` - macOS performance optimization (container authoritative)
- `:z` - SELinux single container
- `:Z` - SELinux multi-container
## Resource Management Patterns
### Pattern: CPU and Memory Limits
```yaml
services:
app:
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
```
**Calculate total resources:**
```yaml
# 3 app replicas + database + redis
services:
app:
deploy:
replicas: 3
resources:
limits:
cpus: '0.5' # 3 x 0.5 = 1.5 CPUs
memory: 512M # 3 x 512M = 1.5GB
database:
deploy:
resources:
limits:
cpus: '2' # 2 CPUs
memory: 4G # 4GB
redis:
deploy:
resources:
limits:
cpus: '0.5' # 0.5 CPUs
memory: 512M # 512MB
# Total: 4 CPUs, 6GB RAM minimum
```
## Logging Patterns
### Pattern: Centralized Logging
```yaml
services:
app:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
compress: "true"
labels: "app,environment"
```
**Alternative: Log to stdout/stderr (12-factor):**
```yaml
services:
app:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
```
**View logs:**
```bash
docker compose logs -f app
docker compose logs --since 30m app
docker compose logs --tail 100 app
```
## Init Container Pattern
### Pattern: Database Migration
```yaml
services:
migration:
image: myapp:latest
command: npm run migrate
depends_on:
database:
condition: service_healthy
restart: "no" # Run once
networks:
- backend
app:
image: myapp:latest
depends_on:
migration:
condition: service_completed_successfully
networks:
- backend
```
## YAML Anchors and Aliases
### Pattern: Reusable Configuration
```yaml
x-common-app-config: &common-app
restart: unless-stopped
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
services:
app1:
<<: *common-app
build: ./app1
ports:
- "8001:8080"
app2:
<<: *common-app
build: ./app2
ports:
- "8002:8080"
app3:
<<: *common-app
build: ./app3
ports:
- "8003:8080"
```
### Pattern: Environment-Specific Overrides
```yaml
x-logging: &default-logging
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
x-resources: &default-resources
limits:
cpus: '1'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
services:
app:
logging: *default-logging
deploy:
resources: *default-resources
```
## Port Binding Patterns
### Pattern: Security-First Port Binding
```yaml
services:
# Public services
web:
ports:
- "80:8080"
- "443:8443"
# Development only (localhost binding)
debug:
ports:
- "127.0.0.1:9229:9229" # Debugger only accessible from host
# Environment-based binding
app:
ports:
- "${DOCKER_WEB_PORT_FORWARD:-127.0.0.1:8000}:8000"
```
**Environment control:**
```bash
# Development (.env.dev)
DOCKER_WEB_PORT_FORWARD=127.0.0.1:8000 # Localhost only
# Production (.env.prod)
DOCKER_WEB_PORT_FORWARD=8000 # All interfaces
```
## Restart Policy Patterns
```yaml
services:
# Always restart (production services)
app:
restart: always
# Restart unless manually stopped (most common)
database:
restart: unless-stopped
# Never restart (one-time tasks)
migration:
restart: "no"
# Restart on failure only (with Swarm)
worker:
deploy:
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
```
## Validation and Testing
### Pattern: Pre-Deployment Validation
```bash
#!/bin/bash
set -euo pipefail
echo "Validating Compose syntax..."
docker compose config > /dev/null
echo "Building images..."
docker compose build
echo "Running security scan..."
for service in $(docker compose config --services); do
image=$(docker compose config | yq ".services.$service.image")
if [ -n "$image" ]; then
docker scout cves "$image" || true
fi
done
echo "Starting services..."
docker compose up -d
echo "Checking health..."
sleep 10
docker compose ps
echo "Running smoke tests..."
curl -f http://localhost:8080/health || exit 1
echo "✓ All checks passed"
```
## Complete Production Example
```yaml
# Modern Compose format (no version field for v2.40+)
x-common-service: &common-service
restart: unless-stopped
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
security_opt:
- no-new-privileges:true
services:
nginx:
<<: *common-service
image: nginxinc/nginx-unprivileged:alpine
ports:
- "80:8080"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d:ro
networks:
- frontend
depends_on:
api:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/health"]
interval: 30s
api:
<<: *common-service
build:
context: ./api
dockerfile: Dockerfile
target: production
user: "1000:1000"
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
networks:
- frontend
- backend
depends_on:
migration:
condition: service_completed_successfully
redis:
condition: service_started
env_file:
- .env
healthcheck:
test: ["CMD", "node", "healthcheck.js"]
interval: 30s
start_period: 40s
deploy:
resources:
limits:
cpus: '1'
memory: 512M
migration:
image: myapp:latest
command: npm run migrate
restart: "no"
networks:
- backend
depends_on:
postgres:
condition: service_healthy
postgres:
<<: *common-service
image: postgres:16-alpine
environment:
- POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password
secrets:
- postgres_password
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 10s
deploy:
resources:
limits:
cpus: '1'
memory: 2G
redis:
<<: *common-service
image: redis:7.4-alpine
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis-data:/data
networks:
- backend
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true
volumes:
postgres-data:
driver: local
redis-data:
driver: local
secrets:
postgres_password:
file: ./secrets/postgres_password.txt
```
## Common Mistakes to Avoid
1. **Using `version` field** - Obsolete in 2025
2. **No health checks** - Leads to race conditions
3. **Running as root** - Security risk
4. **No resource limits** - Can exhaust host resources
5. **Hardcoded secrets** - Use secrets or environment variables
6. **No logging limits** - Disk space issues
7. **Bind mounts in production** - Use named volumes
8. **Missing restart policies** - Services don't recover
9. **No network isolation** - All services can talk to each other
10. **Not using .dockerignore** - Larger build contexts
## Troubleshooting Commands
```bash
# Validate syntax
docker compose config
# View merged configuration
docker compose config --services
# Check which file is being used
docker compose config --files
# View environment interpolation
docker compose config --no-interpolate
# Check service dependencies
docker compose config | yq '.services.*.depends_on'
# View resource usage
docker stats $(docker compose ps -q)
# Debug startup issues
docker compose up --no-deps service-name
# Force recreate
docker compose up --force-recreate service-name
```
## References
- [Docker Compose Documentation](https://docs.docker.com/compose/)
- [Compose v2.42+ Release Notes](https://github.com/docker/compose/releases)
- [Best Practices](https://docs.docker.com/compose/how-tos/production/)

View File

@@ -0,0 +1,42 @@
# Docker Compose Watch Mode (2025 GA)
Docker Compose Watch enables automatic hot reload during local development by synchronizing file changes instantly without manual container restarts.
## Three Watch Actions
### 1. sync - Hot Reload
For frameworks with hot reload (React, Next.js, Node.js, Flask).
Copies changed files directly into running container.
### 2. rebuild - Compilation
For compiled languages (Go, Rust, Java) or dependency changes.
Rebuilds image and recreates container when files change.
### 3. sync+restart - Config Changes
For configuration files requiring restart.
Syncs files and restarts container.
## Usage
```yaml
services:
frontend:
build: ./frontend
develop:
watch:
- action: sync
path: ./frontend/src
target: /app/src
ignore: [node_modules/, .git/]
- action: rebuild
path: ./frontend/package.json
```
Start with: `docker compose up --watch`
## Benefits
- Better performance than bind mounts
- No file permission issues
- Intelligent syncing
- Supports rebuild capability
- Works on all platforms