docker.recipes

NATS JetStream Cluster

intermediate

High-performance messaging system with JetStream persistence and streaming.

Overview

NATS is a high-performance, cloud-native messaging system originally developed by Derek Collison in 2010, designed to provide extremely fast and lightweight communication for distributed systems. Unlike traditional message brokers, NATS focuses on simplicity and speed, delivering sub-millisecond latency with minimal resource overhead. JetStream, introduced as NATS 2.2's persistence layer, adds durability and streaming capabilities while maintaining NATS' performance characteristics. This cluster configuration creates a three-node NATS JetStream cluster that provides both high availability and data persistence, eliminating the single point of failure inherent in standalone deployments. The integration with Prometheus captures detailed metrics about message throughput, consumer lag, and cluster health, while Grafana transforms this telemetry into visual dashboards for real-time monitoring. The nats-box utility container provides a complete CLI toolkit for stream management, consumer testing, and administrative operations. This stack particularly excels in scenarios requiring both real-time messaging performance and guaranteed message delivery, making it ideal for financial trading platforms, IoT data ingestion, and microservices architectures where message loss is unacceptable but traditional heavyweight brokers introduce too much latency.

Key Features

  • Three-node NATS cluster with automatic failover and split-brain protection
  • JetStream persistence engine with configurable retention policies and storage limits
  • Pull and push consumer patterns with acknowledgment-based delivery guarantees
  • Stream replication across cluster nodes for data durability and availability
  • Built-in monitoring endpoints exposing JetStream metrics and cluster topology
  • Subject-based routing with wildcard support for flexible message distribution
  • Queue groups for load balancing consumers across multiple application instances
  • Real-time Grafana dashboards showing message rates, stream sizes, and consumer lag

Common Use Cases

  • 1Financial trading systems requiring sub-millisecond message delivery with audit trails
  • 2IoT sensor networks collecting telemetry data with guaranteed persistence
  • 3Microservices architectures needing both request-reply and event streaming patterns
  • 4Real-time chat applications with message history and offline delivery
  • 5Log aggregation systems processing high-volume structured data streams
  • 6Event-driven architectures implementing CQRS patterns with event sourcing
  • 7Gaming backends managing player state synchronization and match coordination

Prerequisites

  • Minimum 768MB RAM available (256MB per NATS node plus monitoring stack)
  • Docker Engine 20.10+ with Docker Compose v2 for multi-container orchestration
  • Ports 4222, 8222, 9090, and 3000 available on the host system
  • Basic understanding of pub/sub messaging patterns and stream processing concepts
  • Familiarity with PromQL for customizing Prometheus monitoring queries
  • SSD storage recommended for JetStream data volumes to ensure optimal performance

For development & testing. Review security settings, change default credentials, and test thoroughly before production use. See Terms

docker-compose.yml

docker-compose.yml
1services:
2 nats1:
3 image: nats:latest
4 hostname: nats1
5 ports:
6 - "4222:4222"
7 - "8222:8222"
8 command: >
9 -js
10 -sd /data
11 -cluster nats: //0.0.0.0:6222
12 -cluster_name nats-cluster
13 -routes nats: //nats2:6222,nats://nats3:6222
14 -m 8222
15 volumes:
16 - nats1_data:/data
17 networks:
18 - nats-net
19 restart: unless-stopped
20
21 nats2:
22 image: nats:latest
23 hostname: nats2
24 command: >
25 -js
26 -sd /data
27 -cluster nats: //0.0.0.0:6222
28 -cluster_name nats-cluster
29 -routes nats: //nats1:6222,nats://nats3:6222
30 volumes:
31 - nats2_data:/data
32 networks:
33 - nats-net
34 restart: unless-stopped
35
36 nats3:
37 image: nats:latest
38 hostname: nats3
39 command: >
40 -js
41 -sd /data
42 -cluster nats: //0.0.0.0:6222
43 -cluster_name nats-cluster
44 -routes nats: //nats1:6222,nats://nats2:6222
45 volumes:
46 - nats3_data:/data
47 networks:
48 - nats-net
49 restart: unless-stopped
50
51 nats-box:
52 image: natsio/nats-box:latest
53 command: sleep infinity
54 depends_on:
55 - nats1
56 networks:
57 - nats-net
58
59 prometheus:
60 image: prom/prometheus:latest
61 ports:
62 - "9090:9090"
63 volumes:
64 - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
65 - prometheus_data:/prometheus
66 networks:
67 - nats-net
68 restart: unless-stopped
69
70 grafana:
71 image: grafana/grafana:latest
72 ports:
73 - "3000:3000"
74 environment:
75 - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
76 volumes:
77 - grafana_data:/var/lib/grafana
78 depends_on:
79 - prometheus
80 networks:
81 - nats-net
82 restart: unless-stopped
83
84volumes:
85 nats1_data:
86 nats2_data:
87 nats3_data:
88 prometheus_data:
89 grafana_data:
90
91networks:
92 nats-net:
93 driver: bridge

.env Template

.env
1# NATS Configuration
2NATS_CLUSTER_NAME=nats-cluster
3
4# Grafana
5GRAFANA_PASSWORD=secure_grafana_password

Usage Notes

  1. 1NATS client connection at localhost:4222
  2. 2Monitoring endpoint at http://localhost:8222
  3. 3Use nats-box: docker compose exec nats-box nats
  4. 4JetStream enabled for persistence

Individual Services(6 services)

Copy individual services to mix and match with your existing compose files.

nats1
nats1:
  image: nats:latest
  hostname: nats1
  ports:
    - "4222:4222"
    - "8222:8222"
  command: |
    -js -sd /data -cluster nats://0.0.0.0:6222 -cluster_name nats-cluster -routes nats://nats2:6222,nats://nats3:6222 -m 8222
  volumes:
    - nats1_data:/data
  networks:
    - nats-net
  restart: unless-stopped
nats2
nats2:
  image: nats:latest
  hostname: nats2
  command: |
    -js -sd /data -cluster nats://0.0.0.0:6222 -cluster_name nats-cluster -routes nats://nats1:6222,nats://nats3:6222
  volumes:
    - nats2_data:/data
  networks:
    - nats-net
  restart: unless-stopped
nats3
nats3:
  image: nats:latest
  hostname: nats3
  command: |
    -js -sd /data -cluster nats://0.0.0.0:6222 -cluster_name nats-cluster -routes nats://nats1:6222,nats://nats2:6222
  volumes:
    - nats3_data:/data
  networks:
    - nats-net
  restart: unless-stopped
nats-box
nats-box:
  image: natsio/nats-box:latest
  command: sleep infinity
  depends_on:
    - nats1
  networks:
    - nats-net
prometheus
prometheus:
  image: prom/prometheus:latest
  ports:
    - "9090:9090"
  volumes:
    - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
    - prometheus_data:/prometheus
  networks:
    - nats-net
  restart: unless-stopped
grafana
grafana:
  image: grafana/grafana:latest
  ports:
    - "3000:3000"
  environment:
    - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
  volumes:
    - grafana_data:/var/lib/grafana
  depends_on:
    - prometheus
  networks:
    - nats-net
  restart: unless-stopped

Quick Start

terminal
1# 1. Create the compose file
2cat > docker-compose.yml << 'EOF'
3services:
4 nats1:
5 image: nats:latest
6 hostname: nats1
7 ports:
8 - "4222:4222"
9 - "8222:8222"
10 command: >
11 -js
12 -sd /data
13 -cluster nats://0.0.0.0:6222
14 -cluster_name nats-cluster
15 -routes nats://nats2:6222,nats://nats3:6222
16 -m 8222
17 volumes:
18 - nats1_data:/data
19 networks:
20 - nats-net
21 restart: unless-stopped
22
23 nats2:
24 image: nats:latest
25 hostname: nats2
26 command: >
27 -js
28 -sd /data
29 -cluster nats://0.0.0.0:6222
30 -cluster_name nats-cluster
31 -routes nats://nats1:6222,nats://nats3:6222
32 volumes:
33 - nats2_data:/data
34 networks:
35 - nats-net
36 restart: unless-stopped
37
38 nats3:
39 image: nats:latest
40 hostname: nats3
41 command: >
42 -js
43 -sd /data
44 -cluster nats://0.0.0.0:6222
45 -cluster_name nats-cluster
46 -routes nats://nats1:6222,nats://nats2:6222
47 volumes:
48 - nats3_data:/data
49 networks:
50 - nats-net
51 restart: unless-stopped
52
53 nats-box:
54 image: natsio/nats-box:latest
55 command: sleep infinity
56 depends_on:
57 - nats1
58 networks:
59 - nats-net
60
61 prometheus:
62 image: prom/prometheus:latest
63 ports:
64 - "9090:9090"
65 volumes:
66 - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
67 - prometheus_data:/prometheus
68 networks:
69 - nats-net
70 restart: unless-stopped
71
72 grafana:
73 image: grafana/grafana:latest
74 ports:
75 - "3000:3000"
76 environment:
77 - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
78 volumes:
79 - grafana_data:/var/lib/grafana
80 depends_on:
81 - prometheus
82 networks:
83 - nats-net
84 restart: unless-stopped
85
86volumes:
87 nats1_data:
88 nats2_data:
89 nats3_data:
90 prometheus_data:
91 grafana_data:
92
93networks:
94 nats-net:
95 driver: bridge
96EOF
97
98# 2. Create the .env file
99cat > .env << 'EOF'
100# NATS Configuration
101NATS_CLUSTER_NAME=nats-cluster
102
103# Grafana
104GRAFANA_PASSWORD=secure_grafana_password
105EOF
106
107# 3. Start the services
108docker compose up -d
109
110# 4. View logs
111docker compose logs -f

One-Liner

Run this command to download and set up the recipe in one step:

terminal
1curl -fsSL https://docker.recipes/api/recipes/nats-jetstream-cluster/run | bash

Troubleshooting

  • Cluster formation fails with 'no route to host': Ensure all NATS containers can resolve each other's hostnames and verify the nats-net network is created properly
  • JetStream consumers show increasing lag: Check if consumer acknowledgment timeouts are too short or if processing applications have crashed using 'nats consumer info'
  • Memory usage grows unbounded: Configure stream retention policies with max_msgs or max_bytes limits to prevent infinite message accumulation
  • Split-brain scenario with multiple leaders: Restart all NATS containers simultaneously to force cluster re-election and check for network partitioning issues
  • Prometheus shows gaps in NATS metrics: Verify that port 8222 monitoring endpoint is accessible and confirm prometheus.yml includes all NATS node targets
  • Messages lost during node restart: Ensure JetStream streams have replication factor set to 3 using 'nats stream add --replicas=3' for full cluster redundancy

Community Notes

Loading...
Loading notes...

Download Recipe Kit

Get all files in a ready-to-deploy package

Includes docker-compose.yml, .env template, README, and license

Ad Space