Docker Compose deployment
For local multi-node clusters without spinning up Kubernetes, Docker Compose is a quick way to run 3+ nodes of your actor-ts app + dependencies (Cassandra, NATS, Redis).
version: '3.9'
services: actor-ts-1: image: my-app:latest environment: - ACTOR_TS_HOSTNAME=actor-ts-1 - ACTOR_TS_PORT=2552 - ACTOR_TS_SEEDS=actor-ts-1:2552,actor-ts-2:2552,actor-ts-3:2552 ports: - "8081:8080" # app HTTP - "8551:8558" # management depends_on: [cassandra]
actor-ts-2: image: my-app:latest environment: - ACTOR_TS_HOSTNAME=actor-ts-2 - ACTOR_TS_PORT=2552 - ACTOR_TS_SEEDS=actor-ts-1:2552,actor-ts-2:2552,actor-ts-3:2552 ports: - "8082:8080" - "8552:8558" depends_on: [cassandra]
actor-ts-3: image: my-app:latest environment: - ACTOR_TS_HOSTNAME=actor-ts-3 - ACTOR_TS_PORT=2552 - ACTOR_TS_SEEDS=actor-ts-1:2552,actor-ts-2:2552,actor-ts-3:2552 ports: - "8083:8080" - "8553:8558" depends_on: [cassandra]
cassandra: image: cassandra:4.1 ports: - "9042:9042" healthcheck: test: ["CMD", "cqlsh", "-e", "describe keyspaces"] interval: 10s timeout: 5s retries: 10docker compose up -d# 3 actor-ts nodes form a cluster, persistence on shared CassandraWhy Docker Compose
Section titled “Why Docker Compose”For local development:
- Test cluster behavior without K8s setup.
- Reproduce production-like topology locally — multiple nodes, real network, real persistence backend.
- Demo distributed features to teammates or in a presentation.
For production, this isn’t the right tool — Docker Compose lacks the scheduling, scaling, and recovery primitives that K8s provides. See Kubernetes deployment for production.
Cluster discovery
Section titled “Cluster discovery”In the compose file:
environment: - ACTOR_TS_SEEDS=actor-ts-1:2552,actor-ts-2:2552,actor-ts-3:2552Each node’s seed list includes itself + all peers. Compose’s
DNS resolves actor-ts-1 etc. to container IPs.
The app:
import { ConfigSeedProvider } from 'actor-ts';
const seeds = await new ConfigSeedProvider({ envVar: 'ACTOR_TS_SEEDS',}).lookup();
await Cluster.join(system, { host: process.env.ACTOR_TS_HOSTNAME!, port: parseInt(process.env.ACTOR_TS_PORT!), seeds,});For dynamic-size clusters in compose (scaling via docker compose up --scale actor-ts=5), use the
DNS seed provider
instead.
Shared persistence
Section titled “Shared persistence”cassandra: image: cassandra:4.1A single Cassandra container backs all three actor-ts nodes. Sharing the journal lets sharded entities migrate between nodes naturally.
For simple local dev, you can use SQLite per-node — but sharded entities couldn’t migrate (each node only knows its own SQLite file).
Restarts
Section titled “Restarts”services: actor-ts-1: restart: unless-stoppedCompose auto-restarts crashed containers. On restart, the node rejoins the cluster via the seed list — the other two nodes continue running, the recovering one catches up via gossip.
Resource limits
Section titled “Resource limits”services: actor-ts-1: deploy: resources: limits: memory: 1G cpus: '1.0'For testing memory-bounded scenarios, set explicit limits.
Observing
Section titled “Observing”# Check cluster membership from any node's management port:curl http://localhost:8551/cluster/members
# Tail logs:docker compose logs -f actor-ts-1
# Prometheus metrics:curl http://localhost:8551/metricsFor multi-node debugging, add Prometheus + Grafana containers to compose and point them at all three management ports.
When NOT to use Docker Compose
Section titled “When NOT to use Docker Compose”Where to next
Section titled “Where to next”- Kubernetes deployment — the production path.
- Process manager — for VM-based deployment.
- Discovery overview — seed providers for various environments.
- Operations overview — the production checklist.