Skip to content

Docker Services

Carbon Connect uses Docker Compose to run its three core infrastructure services locally: PostgreSQL (with pgvector), Valkey (Redis-compatible cache), and Meilisearch (full-text search). An optional dev profile adds database and cache management UIs.


Architecture Overview

graph LR
    subgraph Docker Compose
        PG["PostgreSQL 16<br/>+ pgvector<br/>:5433"]
        VK["Valkey 8<br/>(Redis-compatible)<br/>:6379"]
        MS["Meilisearch 1.6<br/>:7700"]
    end

    subgraph Dev Profile
        AD["Adminer<br/>(DB UI)<br/>:8080"]
        VC["Valkey Commander<br/>(Cache UI)<br/>:8081"]
    end

    API["FastAPI<br/>:8000"] --> PG
    API --> VK
    API --> MS
    AD --> PG
    VC --> VK

Services

PostgreSQL 16 with pgvector

The primary relational database extended with pgvector for 768-dimensional vector similarity search.

Property Value
Image pgvector/pgvector:pg16
Container Name granted_carbon_postgres
External Port 5433 (mapped from internal 5432)
Database grant_engine
Username grant_user
Password grant_password_dev
Volume granted_carbon_postgres_data

Port 5433

The external port is 5433, not the default 5432. This avoids conflicts with local PostgreSQL installations on Windows.

Health Check: Runs pg_isready every 10 seconds with 5 retries.

Init Script: The file scripts/init-extensions.sql is mounted to /docker-entrypoint-initdb.d/ and runs on first container creation. It creates the pgvector extension required for embedding storage and similarity search.

Connection Strings:

postgresql://grant_user:grant_password_dev@localhost:5433/grant_engine
postgresql+asyncpg://grant_user:grant_password_dev@localhost:5433/grant_engine

Valkey 8

Redis-compatible in-memory data store used for caching, session storage, and as the Celery message broker and result backend. Valkey is 100% compatible with Redis clients and is approximately 20% cheaper on AWS (ElastiCache).

Property Value
Image valkey/valkey:8-alpine
Container Name granted_carbon_valkey
Port 6379
Volume granted_carbon_valkey_data
Persistence Append-only file (--appendonly yes)

Health Check: Runs valkey-cli ping every 10 seconds with 5 retries.

Connection URL: redis://localhost:6379/0

Redis Protocol Compatibility

Despite being Valkey, the connection URL uses the redis:// protocol scheme. All Redis client libraries (including Python redis and Celery) work without modification.


Meilisearch 1.6

High-performance full-text search engine providing sub-100ms search latency across 100k+ grant documents.

Property Value
Image getmeili/meilisearch:v1.6
Container Name granted_carbon_meilisearch
Port 7700
Volume granted_carbon_meilisearch_data
Master Key meilisearch_dev_master_key_change_in_prod (configurable via MEILI_MASTER_KEY)
Analytics Disabled (MEILI_NO_ANALYTICS=true)

Health Check: Runs curl -f http://localhost:7700/health every 10 seconds with 5 retries.

Environment Variables (container-level):

Variable Value Description
MEILI_MASTER_KEY ${MEILI_MASTER_KEY:-...} API authentication key (reads from .env)
MEILI_ENV development Runtime environment
MEILI_NO_ANALYTICS true Disables telemetry

Dev Profile Services

These services are only started when using the dev profile. They provide web-based management interfaces for development convenience.

Adminer (Database UI)

Property Value
Image adminer:latest
Container Name granted_carbon_adminer
Port 8080
Depends On postgres

Access at http://localhost:8080 and connect with:

  • System: PostgreSQL
  • Server: postgres (Docker service name)
  • Username: grant_user
  • Password: grant_password_dev
  • Database: grant_engine

Valkey Commander (Cache UI)

Property Value
Image rediscommander/redis-commander:latest
Container Name granted_carbon_valkey_commander
Port 8081
Depends On valkey
Redis Host local:valkey:6379

Access at http://localhost:8081 to browse keys, monitor connections, and inspect Celery queues.


Commands

Starting Services

# Start core services (PostgreSQL, Valkey, Meilisearch)
docker compose up -d

# Start with dev tools (adds Adminer and Valkey Commander)
docker compose --profile dev up -d

# Start a specific service
docker compose up -d postgres

Stopping Services

# Stop all running containers (preserves data)
docker compose down

# Stop and remove all volumes (fresh start, destroys data)
docker compose down -v

# Stop only dev profile services
docker compose --profile dev down

Monitoring

# View running containers and their health status
docker compose ps

# Follow logs for all services
docker compose logs -f

# Follow logs for a specific service
docker compose logs -f postgres
docker compose logs -f valkey
docker compose logs -f meilisearch

Direct Container Access

# Open PostgreSQL interactive shell
docker exec -it granted_carbon_postgres psql -U grant_user -d grant_engine

# List database tables
docker exec granted_carbon_postgres psql -U grant_user -d grant_engine -c "\dt"

# Check pgvector extension
docker exec granted_carbon_postgres psql -U grant_user -d grant_engine -c "SELECT * FROM pg_extension WHERE extname = 'vector';"

# Ping Valkey
docker exec granted_carbon_valkey valkey-cli ping

# List Valkey keys
docker exec granted_carbon_valkey valkey-cli keys "*"

# Check Meilisearch health
curl http://localhost:7700/health

# List Meilisearch indexes
curl http://localhost:7700/indexes -H "Authorization: Bearer meilisearch_dev_master_key_change_in_prod"

Volumes

Docker Compose defines three named volumes for data persistence across container restarts:

Volume Name Service Mount Point
granted_carbon_postgres_data PostgreSQL /var/lib/postgresql/data
granted_carbon_valkey_data Valkey /data
granted_carbon_meilisearch_data Meilisearch /meili_data

Volume Cleanup

Running docker compose down -v deletes all named volumes and their data. This is useful for a fresh start but will destroy your local database, cache, and search indexes. You will need to re-run Alembic migrations (poetry run alembic upgrade head) after volume deletion.


Network

All services share a single Docker network:

Property Value
Network Name granted_carbon_network
Driver bridge (default)

Services can reference each other by their Docker Compose service names (postgres, valkey, meilisearch) within the network. External access from the host uses localhost with the mapped ports.


Troubleshooting

Docker containers fail to start
  1. Ensure Docker Desktop is running and has sufficient resources allocated.
  2. Check for port conflicts:
    netstat -an | findstr "5433 6379 7700"
    
  3. If ports are occupied, stop the conflicting service or change the port mapping in docker-compose.yml.
  4. Remove stale containers and volumes:
    docker compose down -v
    docker compose up -d
    
PostgreSQL health check failing

The health check runs pg_isready which requires the PostgreSQL process to be fully initialized. On first startup with a fresh volume, initialization may take 15-30 seconds. Check the logs:

docker compose logs -f postgres

Meilisearch returns 403 Forbidden

Verify you are passing the correct master key in the Authorization header:

curl http://localhost:7700/indexes \
  -H "Authorization: Bearer meilisearch_dev_master_key_change_in_prod"
If you changed MEILI_MASTER_KEY in .env, the container must be recreated:
docker compose down meilisearch
docker compose up -d meilisearch

Valkey connection refused

Verify the container is running and healthy:

docker compose ps valkey
docker exec granted_carbon_valkey valkey-cli ping
Expected response: PONG

Out of disk space

Docker volumes can accumulate data over time. To reclaim space:

# Remove unused Docker resources
docker system prune

# Remove specific project volumes (destroys data)
docker compose down -v


Docker Compose File Reference

The full docker-compose.yml is located at the project root. Key structural notes:

  • Compose version: 3.9
  • Restart policy: All services use unless-stopped
  • Health checks: All three core services define health checks with 10-second intervals and 5 retries
  • Init script: PostgreSQL mounts scripts/init-extensions.sql as a read-only init script
  • Dev profile: Adminer and Valkey Commander are gated behind the dev profile to keep the default startup lightweight