This guide explains how to build and run Matchbook services using Docker.
- Docker 24.0+
- Docker Compose 2.20+
- At least 8GB RAM available for Docker
Start PostgreSQL and Redis without building the Rust services:
docker-compose -f Docker/docker-compose.yml up -d postgres redisBuild and start all services:
docker-compose -f Docker/docker-compose.yml up -d# All services
docker-compose -f Docker/docker-compose.yml logs -f
# Specific service
docker-compose -f Docker/docker-compose.yml logs -f api# Stop but keep volumes
docker-compose -f Docker/docker-compose.yml down
# Stop and remove volumes (clean slate)
docker-compose -f Docker/docker-compose.yml down -v| Service | Port | Description |
|---|---|---|
postgres |
5432 | PostgreSQL with TimescaleDB |
redis |
6379 | Redis for caching and pub/sub |
indexer |
9090 | Geyser indexer (metrics) |
api |
8080, 8081 | REST API and WebSocket |
crank |
9091 | Crank service (metrics) |
Create a .env file in the project root:
# Logging
RUST_LOG=info
# Solana
SOLANA_RPC_URL=https://api.devnet.solana.com
# Geyser (for indexer)
GEYSER_ENDPOINT=http://your-geyser-endpoint:10000
GEYSER_X_TOKEN=your-auth-token
# Crank
CRANK_KEYPAIR=your-base58-encoded-keypair
MIN_PROFIT_LAMPORTS=1000
MAX_MATCHES_PER_TX=8docker-compose -f Docker/docker-compose.yml builddocker-compose -f Docker/docker-compose.yml build apidocker-compose -f Docker/docker-compose.yml build --no-cacheAll Docker-related files are located in the Docker/ directory:
Docker/
├── .dockerignore # Files to exclude from build context
├── api.Dockerfile # API server image
├── crank.Dockerfile # Crank service image
├── docker-compose.yml # Local development compose
├── docker-compose.prod.yml # Production compose
└── indexer.Dockerfile # Indexer service image
# Create builder
docker buildx create --name matchbook-builder --use
# Build and push multi-arch images
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t ghcr.io/joaquinbejar/matchbook-api:latest \
-f Docker/api.Dockerfile \
--push .# Set required environment variables
export DATABASE_URL=postgres://user:pass@your-postgres:5432/matchbook
export REDIS_URL=redis://your-redis:6379
export GEYSER_ENDPOINT=http://your-geyser:10000
export GEYSER_X_TOKEN=your-token
export SOLANA_RPC_URL=https://api.mainnet-beta.solana.com
export CRANK_KEYPAIR=your-keypair
# Start services
docker-compose -f Docker/docker-compose.prod.yml up -d# Pull latest images
docker-compose -f Docker/docker-compose.prod.yml pull
# Start with specific version
VERSION=v1.0.0 docker-compose -f Docker/docker-compose.prod.yml up -dAll services expose health endpoints:
# API health
curl http://localhost:8080/health
# Indexer health
curl http://localhost:9090/health
# Crank health
curl http://localhost:9091/healthCheck logs:
docker-compose -f Docker/docker-compose.yml logs <service-name>Verify PostgreSQL is healthy:
docker-compose -f Docker/docker-compose.yml exec postgres pg_isready -U matchbookIncrease Docker memory limit or reduce service resources in docker-compose.yml.
Clear build cache:
docker builder prune -a
docker-compose -f Docker/docker-compose.yml build --no-cacheTarget sizes for production images:
| Image | Target Size |
|---|---|
| matchbook-indexer | < 100MB |
| matchbook-api | < 100MB |
| matchbook-crank | < 80MB |
Check actual sizes:
docker images | grep matchbook- All services run as non-root user (UID 1000)
- Sensitive data should be passed via environment variables or secrets
- Never commit
.envfiles with real credentials - Use Docker secrets in production for sensitive values
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
file: ./api/Dockerfile
push: true
tags: ghcr.io/${{ github.repository }}/matchbook-api:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max