Docker

All Causet services are distributed as Docker images. This page covers building images locally, container configuration, resource sizing, and how services are ordered and health-checked.


Building service images

Causet service images are built with Docker Compose or standard docker build commands.

# Build all service images
docker compose build
 
# Build a specific service image
docker compose build causet-runtime-service
docker compose build causet-query-service
docker compose build causet-projection-worker
docker compose build causet-saas-cloud
 
# Build and tag for a registry
docker build -t your-registry/causet-runtime-service:v1.2.3 \
  ./apps/causet-runtime-service
 
# Push to registry
docker push your-registry/causet-runtime-service:v1.2.3

Image tagging

Tag images with the same version as the IR artifacts they are paired with. This makes it straightforward to correlate a running container version with the IR it was compiled against.

export VERSION=2026.06.25-abc1234
 
docker build -t your-registry/causet-runtime-service:$VERSION \
  ./apps/causet-runtime-service
 
docker build -t your-registry/causet-projection-worker:$VERSION \
  ./apps/causet-projection-worker

Use latest only in local development. Always use pinned versions in production deployments.


Container environment variables

Each service is configured entirely through environment variables. See Environment Variables for the complete reference.

Key variables required for all Java services:

# causet-runtime-service
DATABASE_URL=r2dbc:postgresql://postgres:5432/causet
KAFKA_BOOTSTRAP_SERVERS=redpanda:9092
S3_ENDPOINT=http://minio:9000
S3_BUCKET=causet-artifacts
AWS_ACCESS_KEY_ID=minioadmin
AWS_SECRET_ACCESS_KEY=minioadmin
CAUSET_SAAS_URL=http://causet-saas-cloud:8085
SERVER_PORT=8080
GRPC_PORT=9090

Resource requirements

These are starting points. Tune based on your actual load and JVM GC metrics.

ServiceMemory (min)Memory (recommended)CPU
causet-runtime-service512 MB1–2 GB0.5–2 vCPU
causet-projection-worker512 MB1–2 GB0.5–2 vCPU
causet-query-service256 MB512 MB–1 GB0.25–1 vCPU
causet-saas-cloud256 MB512 MB0.25–0.5 vCPU
ws-gateway-go64 MB128 MB0.1–0.5 vCPU
causet-cloud-control-plane128 MB256 MB0.1–0.25 vCPU

Note: Java services use a JVM and have a non-trivial startup cost. Set container memory limits above the JVM heap size to leave room for metaspace, stack, and native memory. A common rule: container limit ≈ 1.5× the configured -Xmx.


Health check configuration

All Java services expose /actuator/health on their HTTP port.

In docker-compose.yml, health checks look like:

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
  interval: 10s
  timeout: 5s
  retries: 10
  start_period: 60s

start_period is critical for Java services — the JVM and Spring context need time to initialize before the health endpoint becomes available. causet-runtime-service and causet-projection-worker should have start_period of at least 60–90 seconds.

The projection worker has no external port. Run the health check against its internal port:

# causet-projection-worker has an internal health port (not exposed to host)
healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:8083/actuator/health"]
  interval: 15s
  timeout: 5s
  retries: 8
  start_period: 90s

Startup ordering in Docker Compose

Use depends_on with condition: service_healthy to enforce ordering:

causet-runtime-service:
  depends_on:
    postgres:
      condition: service_healthy
    redpanda:
      condition: service_healthy
    redis:
      condition: service_healthy
    minio:
      condition: service_healthy
    causet-saas-cloud:
      condition: service_healthy

The projection worker depends on Kafka being ready and topics existing. Run ./infra/redpanda/create-topics.sh before the worker is expected to consume.


Logging

All Causet services write structured JSON logs to stdout. The log format:

{
  "timestamp": "2026-06-25T20:00:00.123Z",
  "level": "INFO",
  "logger": "com.causet.runtime.IntentProcessor",
  "message": "Intent processed",
  "action": "FOLLOW_ARTIST",
  "entityId": "user-1",
  "correlationId": "corr-abc123",
  "durationMs": 12
}

Capture logs with Docker:

docker compose logs -f causet-runtime-service
docker compose logs --tail=100 causet-projection-worker

In production, ship stdout/stderr to your log aggregator (e.g., Grafana Alloy → Loki). Do not write logs to files inside the container.


Volumes

Services themselves are stateless. State lives in PostgreSQL, Kafka, Redis, and S3. Containers should not use local volumes for application data.

In local Docker Compose, named volumes persist Postgres data and Redpanda state across docker compose down (without -v):

volumes:
  postgres-data:
  redpanda-data:
  minio-data:

Networking

In Docker Compose, all services share a default bridge network and communicate using container names as hostnames. Example: causet-runtime-service connects to Postgres at postgres:5432.

In production (ECS, Kubernetes), use your platform’s DNS-based service discovery. Services should never hard-code IP addresses.


Building all images at once

docker compose build

This builds all services and loads them into the local Docker daemon. Useful before running docker compose up with locally built images.