2026-01-14 04:56:20 +00:00
# Docker Compose Templates
Nickel-based Docker Compose templates for deploying platform services across all deployment modes.
## Overview
This directory contains Nickel templates that generate Docker Compose files for different deployment scenarios.
Each template imports configuration from `values/*.ncl` and expands to valid Docker Compose YAML.
**Key Pattern**: Templates use **Nickel composition** to build service definitions dynamically based on configuration, allowing parameterized infrastructure-as-code.
## Templates
### 1. platform-stack.solo.yml.ncl
**Purpose**: Single-developer local development stack
**Services**:
- `orchestrator` - Workflow engine
- `control-center` - Policy and RBAC management
- `mcp-server` - MCP protocol server
**Configuration**:
- Network: Bridge network named `provisioning`
- Volumes: 5 named volumes for persistence
- `orchestrator-data` - Orchestrator workflows
- `control-center-data` - Control Center policies
- `mcp-server-data` - MCP Server cache
- `logs` - Shared log volume
- `cache` - Shared cache volume
- Ports:
- 9090 - Orchestrator API
- 8080 - Control Center UI
- 8888 - MCP Server
- Health Checks: 30-second intervals for all services
- Logging: JSON format, 10MB max file size, 3 backups
- Restart Policy: `unless-stopped` (survives host reboot)
**Usage**:
```bash
# Generate from Nickel template
nickel export --format json platform-stack.solo.yml.ncl | yq -P > docker-compose.solo.yml
# Start services
docker-compose -f docker-compose.solo.yml up -d
# View logs
docker-compose -f docker-compose.solo.yml logs -f
# Stop services
docker-compose -f docker-compose.solo.yml down
```
**Environment Variables** (recommended in `.env` file):
```bash
ORCHESTRATOR_LOG_LEVEL=debug
CONTROL_CENTER_LOG_LEVEL=info
MCP_SERVER_LOG_LEVEL=info
```
---
### 2. platform-stack.multiuser.yml.ncl
**Purpose**: Team collaboration with persistent database storage
**Services** (6 total):
- `postgres` - Primary database (PostgreSQL 15)
- `orchestrator` - Workflow engine
- `control-center` - Policy and RBAC management
- `mcp-server` - MCP protocol server
- `surrealdb` - Workflow storage (SurrealDB server)
- `gitea` - Git repository hosting (optional, for version control)
**Configuration**:
- Network: Custom bridge network named `provisioning-network`
- Volumes:
- `postgres-data` - PostgreSQL database files
- `orchestrator-data` - Orchestrator workflows
- `control-center-data` - Control Center policies
- `surrealdb-data` - SurrealDB files
- `gitea-data` - Gitea repositories and configuration
- `logs` - Shared logs
- Ports:
- 9090 - Orchestrator API
- 8080 - Control Center UI
- 8888 - MCP Server
- 5432 - PostgreSQL (internal only)
- 8000 - SurrealDB (internal only)
- 3000 - Gitea web UI (optional)
- 22 - Gitea SSH (optional)
- Service Dependencies: Explicit `depends_on` with health checks
- Control Center waits for PostgreSQL
- SurrealDB starts before Orchestrator
- Health Checks: Service-specific health checks
- Restart Policy: `always` (automatic recovery on failure)
- Logging: JSON format with rotation
**Usage**:
```bash
# Generate from Nickel template
nickel export --format json platform-stack.multiuser.yml.ncl | yq -P > docker-compose.multiuser.yml
# Create environment file
cat > .env.multiuser < < 'EOF'
DB_PASSWORD=secure-postgres-password
SURREALDB_PASSWORD=secure-surrealdb-password
JWT_SECRET=secure-jwt-secret-256-bits
EOF
# Start services
docker-compose -f docker-compose.multiuser.yml --env-file .env.multiuser up -d
# Wait for all services to be healthy
docker-compose -f docker-compose.multiuser.yml ps
# Create database and initialize schema (one-time)
docker-compose exec postgres psql -U postgres -c "CREATE DATABASE provisioning;"
```
**Database Initialization**:
```bash
# Connect to PostgreSQL for schema creation
docker-compose exec postgres psql -U provisioning -d provisioning
# Connect to SurrealDB for schema setup
docker-compose exec surrealdb surreal sql --auth root:password
# Connect to Gitea web UI
# http://localhost:3000 (admin:admin by default)
```
**Environment Variables** (in `.env.multiuser` ):
```bash
# Database Credentials (CRITICAL - change before production)
DB_PASSWORD=your-strong-password
SURREALDB_PASSWORD=your-strong-password
# Security
JWT_SECRET=your-256-bit-random-string
# Logging
ORCHESTRATOR_LOG_LEVEL=info
CONTROL_CENTER_LOG_LEVEL=info
MCP_SERVER_LOG_LEVEL=info
# Optional: Gitea Configuration
GITEA_DOMAIN=localhost:3000
GITEA_ROOT_URL=http://localhost:3000/
```
---
### 3. platform-stack.cicd.yml.ncl
**Purpose**: Ephemeral CI/CD pipeline stack with minimal persistence
**Services** (2 total):
- `orchestrator` - API-only mode (no UI, streamlined for programmatic use)
- `api-gateway` - Optional: Request routing and authentication
**Configuration**:
- Network: Bridge network
- Volumes:
- `orchestrator-tmpfs` - Temporary storage (tmpfs - in-memory, no persistence)
- Ports:
- 9090 - Orchestrator API (read-only orchestrator state)
- 8000 - API Gateway (optional)
- Health Checks: Fast checks (10-second intervals)
- Restart Policy: `no` (containers do not auto-restart)
- Logging: Minimal (only warnings and errors)
- Cleanup: All artifacts deleted when containers stop
**Characteristics**:
- **Ephemeral**: No persistent storage (uses tmpfs)
- **Fast Startup**: Minimal services, quick boot time
- **API-First**: No UI, command-line/API integration only
- **Stateless**: Clean slate each run
- **Low Resource**: Minimal memory/CPU footprint
**Usage**:
```bash
# Generate from Nickel template
nickel export --format json platform-stack.cicd.yml.ncl | yq -P > docker-compose.cicd.yml
# Start ephemeral stack
docker-compose -f docker-compose.cicd.yml up
# Run CI/CD commands (in parallel terminal)
curl -X POST http://localhost:9090/api/workflows
-H "Content-Type: application/json"
-d @workflow .json
# Stop and cleanup (all data lost)
docker-compose -f docker-compose.cicd.yml down
# Or with volume cleanup
docker-compose -f docker-compose.cicd.yml down -v
```
**CI/CD Integration Example**:
```bash
# GitHub Actions workflow
- name: Start Provisioning Stack
run: docker-compose -f docker-compose.cicd.yml up -d
- name: Run Tests
run: |
./tests/integration.sh
curl -X GET http://localhost:9090/health
- name: Cleanup
if: always()
run: docker-compose -f docker-compose.cicd.yml down -v
```
**Environment Variables** (minimal):
```bash
# Logging (optional)
ORCHESTRATOR_LOG_LEVEL=warn
```
---
### 4. platform-stack.enterprise.yml.ncl
**Purpose**: Production-grade high-availability deployment
**Services** (10+ total):
- `postgres` - PostgreSQL 15 (primary database)
- `orchestrator` (3 replicas) - Load-balanced workflow engine
- `control-center` (2 replicas) - Load-balanced policy management
- `mcp-server` (1-2 replicas) - MCP server for AI integration
- `surrealdb-1` , `surrealdb-2` , `surrealdb-3` - SurrealDB cluster (3 nodes)
- `nginx` - Load balancer and reverse proxy
- `prometheus` - Metrics collection
- `grafana` - Visualization and dashboards
- `loki` - Log aggregation
**Configuration**:
- Network: Custom bridge network named `provisioning-enterprise`
- Volumes:
- `postgres-data` - PostgreSQL HA storage
- `surrealdb-node-1` , `surrealdb-node-2` , `surrealdb-node-3` - Cluster storage
- `prometheus-data` - Metrics storage
- `grafana-data` - Grafana configuration
- `loki-data` - Log storage
- `logs` - Shared log aggregation
- Ports:
- 80 - HTTP (Nginx reverse proxy)
- 443 - HTTPS (TLS - requires certificates)
- 9090 - Orchestrator API (internal)
- 8080 - Control Center UI (internal)
- 8888 - MCP Server (internal)
- 5432 - PostgreSQL (internal only)
- 8000 - SurrealDB cluster (internal)
- 9091 - Prometheus metrics (internal)
- 3000 - Grafana dashboards (external)
- Service Dependencies:
- Control Center waits for PostgreSQL
- Orchestrator waits for SurrealDB cluster
- MCP Server waits for Orchestrator and Control Center
- Prometheus waits for all services
- Health Checks: 30-second intervals with 10-second timeout
- Restart Policy: `always` (high availability)
- Load Balancing: Nginx upstream blocks for orchestrator, control-center
- Logging: JSON format with 500MB files, kept 30 versions
**Architecture**:
```bash
┌──────────────────────┐
│ External Client │
│ (HTTPS, Port 443) │
└──────────┬───────────┘
│
┌──────▼──────────┐
│ Nginx Load │
│ Balancer │
│ (TLS, CORS, │
│ Rate Limiting) │
└───────┬──────┬──────┬─────┐
│ │ │ │
┌────────▼──┐ ┌──────▼──┐ ┌──▼────────┐
│Orchestrator│ │Control │ │MCP Server │
│ (3 copies) │ │ Center │ │ (1-2 copy)│
│ │ │(2 copies)│ │ │
└────────┬──┘ └─────┬───┘ └──┬───────┘
│ │ │
┌───────▼────────┬──▼────┐ │
│ SurrealDB │ PostSQL │
│ Cluster │ HA │
│ (3 nodes) │ (Primary/│
│ │ Replica)│
└────────────────┴──────────┘
Observability Stack:
┌────────────┬───────────┬───────────┐
│ Prometheus │ Grafana │ Loki │
│ (Metrics) │(Dashboard)│ (Logs) │
└────────────┴───────────┴───────────┘
```
**Usage**:
```bash
# Generate from Nickel template
nickel export --format json platform-stack.enterprise.yml.ncl | yq -P > docker-compose.enterprise.yml
# Create environment file with secrets
cat > .env.enterprise < < 'EOF'
# Database
DB_PASSWORD=generate-strong-password
SURREALDB_PASSWORD=generate-strong-password
# Security
JWT_SECRET=generate-256-bit-random-string
ADMIN_PASSWORD=generate-strong-admin-password
# TLS Certificates
TLS_CERT_PATH=/path/to/cert.pem
TLS_KEY_PATH=/path/to/key.pem
# Logging and Monitoring
PROMETHEUS_RETENTION=30d
GRAFANA_ADMIN_PASSWORD=generate-strong-password
LOKI_RETENTION_DAYS=30
EOF
# Start entire stack
docker-compose -f docker-compose.enterprise.yml --env-file .env.enterprise up -d
# Verify all services are healthy
docker-compose -f docker-compose.enterprise.yml ps
# Check load balancer status
curl -H "Host: orchestrator.example.com" http://localhost/health
# Access monitoring
# Grafana: http://localhost:3000 (admin/password)
# Prometheus: http://localhost:9091 (internal)
# Loki: http://localhost:3100 (internal)
```
**Production Checklist**:
- [ ] Generate strong database passwords (32+ characters)
- [ ] Generate strong JWT secret (256-bit random string)
- [ ] Provision valid TLS certificates (not self-signed)
- [ ] Configure Nginx upstream health checks
- [ ] Set up log retention policies (30+ days)
- [ ] Enable Prometheus scraping with 15-second intervals
- [ ] Configure Grafana dashboards and alerts
- [ ] Test SurrealDB cluster failover
- [ ] Document backup procedures
- [ ] Enable PostgreSQL replication and backups
- [ ] Configure external log aggregation (ELK stack, Splunk, etc.)
**Environment Variables** (in `.env.enterprise` ):
```bash
# Database Credentials (CRITICAL)
DB_PASSWORD=your-strong-password-32-chars-min
SURREALDB_PASSWORD=your-strong-password-32-chars-min
# Security
JWT_SECRET=your-256-bit-random-base64-encoded-string
ADMIN_PASSWORD=your-strong-admin-password
# TLS/HTTPS
TLS_CERT_PATH=/etc/provisioning/certs/server.crt
TLS_KEY_PATH=/etc/provisioning/certs/server.key
# Logging and Monitoring
PROMETHEUS_RETENTION=30d
PROMETHEUS_SCRAPE_INTERVAL=15s
GRAFANA_ADMIN_USER=admin
GRAFANA_ADMIN_PASSWORD=your-strong-grafana-password
LOKI_RETENTION_DAYS=30
# Optional: External Integrations
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/xxxxxxx
PAGERDUTY_INTEGRATION_KEY=your-pagerduty-key
```
---
## Workflow: From Nickel to Docker Compose
### 1. Configuration Source (values/*.ncl)
```nickel
# values/orchestrator.enterprise.ncl
{
orchestrator = {
server = {
host = "0.0.0.0",
port = 9090,
workers = 8,
},
storage = {
backend = 'surrealdb_cluster,
surrealdb_url = "surrealdb://surrealdb-1:8000",
},
queue = {
max_concurrent_tasks = 100,
retry_attempts = 5,
task_timeout = 7200000,
},
monitoring = {
enabled = true,
metrics_interval = 10,
},
},
}
```
### 2. Template Generation (Nickel → JSON)
```nickel
# Exports Nickel config as JSON
nickel export --format json platform-stack.enterprise.yml.ncl
```
### 3. YAML Conversion (JSON → YAML)
```yaml
# Converts JSON to YAML format
nickel export --format json platform-stack.enterprise.yml.ncl | yq -P > docker-compose.enterprise.yml
```
### 4. Deployment (YAML → Running Containers)
```yaml
# Starts all services defined in YAML
docker-compose -f docker-compose.enterprise.yml up -d
```
---
## Common Customizations
### Change Service Replicas
Edit the template to adjust replica counts:
```bash
# In platform-stack.enterprise.yml.ncl
let orchestrator_replicas = 5 in # Instead of 3
let control_center_replicas = 3 in # Instead of 2
services.orchestrator_replicas
```
### Add Custom Service
Add to the template services record:
```bash
# In platform-stack.enterprise.yml.ncl
services = base_services & {
custom_service = {
image = "custom:latest",
ports = ["9999:9999"],
volumes = ["custom-data:/data"],
restart = "always",
healthcheck = {
test = ["CMD", "curl", "-f", "http://localhost:9999/health"],
interval = "30s",
timeout = "10s",
retries = 3,
},
},
}
```
### Modify Resource Limits
In each service definition:
```bash
orchestrator = {
deploy = {
resources = {
limits = {
cpus = "2.0",
memory = "2G",
},
reservations = {
cpus = "1.0",
memory = "1G",
},
},
},
}
```
---
## Validation and Testing
### Syntax Validation
```bash
# Validate YAML before deploying
docker-compose -f docker-compose.enterprise.yml config --quiet
# Check service definitions
docker-compose -f docker-compose.enterprise.yml ps
```
### Health Checks
```bash
# Monitor health of all services
watch docker-compose ps
# Check specific service health
docker-compose exec orchestrator curl -s http://localhost:9090/health
```
### Log Inspection
```bash
# View logs from all services
docker-compose logs -f
# View logs from specific service
docker-compose logs -f orchestrator
# Follow specific container
docker logs -f $(docker ps | grep orchestrator | awk '{print $1}')
```
---
## Troubleshooting
### Port Already in Use
**Error**: `bind: address already in use`
**Fix**: Change port in template or stop conflicting container:
```bash
# Find process using port
lsof -i :9090
# Kill process
kill -9 < PID >
# Or change port in docker-compose file
ports:
- "9999:9090" # Use 9999 instead
```
### Service Fails to Start
**Check logs**:
```bash
docker-compose logs orchestrator
```
**Common causes**:
- Port conflict - Check if another service uses port
- Missing volume - Create volume before starting
- Network connectivity - Verify docker network exists
- Database not ready - Wait for db service to become healthy
- Configuration error - Validate YAML syntax
### Persistent Volume Issues
**Clean volumes** (WARNING: Deletes data):
```bash
docker-compose down -v
docker volume prune -f
```
---
## See Also
- **Kubernetes Templates**: `../kubernetes/` - For production K8s deployments
- **Configuration System**: `../../` - Full configuration documentation
- **Examples**: `../../examples/` - Example deployment scenarios
- **Scripts**: `../../scripts/` - Automation scripts
---
**Version**: 1.0
**Last Updated**: 2025-01-05
**Status**: Production Ready