---
# === IDENTITY ===
id: software/devops/docker-redis-cluster/2026
canonical_question: "Docker Compose reference: Redis Cluster"
aliases:
  - "Redis Cluster docker compose setup"
  - "docker compose redis sentinel configuration"
  - "redis cluster 6 nodes docker"
  - "redis high availability docker compose"
  - "redis standalone vs sentinel vs cluster docker"
  - "docker redis persistence AOF RDB"
  - "redis cluster NAT docker networking"
  - "redis-cli --cluster create docker"
entity_type: software_reference
domain: software > devops > Docker Redis Cluster
region: global
jurisdiction: global
temporal_scope: 2024-2026

# === VERIFICATION ===
last_verified: 2026-02-27
confidence: 0.93
version: 1.0
first_published: 2026-02-27

# === TEMPORAL VALIDITY ===
temporal_validity:
  status: stable
  last_breaking_change: "Redis 8.0 (2025) unified modules into core; Redis 7.0 introduced multi-part AOF. Docker Compose v2 replaced v1."
  next_review: 2026-08-26
  change_sensitivity: medium

# === CONSTRAINTS ===
constraints:
  - "Redis Cluster requires a MINIMUM of 3 master nodes -- fewer masters cannot form a quorum for failover"
  - "Both the data port (default 6379) AND cluster bus port (data port + 10000) MUST be accessible between all nodes"
  - "Redis Cluster does NOT support NATted environments by default -- use host networking or cluster-announce-ip/port directives"
  - "NEVER use the default Docker bridge network for Redis Cluster -- use a user-defined bridge or host networking"
  - "cluster-config-file (nodes.conf) MUST persist across container restarts via Docker volumes"
  - "Multi-key operations (MGET, MSET, transactions) only work on keys in the same hash slot -- use hash tags {tag} to co-locate"

# === SKIP CONDITIONS ===
skip_this_unit_if:
  - condition: "Need a simple Redis cache without HA or sharding"
    use_instead: "Use standalone Redis: docker run redis:7.4-alpine"
  - condition: "Need Redis with search, JSON, or time series modules in cluster mode"
    use_instead: "Use redis/redis-stack-server image with cluster config"
  - condition: "Using managed Redis (AWS ElastiCache, GCP Memorystore, Azure Cache)"
    use_instead: "Refer to cloud provider Redis cluster documentation"

# === AGENT HINTS ===
inputs_needed:
  - key: "deployment_mode"
    question: "Which Redis deployment mode do you need?"
    type: choice
    options: ["Standalone (dev/testing)", "Sentinel (HA, single-write)", "Cluster (sharding + HA)"]
  - key: "persistence_need"
    question: "What level of data persistence do you need?"
    type: choice
    options: ["None (cache only)", "RDB snapshots", "AOF (append-only)", "Both RDB + AOF"]

# === DISTRIBUTION ===
canonical_source: "https://knowledgelib.io/software/devops/docker-redis-cluster/2026"
suggested_citation: "Source: knowledgelib.io -- AI Knowledge Library (verified 2026-02-27)"

# === RELATED UNITS ===
related_kos:
  depends_on: []
  related_to:
    - id: "software/devops/docker-compose-networking/2026"
      label: "Docker Compose Networking Guide"
  solves: []
  alternative_to: []
  often_confused_with:
    - id: "software/devops/redis-sentinel-setup/2026"
      label: "Redis Sentinel Setup (HA without sharding)"

# === SOURCES (7 authoritative sources) ===
sources:
  - id: src1
    title: "Scale with Redis Cluster"
    author: Redis Ltd
    url: https://redis.io/docs/latest/operate/oss_and_stack/management/scaling/
    type: official_docs
    published: 2025-06-01
    reliability: authoritative
  - id: src2
    title: "Redis persistence"
    author: Redis Ltd
    url: https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/
    type: official_docs
    published: 2025-06-01
    reliability: authoritative
  - id: src3
    title: "High availability with Redis Sentinel"
    author: Redis Ltd
    url: https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/
    type: official_docs
    published: 2025-06-01
    reliability: authoritative
  - id: src4
    title: "redis - Official Image"
    author: Docker Inc
    url: https://hub.docker.com/_/redis
    type: official_docs
    published: 2025-12-01
    reliability: high
  - id: src5
    title: "bitnami/redis-cluster - Docker Image"
    author: Bitnami (VMware)
    url: https://hub.docker.com/r/bitnami/redis-cluster/
    type: official_docs
    published: 2025-10-01
    reliability: high
  - id: src6
    title: "Redis Solutions: Standalone vs Sentinel vs Cluster"
    author: Hepsiburada Tech
    url: https://medium.com/hepsiburadatech/redis-solutions-standalone-vs-sentinel-vs-cluster-f46e703307a9
    type: technical_blog
    published: 2024-08-15
    reliability: moderate_high
  - id: src7
    title: "How to Use the Redis Docker Official Image"
    author: Docker Inc
    url: https://www.docker.com/blog/how-to-use-the-redis-docker-official-image/
    type: technical_blog
    published: 2025-03-01
    reliability: high
---

# Docker Compose Redis Cluster: Standalone, Sentinel & Cluster Modes

## TL;DR

- **Bottom line**: Redis offers three deployment modes in Docker Compose -- Standalone (simplest), Sentinel (HA with automatic failover), and Cluster (sharding + HA) -- choose based on data size, availability needs, and whether you need horizontal write scaling.
- **Key tool/command**: `redis-cli --cluster create node1:6379 node2:6379 node3:6379 node4:6379 node5:6379 node6:6379 --cluster-replicas 1`
- **Watch out for**: Docker's default bridge network breaks Redis Cluster node discovery -- use a user-defined bridge network with `cluster-announce-ip` or host networking.
- **Works with**: Redis 7.0+ (recommended 7.4+), Docker Compose v2, Docker Engine 20.10+. All examples use `redis:7.4-alpine`.

## Constraints
<!-- Agents: read this section before recommending any action from this unit.
     These are hard constraints that must not be violated. -->

- Redis Cluster requires a MINIMUM of 3 master nodes -- fewer masters cannot form a quorum for failover
- Both the data port (default 6379) AND cluster bus port (data port + 10000) MUST be accessible between all nodes
- Redis Cluster does NOT support NATted environments by default -- use host networking or cluster-announce-ip/port directives
- NEVER use the default Docker bridge network for Redis Cluster -- use a user-defined bridge or host networking
- cluster-config-file (nodes.conf) MUST persist across container restarts via Docker volumes
- Multi-key operations (MGET, MSET, transactions) only work on keys in the same hash slot -- use hash tags {tag} to co-locate

## Quick Reference

| Mode | Nodes | HA | Sharding | Max Data | Write Scaling | Use Case |
|---|---|---|---|---|---|---|
| Standalone | 1 | No | No | Single node RAM | No | Dev, testing, caching |
| Replication | 1 master + N replicas | Manual failover | No | Single node RAM | Read-only replicas | Read scaling, backups |
| Sentinel | 1 master + N replicas + 3 sentinels | Auto failover | No | Single node RAM | No | Production HA, <100GB |
| Cluster | 3+ masters + replicas | Auto failover | Yes (16384 hash slots) | Aggregate RAM | Yes | Production, >100GB, high throughput |

**Docker Compose Service Configuration:**

| Service | Image | Ports | Volumes | Key Config |
|---|---|---|---|---|
| Redis Standalone | `redis:7.4-alpine` | `6379:6379` | `redis-data:/data` | `appendonly yes` |
| Redis Master (Sentinel) | `redis:7.4-alpine` | `6379:6379` | `master-data:/data` | `appendonly yes` |
| Redis Replica (Sentinel) | `redis:7.4-alpine` | `6380:6379` | `replica-data:/data` | `--replicaof master 6379` |
| Redis Sentinel | `redis:7.4-alpine` | `26379:26379` | `sentinel-data:/data` | `sentinel monitor mymaster master 6379 2` |
| Redis Cluster Node | `redis:7.4-alpine` | `6371-6376:6379` | `node-N-data:/data` | `cluster-enabled yes` |

**Persistence Modes:**

| Strategy | Config | Data Loss Risk | Performance | Recommended For |
|---|---|---|---|---|
| None | Default | Total on restart | Fastest | Cache-only |
| RDB only | `save 60 1000` | Minutes between snapshots | Fast | Backups, cache with recovery |
| AOF everysec | `appendonly yes`, `appendfsync everysec` | ~1 second | Good | Most production workloads |
| AOF always | `appendonly yes`, `appendfsync always` | None | Slow | Financial/critical data |
| RDB + AOF | Both enabled | ~1 second | Good | PostgreSQL-level durability |

## Decision Tree

```
START: What do you need from Redis?
├── Just a cache for development/testing?
│   ├── YES → Use Standalone mode (1 container, simplest setup)
│   └── NO ↓
├── Need high availability (auto-failover)?
│   ├── YES ↓
│   │   ├── Data fits in single node RAM (<100GB)?
│   │   │   ├── YES → Use Sentinel mode (1 master + 2 replicas + 3 sentinels)
│   │   │   └── NO ↓
│   │   └── Need to shard data or scale writes?
│   │       ├── YES → Use Cluster mode (6+ nodes: 3 masters + 3 replicas)
│   │       └── NO → Use Sentinel mode
│   └── NO ↓
├── Need read scaling only?
│   ├── YES → Use Replication (1 master + N replicas, no Sentinel)
│   └── NO ↓
└── DEFAULT → Start with Standalone, add Sentinel when uptime matters
```

## Step-by-Step Guide

### 1. Set up Redis Standalone with Docker Compose

The simplest mode: a single Redis instance with optional persistence. Ideal for development and testing. [src4]

```yaml
# docker-compose.yml -- Redis Standalone
services:
  redis:
    image: redis:7.4-alpine
    container_name: redis-standalone
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data
    command: >
      redis-server
      --appendonly yes
      --appendfsync everysec
      --save 60 1000
      --maxmemory 256mb
      --maxmemory-policy allkeys-lru
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 3

volumes:
  redis-data:
```

**Verify**: `docker compose up -d && docker exec redis-standalone redis-cli ping` --> expected: `PONG`

### 2. Set up Redis Sentinel for high availability

Sentinel monitors a master and its replicas, automatically promoting a replica if the master fails. Minimum: 1 master + 2 replicas + 3 sentinels. [src3]

Create the Sentinel configuration file first:

```conf
# sentinel.conf
sentinel monitor mymaster redis-master 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 10000
sentinel parallel-syncs mymaster 1
sentinel resolve-hostnames yes
```

Full script: [docker-compose-sentinel.yml](scripts/docker-compose-sentinel.yml) (53 lines)

```yaml
# docker-compose.yml -- Redis Sentinel (excerpt)
services:
  redis-master:
    image: redis:7.4-alpine
    # ... (see full script)
```

**Verify**: `docker exec redis-sentinel-1 redis-cli -p 26379 sentinel masters` --> shows `mymaster` with status `ok`

### 3. Set up Redis Cluster (6 nodes)

Redis Cluster distributes data across 3+ masters using 16,384 hash slots. Each master has a replica for failover. [src1]

Create the cluster node configuration:

```conf
# redis-cluster.conf (shared by all nodes, port set via command line)
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
appendfsync everysec
save 60 1000
maxmemory 256mb
maxmemory-policy allkeys-lru
```

Full script: [docker-compose-cluster.yml](scripts/docker-compose-cluster.yml) (99 lines)

```yaml
# docker-compose.yml -- Redis Cluster (excerpt)
services:
  redis-node-1:
    image: redis:7.4-alpine
    # ... (see full script)
```

**Verify**: `docker exec redis-node-1 redis-cli cluster info` --> `cluster_state:ok`, `cluster_slots_assigned:16384`

### 4. Create the Redis Cluster

After all 6 nodes are running, initialize the cluster topology. [src1]

```bash
# Create cluster with 3 masters + 3 replicas
docker exec redis-node-1 redis-cli --cluster create \
  redis-node-1:6379 redis-node-2:6379 redis-node-3:6379 \
  redis-node-4:6379 redis-node-5:6379 redis-node-6:6379 \
  --cluster-replicas 1 --cluster-yes
```

**Verify**: `docker exec redis-node-1 redis-cli --cluster check redis-node-1:6379` --> `[OK] All 16384 slots covered`

### 5. Configure persistence for production

Choose persistence based on durability requirements. Redis 7.0+ uses multi-part AOF with an appendonlydir directory. [src2]

```conf
# Production redis.conf -- RDB + AOF (PostgreSQL-level durability)
# RDB snapshots
save 900 1
save 300 10
save 60 10000

# AOF persistence
appendonly yes
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# Cluster-specific
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
```

**Verify**: `docker exec redis-node-1 redis-cli info persistence` --> check `aof_enabled:1`, `rdb_last_save_time` is recent

## Code Examples
<!-- Keep inline examples <=15 lines. For longer scripts, extract to scripts/ subdirectory
     and link: "Full script: [name.ext](scripts/name.ext) (N lines)" -->

### Docker Compose: Redis Standalone with Custom Config

```yaml
# Input:  redis.conf mounted from host
# Output: Redis instance with persistence and memory limits

services:
  redis:
    image: redis:7.4-alpine
    ports:
      - "6379:6379"
    volumes:
      - ./redis.conf:/usr/local/etc/redis/redis.conf
      - redis-data:/data
    command: redis-server /usr/local/etc/redis/redis.conf
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 3

volumes:
  redis-data:
```

### Docker Compose: Redis Sentinel (3 Sentinels + Master + 2 Replicas)

Full script: [docker-compose-sentinel.yml](scripts/docker-compose-sentinel.yml) (53 lines)

```yaml
# Input:  sentinel.conf with monitor directive
# Output: HA Redis with automatic failover
services:
  redis-master:
    image: redis:7.4-alpine
    volumes:
      - master-data:/data
    command: redis-server --appendonly yes
  # ... 2 replicas + 3 sentinels (see full script)
```

### Docker Compose: Redis Cluster (6 Nodes)

Full script: [docker-compose-cluster.yml](scripts/docker-compose-cluster.yml) (99 lines)

```yaml
# Input:  redis-cluster.conf with cluster-enabled yes
# Output: 3-master + 3-replica cluster with 16384 hash slots
services:
  redis-node-1:
    image: redis:7.4-alpine
    volumes:
      - ./redis-cluster.conf:/usr/local/etc/redis/redis.conf
      - node1-data:/data
    command: redis-server /usr/local/etc/redis/redis.conf
    networks:
      - redis-cluster
  # ... 5 more nodes (see full script)
```

### Python: Connecting to Redis Cluster

```python
# Input:  Redis Cluster running on localhost ports 6371-6376
# Output: Distributed key-value operations across cluster

from redis.cluster import RedisCluster  # redis-py >= 4.1.0

rc = RedisCluster(
    startup_nodes=[
        {"host": "127.0.0.1", "port": 6371},
        {"host": "127.0.0.1", "port": 6372},
        {"host": "127.0.0.1", "port": 6373},
    ],
    decode_responses=True,
    skip_full_coverage_check=False,
)

rc.set("user:{1001}:name", "Alice")    # Hash slot from {1001}
rc.set("user:{1001}:email", "a@b.com") # Same slot as above
print(rc.get("user:{1001}:name"))      # "Alice"
print(rc.cluster_info())               # Cluster state info
```

### Node.js: Connecting to Redis Cluster

```javascript
// Input:  Redis Cluster running on localhost ports 6371-6376
// Output: Distributed key-value operations across cluster

import { createCluster } from 'redis';  // redis >= 4.0.0

const cluster = createCluster({
  rootNodes: [
    { url: 'redis://127.0.0.1:6371' },
    { url: 'redis://127.0.0.1:6372' },
    { url: 'redis://127.0.0.1:6373' },
  ],
});

await cluster.connect();
await cluster.set('user:{1001}:name', 'Alice');
const name = await cluster.get('user:{1001}:name');
console.log(name); // "Alice"
await cluster.quit();
```

## Anti-Patterns

### Wrong: Using default bridge network for Redis Cluster

```yaml
# BAD -- default bridge network uses internal IPs unreachable between containers
services:
  redis-node-1:
    image: redis:7.4-alpine
    ports:
      - "6371:6379"
    # No custom network defined -- uses default bridge
```

### Correct: Using a user-defined bridge network

```yaml
# GOOD -- user-defined bridge network enables DNS resolution by container name
services:
  redis-node-1:
    image: redis:7.4-alpine
    networks:
      - redis-cluster

networks:
  redis-cluster:
    driver: bridge
```

### Wrong: No volume for cluster-config-file

```yaml
# BAD -- nodes.conf lost on container restart, cluster state corrupted
services:
  redis-node-1:
    image: redis:7.4-alpine
    command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf
    # No volume for /data -- nodes.conf is written to /data
```

### Correct: Persistent volume for /data directory

```yaml
# GOOD -- nodes.conf and persistence files survive restarts
services:
  redis-node-1:
    image: redis:7.4-alpine
    command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf
    volumes:
      - node1-data:/data

volumes:
  node1-data:
```

### Wrong: Using MGET across different hash slots

```python
# BAD -- keys land on different slots, raises CrossSlotError
rc.mget("user:1:name", "user:2:name", "user:3:name")
# redis.exceptions.CrossSlotError: Keys in request don't hash to the same slot
```

### Correct: Using hash tags to co-locate keys

```python
# GOOD -- {user:1} ensures all keys go to the same hash slot
rc.mget("{user:1}:name", "{user:1}:email", "{user:1}:role")
# All keys share hash slot for {user:1}
```

### Wrong: Exposing only client port in firewall

```yaml
# BAD -- cluster bus port (16379) blocked, nodes can't gossip
services:
  redis-node-1:
    image: redis:7.4-alpine
    ports:
      - "6379:6379"
    # Missing: port 16379 for cluster bus communication
```

### Correct: Exposing both client and cluster bus ports

```yaml
# GOOD -- both ports accessible on user-defined network (no explicit mapping needed)
# On user-defined bridge networks, all ports are open between containers.
# Only expose client port to host if external access is needed:
services:
  redis-node-1:
    image: redis:7.4-alpine
    ports:
      - "6371:6379"    # Client access from host
    # Port 16379 is open automatically within the Docker network
    networks:
      - redis-cluster
```

## Common Pitfalls

- **NAT breaks cluster discovery**: Redis nodes advertise their container-internal IP, which is unreachable from the host or other networks. Fix: Use `cluster-announce-ip` and `cluster-announce-port` in redis.conf, or use `--net=host`. [src1]
- **nodes.conf not persisted**: If the container restarts without a volume mount for `/data`, the node loses its cluster identity and cannot rejoin. Fix: Always mount a named volume to `/data` for every cluster node. [src1]
- **Cluster creation before all nodes ready**: Running `redis-cli --cluster create` before all 6 nodes are healthy causes partial cluster formation. Fix: Add `depends_on` with healthchecks in docker-compose.yml, or wait with a script. [src4]
- **Single-node "cluster"**: Running only 1-2 masters. Redis Cluster needs a majority to elect a new master -- 2 masters means no failover is possible. Fix: Always use at least 3 masters (6 nodes with replicas). [src1]
- **Port conflicts with multiple nodes**: Assigning the same host port to multiple Redis containers. Fix: Map different host ports (6371-6376) or use `network_mode: host` with different `--port` values. [src4]
- **Forgetting cluster-node-timeout**: Default is 15000ms. In Docker networks with low latency, nodes may be marked as failed too slowly or too quickly. Fix: Set `cluster-node-timeout 5000` for Docker environments. [src1]
- **AOF rewrite during cluster creation**: Large AOF rewrites can block the event loop during cluster initialization. Fix: Disable AOF rewrite during initial data load, enable after cluster is stable. [src2]
- **Redis Cluster with Sentinel**: Trying to use Sentinel to monitor a Redis Cluster. Sentinel is for standalone master-replica setups only -- Cluster has its own failover mechanism. Fix: Choose one mode, not both. [src3]

## Diagnostic Commands

```bash
# Check cluster health (from any node)
docker exec redis-node-1 redis-cli cluster info

# Verify all 16384 slots are assigned
docker exec redis-node-1 redis-cli --cluster check redis-node-1:6379

# List all cluster nodes and their roles
docker exec redis-node-1 redis-cli cluster nodes

# Check which slot a key belongs to
docker exec redis-node-1 redis-cli cluster keyslot mykey

# Check Sentinel status (Sentinel mode)
docker exec redis-sentinel-1 redis-cli -p 26379 sentinel masters

# Trigger manual failover on a replica
docker exec redis-node-4 redis-cli cluster failover

# Check persistence status
docker exec redis-node-1 redis-cli info persistence

# Check memory usage
docker exec redis-node-1 redis-cli info memory

# Monitor cluster bus traffic (debug)
docker exec redis-node-1 redis-cli cluster info | grep cluster_stats

# Test cluster write across all masters
docker exec redis-node-1 redis-cli -c set test:key1 "hello"
docker exec redis-node-1 redis-cli -c set test:key2 "world"
docker exec redis-node-1 redis-cli -c set test:key3 "redis"
```

## Version History & Compatibility

| Version | Status | Key Changes | Docker Image |
|---|---|---|---|
| Redis 8.0 | Current | Unified modules (Search, JSON, TimeSeries) into core, new ACL categories | `redis:8.0-alpine` |
| Redis 7.4 | Stable | Hash field expiration, performance improvements | `redis:7.4-alpine` |
| Redis 7.2 | Maintained | Cluster improvements, enhanced ACLs | `redis:7.2-alpine` |
| Redis 7.0 | Maintained | Multi-part AOF, sharded pub/sub, CLUSTER SHARDS command | `redis:7.0-alpine` |
| Redis 6.2 | EOL | ACL improvements, GETDEL/GETEX commands | `redis:6.2-alpine` |
| Redis 4.0 | EOL | cluster-announce-ip/port (NAT support), modules API | N/A |

| Docker Compose | Status | Notes |
|---|---|---|
| V2 (docker compose) | Current | Built into Docker CLI, YAML v3 syntax |
| V1 (docker-compose) | Deprecated | Standalone binary, removed in Docker 25+ |

## When to Use / When Not to Use

| Use When | Don't Use When | Use Instead |
|---|---|---|
| Need sharding across multiple nodes (data > single node RAM) | Data fits in a single Redis instance | Standalone or Sentinel |
| Need automatic failover AND horizontal write scaling | Only need HA without sharding | Sentinel (simpler ops) |
| High-throughput writes that exceed single-node capacity | Latency-sensitive multi-key transactions across different data | Single-instance Redis for atomicity |
| Building microservices where each service has its own keyspace | Running on a single Docker host with limited resources | Standalone with persistence |
| Production system requiring zero-downtime upgrades | Development or testing environment | Standalone is sufficient |

## Important Caveats

- Redis Cluster uses asynchronous replication -- writes acknowledged before replicated to replicas, so data loss is possible during master failure [src1]
- The WAIT command can enforce synchronous replication but does not guarantee strong consistency -- in a network partition, acknowledged writes can still be lost [src1]
- Multi-key operations (MGET, MSET, EXEC transactions, Lua scripts) require all keys to be in the same hash slot -- use hash tags `{tag}` to co-locate related keys [src1]
- Docker Desktop on macOS/Windows runs containers in a Linux VM, adding a network layer that can complicate `cluster-announce-ip` settings -- test with `docker network inspect` to verify IPs [src4]
- Bitnami Redis Cluster images simplify setup but use different config paths (`/opt/bitnami/redis/etc/`) and environment variables -- do not mix Bitnami and official image documentation [src5]
- Redis 8.0 changed ACL categories to include module commands -- existing ACL configurations may need updates when upgrading [src1]

## Related Units
<!-- Generated from related_kos frontmatter -->

- [Docker Compose Networking Guide](/software/devops/docker-compose-networking/2026)
- [Redis Sentinel Setup](/software/devops/redis-sentinel-setup/2026)
