Initial commit
This commit is contained in:
643
skills/azure-emulators-2025.md
Normal file
643
skills/azure-emulators-2025.md
Normal 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)
|
||||
860
skills/compose-patterns-2025.md
Normal file
860
skills/compose-patterns-2025.md
Normal 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/)
|
||||
42
skills/docker-watch-mode-2025.md
Normal file
42
skills/docker-watch-mode-2025.md
Normal 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
|
||||
Reference in New Issue
Block a user