Skip to content

Docker Setup

Guide for running TradAI services with Docker.


Prerequisites

  • Docker: 20.10+ (Install Guide)
  • Docker Compose: 2.0+ (included with Docker Desktop)
  • ~8GB RAM available for Docker

Quick Start

# Clone repository
git clone https://github.com/tradai-bot/tradai.git
cd tradai

# Copy environment files (or run just setup which does this automatically)
cp .env.example .env
cp .env.docker.example .env.docker

# Start services
just up

# View logs
docker compose logs -f

# Stop services
just down

Docker Compose Services

graph TD
    Backend["Backend API<br/>:8000"] --> DC["Data Collection<br/>:8002"]
    Backend --> SS["Strategy Service<br/>:8003"]
    Backend --> MLflow["MLflow<br/>:5001"]
    Backend --> DDB["DynamoDB<br/>LocalStack"]
    SS --> MLflow
    DC --> Arctic["ArcticDB<br/>LocalStack S3"]
    MLflow --> PG["PostgreSQL<br/>:5433"]

Core Services

Service Port Description
backend 8000 API Gateway
data-collection 8002 Market data sync
strategy-service 8003 Strategy execution
mlflow 5001 ML experiment tracking (optional)

MLflow is an optional service that requires --profile mlflow to start: docker compose --profile mlflow up or use just up-full to start all profiles (MLflow, LocalStack, Redis).

MLflow port mapping: MLflow runs on port 5000 inside the Docker network. Host port 5001 is mapped for browser access. Service-to-service communication uses port 5000 (e.g., http://mlflow:5000). Local browser access uses port 5001 (e.g., http://localhost:5001).

Infrastructure

Service Port Description
postgres 5433 (host) → 5432 (container) MLflow backend store
localstack 4566 Local AWS services

Note: Postgres host port mapping (5433) is only available in docker-compose.override.yaml (dev). Base compose does not expose Postgres to host.


Configuration

Environment Files

.env                           # Shared config
services/backend/.env          # Backend-specific
services/data-collection/.env  # Data collection-specific
services/strategy-service/.env # Strategy service-specific

Docker Network

Services communicate via two Docker networks: tradai-internal (service-to-service traffic, including databases) and tradai-external (services that need outbound internet access):

# Internal service URLs
BACKEND_DATA_COLLECTION_URL=http://data-collection:8002
BACKEND_STRATEGY_SERVICE_URL=http://strategy-service:8003
BACKEND_MLFLOW_TRACKING_URI=http://mlflow:5000
STRATEGY_SERVICE_MLFLOW_TRACKING_URI=http://mlflow:5000

Building Images

Build All Services

# Build all images
docker compose build

# Build specific service
docker compose build backend

# Build with no cache
docker compose build --no-cache

Multi-Stage Builds

Our Dockerfiles use multi-stage builds for optimal image size:

# Stage 1: Build wheel
FROM python:3.11-slim AS builder
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
WORKDIR /build
COPY . .
RUN uv build --wheel

# Stage 2: Runtime
FROM python:3.11-slim AS runtime
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
COPY --from=builder /build/dist/*.whl /wheels/
RUN uv pip install --system /wheels/*.whl
CMD ["backend", "serve"]

Image Tags

# Tag for development
TAG=dev docker compose build

# Tag for production
TAG=v1.0.0 docker compose build

Volume Mounts

Development Volumes

Note: Hot-reloading is not done via Docker volume mounts. For development, use uv run locally instead of Docker. See docker-compose.override.yaml for dev-specific mounts (user_data, strategies, AWS credentials).

Data Persistence

# Base volumes (always created)
postgres-data:    # MLflow database
user-data:        # Freqtrade user data

# Optional profile volumes (docker-compose.override.yaml)
mlflow-data:      # ML artifacts (profile: mlflow)
localstack-data:  # LocalStack state (profile: localstack)
redis-data:       # Redis cache (profile: redis)

Clear Volumes

# Remove all volumes (WARNING: deletes data)
docker compose down -v

# Remove specific volume
docker volume rm tradai_postgres_data

LocalStack (Local AWS)

LocalStack provides local AWS service emulation.

Supported Services

  • S3: ArcticDB storage, config files
  • SQS: Backtest job queues
  • DynamoDB: State tracking
  • Secrets Manager: Credentials (dev only)

Configuration

LocalStack configuration variables are set in docker-compose.override.yaml environment blocks:

DATA_COLLECTION_ARCTIC_S3_ENDPOINT=localstack:4566
DATA_COLLECTION_ARCTIC_USE_SSL=false
DATA_COLLECTION_ARCTIC_USE_VIRTUAL_ADDRESSING=false
DATA_COLLECTION_ARCTIC_ACCESS_KEY=test
DATA_COLLECTION_ARCTIC_SECRET_KEY=test

Verify LocalStack

# List S3 buckets
aws --endpoint-url=http://localhost:4566 s3 ls

# Create bucket
aws --endpoint-url=http://localhost:4566 s3 mb s3://tradai-dev

Health Checks

Service Health

# Check backend health
curl http://localhost:8000/api/v1/health

# Check all services
for port in 8000 8002 8003; do
  echo "Port $port: $(curl -s http://localhost:$port/api/v1/health | jq -r '.status')"
done
# MLflow uses a different health path
echo "Port 5001: $(curl -s http://localhost:5001/health | jq -r '.status')"

Docker Health Status

# View container health
docker compose ps

# Detailed health info
docker inspect --format='{{json .State.Health}}' tradai-backend-1 | jq

Logging

View Logs

# All services
docker compose logs -f

# Specific service
docker compose logs -f backend

# Last 100 lines
docker compose logs --tail=100 backend

# Since timestamp
docker compose logs --since="2024-01-01T00:00:00" backend

Log Levels

# Set in .env
BACKEND_LOG_LEVEL=DEBUG

Debugging

Shell Access

# Open shell in running container
docker compose exec backend bash

# Run one-off container
docker compose run --rm backend bash

Python REPL

# Interactive Python with project context
docker compose exec backend python -c "
from tradai.common import ExchangeConfig, TradingMode
config = ExchangeConfig(name='binance', trading_mode=TradingMode.FUTURES)
print(config)
"

Debug Mode

# Enable debug mode
BACKEND_DEBUG=true docker compose up backend

Common Issues

Port Conflicts

# Check what's using a port
lsof -i :8000

# Use different ports
HOST_BACKEND_PORT=8080 docker compose up backend

Permission Issues

# Fix volume permissions
sudo chown -R $USER:$USER ./data

Memory Issues

# Increase Docker memory limit
# Docker Desktop > Settings > Resources > Memory: 8GB

# Check container memory usage
docker stats

Container Won't Start

# View container logs
docker compose logs backend

# Check container status
docker compose ps -a

# Rebuild from scratch
docker compose down -v
docker compose build --no-cache
docker compose up

Production Docker

ECR Push

# Login to ECR
aws ecr get-login-password --region eu-central-1 | \
  docker login --username AWS --password-stdin 123456789.dkr.ecr.eu-central-1.amazonaws.com

# Tag and push
docker tag tradai-backend:latest 123456789.dkr.ecr.eu-central-1.amazonaws.com/tradai-backend:v1.0.0
docker push 123456789.dkr.ecr.eu-central-1.amazonaws.com/tradai-backend:v1.0.0

Security Best Practices

  1. Non-root user: Run containers as non-root
  2. Read-only filesystem: Use read_only: true where possible
  3. No secrets in images: Use environment variables or Secrets Manager
  4. Minimal base images: Use -slim or distroless images
  5. Security scanning: Use docker scan or Trivy

See Also