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.3Image 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-workerUse 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=9090Resource requirements
These are starting points. Tune based on your actual load and JVM GC metrics.
| Service | Memory (min) | Memory (recommended) | CPU |
|---|---|---|---|
causet-runtime-service | 512 MB | 1–2 GB | 0.5–2 vCPU |
causet-projection-worker | 512 MB | 1–2 GB | 0.5–2 vCPU |
causet-query-service | 256 MB | 512 MB–1 GB | 0.25–1 vCPU |
causet-saas-cloud | 256 MB | 512 MB | 0.25–0.5 vCPU |
ws-gateway-go | 64 MB | 128 MB | 0.1–0.5 vCPU |
causet-cloud-control-plane | 128 MB | 256 MB | 0.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: 60sstart_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: 90sStartup 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_healthyThe 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-workerIn 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 buildThis builds all services and loads them into the local Docker daemon. Useful before running docker compose up with locally built images.