Docker Compose Profiles Guide
This guide explains how to use Docker Compose profiles and multi-file configurations for deploying the CTMS platform.
Overview
Docker Compose profiles provide a modular approach to deploying services. Instead of starting all services at once, you can selectively start groups of related services based on your needs.
Profile Structure
The CTMS platform uses the following profiles:
| Profile | Services | Use Case |
|---|---|---|
| (none) | Caddy, API Gateway, Zynexa, Sublink | Always on — start with any docker compose up |
| core | ODM API | Report generation (adds to always-on services) |
| analytics | Cube.dev, Cubestore, MCP Server | Data analytics and AI agent |
| observability | OpenObserve, OTEL Collector | Logging, metrics, and traces |
| linux-logs | Fluent Bit | Multiline log aggregation (Linux production only) |
| lakehouse | Lakehouse DB, Ingester, dbt | Data pipeline (ELT into analytics warehouse) |
| init | ctms-init, ctms-supabase-seed, ctms-user-seed | One-shot provisioning containers (run once, then exit) |
| all | Everything (except linux-logs) | Full platform deployment |
Profile Naming Rationale
-
core — The ODM API service that adds report generation on top of always-on services (Caddy, API Gateway, Zynexa, Sublink).
-
analytics — Data analytics stack including Cube.dev (semantic layer for data analysis), Cubestore (pre-aggregation cache), and MCP Server (AI-powered natural language queries).
-
observability — Monitoring and logging infrastructure. Separated to allow selective deployment — not always needed in development but essential for production.
-
lakehouse — Data pipeline stack for extracting, loading, and transforming data into an analytics warehouse using dbt.
-
linux-logs — Fluent Bit for multiline Docker log aggregation. Only needed on Linux production servers; excluded from
allprofile. -
init — One-shot provisioning containers. These run once to seed databases and configure Frappe, then exit. Use
--profile initonly during initial setup.
Startup Order (Self-Hosted)
When running the full self-hosted stack (Supabase + Frappe + CTMS), services must be started in this order:
| Order | Stack | Command | Why |
|---|---|---|---|
| 1 | Supabase | cd supabase && docker compose up -d | Database and auth must be ready first |
| 2 | Frappe | cd frappe-marley-health && docker compose up -d | ERP and DocTypes needed before CTMS init |
| 3 | CTMS seed | docker compose --profile init run --rm ctms-supabase-seed | Creates CTMS tables in Supabase |
| 4 | CTMS init | docker compose --profile init up ctms-init | Provisions Frappe DocTypes, RBAC, seed data |
| 5 | User seed | docker compose --profile init up ctms-user-seed | Seeds 4 demo users into Supabase Auth + Zynexa |
| 6 | CTMS core | docker compose -f ... --profile all up -d | Application services connect to Supabase + Frappe |
The zynctl.sh deploy command handles this entire sequence automatically. The order above is for manual or developer deployments only.
Docker Compose Commands Explained
Basic Profile Commands
# Start core services only
docker compose --profile core up -d
# Start analytics stack
docker compose --profile analytics up -d
# Combine profiles
docker compose --profile core --profile analytics up -d
# Start everything
docker compose --profile all up -d
Multi-file Configuration
Docker Compose supports merging multiple configuration files:
docker compose -f docker-compose.yml -f docker-compose.prod.yml --profile all up -d
Flag Breakdown
| Flag | Purpose | Example |
|---|---|---|
-f <file> | Specify compose file | -f docker-compose.yml |
--profile <name> | Enable a profile | --profile analytics |
up | Create and start containers | - |
-d | Run in detached mode | - |
config | Validate and output merged config | - |
How Multi-file Merging Works
When multiple files are specified with -f, Docker Compose merges them in order. Later files override earlier ones:
docker compose -f docker-compose.yml -f docker-compose.prod.yml config
This command:
- Reads
docker-compose.yml(base configuration) - Reads
docker-compose.prod.yml(overrides) - Merges them together (prod overrides base)
- Outputs the final merged configuration
Use cases for multi-file:
docker-compose.yml- Base configuration (networks, volumes, service definitions)docker-compose.prod.yml- Production overrides (direct port exposure, different images)docker-compose.override.yml- Local development overrides (auto-loaded if present)
Validate Configuration
Before deploying, validate your configuration:
# Validate and see merged output
docker compose --profile all config
# Validate with production overrides
docker compose -f docker-compose.yml -f docker-compose.prod.yml --profile all config
Common Commands Reference
Starting Services
# Development (with local HTTPS)
docker compose --profile core up -d
# Production with overrides
docker compose -f docker-compose.yml -f docker-compose.prod.yml --profile all up -d
Viewing Logs
# All services
docker compose logs -f
# Specific service
docker compose logs -f zynexa
# Last 100 lines
docker compose logs --tail=100 -f
Service Management
# Stop all services
docker compose down
# Stop and remove volumes
docker compose down -v
# Restart a specific service
docker compose restart zynexa
# Check service status
docker compose ps
Updating Images
# Pull latest images (all CTMS images are pre-built via CI)
docker compose pull
# Update a service with new image
docker compose pull zynexa && docker compose up -d zynexa
Services Without Profiles (Always-On)
Services without a profile assignment will always start regardless of which profile is selected. In the CTMS stack, the following services always start when any docker compose up command is run:
caddy— Reverse proxy (always needed)api-gateway— KrakenD API Gateway (always needed)zynexa— Main CTMS web applicationsublink— Mobile companion app
Profile Dependencies
Some profiles have implicit dependencies:
-
analytics profile: The MCP Server depends on Cube.dev for natural language queries. Both are included in the analytics profile.
-
observability profile: OTEL Collector sends data to OpenObserve. Both must run together.
Make Commands
The Makefile wraps all Docker Compose profile commands with sensible defaults. Quick examples:
make help # Show all available commands and URLs
make up # Start core services
make up-all # Start all profiles
make down # Stop everything
make health # Check health of all services
For the complete list of Make targets — including logs, shell access, provisioning, data pipeline, and vendor stack commands — see the Platform Runbook.
Production Deployment
For production deployment on a Linux VM, use the Bundle Deployment approach — the recommended method:
# One-command deploy using zynctl
SERVER_HOST=<your-ip> ./zynctl.sh full-deploy
The bundle includes all compose files, configs, and setup scripts. zynctl.sh handles the full startup sequence (Supabase → Frappe → seed → init → CTMS core) automatically.
Troubleshooting
Profile Not Starting
Ensure you're using the correct profile name:
# ❌ Wrong
docker compose --profile ai up -d
# ✅ Correct
docker compose --profile analytics up -d
Services Missing
Check if services are assigned to profiles:
docker compose config --services
docker compose --profile all config --services
Configuration Validation Errors
# Validate before running
docker compose config
View Effective Configuration
# See exactly what Docker Compose will run
docker compose --profile core config > debug-config.yml