Redis: Use Docker Compose for Redis

This is how to create a Redis single node or a Redis cluster using Docker Compose

Redis: Use Docker Compose for Redis

Redis is an in-memory NoSQL database for key value store. It claims to be "the world’s fastest data platform for caching, vector search, and NoSQL DBs".

Creating a Docker container for Redis, you don't need much in your Docker compose file:

services:
  db1:
    image: redis

We can pull the image and start the container:

# docker compose pull
[+] Pulling 14/14
 ✔ db1 Pulled                            3.0s
   ✔ 4d2547c08499 Already exists         0.0s
   ✔ 13dec22004c9 Pull complete          0.5s
   ✔ 00a9faca8e4e Pull complete          0.5s
   ✔ 658b37ee7a86 Pull complete          0.6s
   ✔ 35d5968306fa Pull complete          1.3s
   ✔ 2dd354c361c9 Pull complete          1.3s
   ✔ 4f4fb700ef54 Pull complete          1.3s
   ✔ 1eecbca6a5db Pull complete         
[+] Running 1/1
 ✔ Container redis-db1-1  Started        0.9s
# docker compose up -d
1:C 18 Feb 2025 10:40:21.896 # WARNING Memory overcommit must be enabled! Without it, a background save or replication may fail under low memory condition. Being disabled, it can also cause failures without low memory condition, see https://github.com/jemalloc/jemalloc/issues/1328. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
1:C 18 Feb 2025 10:40:21.904 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 18 Feb 2025 10:40:21.904 * Redis version=7.4.2, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 18 Feb 2025 10:40:21.904 * Configuration loaded
1:M 18 Feb 2025 10:40:21.905 * monotonic clock: POSIX clock_gettime
1:M 18 Feb 2025 10:40:21.913 * Running mode=standalone, port=6379.
1:M 18 Feb 2025 10:40:21.914 * No cluster configuration found, I'm 2ac80692b2ccccc1b0f25ca700aaa4265aa2688f
1:M 18 Feb 2025 10:40:21.922 * Server initialized
1:M 18 Feb 2025 10:40:21.926 * Creating AOF base file appendonly.aof.1.base.rdb on server start
1:M 18 Feb 2025 10:40:21.936 * Creating AOF incr file appendonly.aof.1.incr.aof on server start
1:M 18 Feb 2025 10:40:21.937 * Ready to accept connections tcp

But Redis has a great cluster functionality. Let's start not one, but 6 containers :-) Here's my docker-compose.yml:

services:
  db1:
    image: redis
    hostname: redis1
    networks:
      - redis
    command: redis-server --bind 0.0.0.0 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 3000 --appendonly yes --appendfilename appendonly.aof

  db2:
    image: redis
    hostname: redis2
    networks:
      - redis
    command: redis-server --bind 0.0.0.0 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 3000 --appendonly yes --appendfilename appendonly.aof

  db3:
    image: redis
    hostname: redis3
    networks:
      - redis
    command: redis-server --bind 0.0.0.0 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 3000 --appendonly yes --appendfilename appendonly.aof

  db4:
    image: redis
    hostname: redis4
    networks:
      - redis
    command: redis-server --bind 0.0.0.0 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 3000 --appendonly yes --appendfilename appendonly.aof

  db5:
    image: redis
    hostname: redis5
    networks:
      - redis
    command: redis-server --bind 0.0.0.0 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 3000 --appendonly yes --appendfilename appendonly.aof

  db6:
    image: redis
    hostname: redis6
    networks:
      - redis
    command: redis-server --bind 0.0.0.0 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 3000 --appendonly yes --appendfilename appendonly.aof

networks:
  redis:
    name: redis

Ok, this is quite a lot. Let's have a look:

  • hostname is needed to be able to access the servers/containers
  • network: we use the network redis to make all the Redis servers ready to communicate
  • command: by default, Redis starts as standalone service. We explicitly tell the container how to start:
    • bind: 0.0.0.0 means that the service listens on all interfaces
    • cluster-enabled to enable cluster functionality
    • cluster-config-file is the name of the file
    • additionally, some parameters I don't have to explain:
      • cluster-node-timeout
      • apppendonly
      • appendfilename

After starting all the containers using

# docker compose pull
# docker compose up -d

we can see that they are running. But the 6 services are not yet configured as a cluster.

We'll do it like that:

  • connect to one of the Docker containers
# docker exec -u redis -ti redis-db1-1 bash
  • create the cluster
    • with 6 Master nodes
# redis-cli --cluster create redis1:6379 redis2:6379 redis3:6379 redis4:6379 redis5:6379 redis6:6379
    • with 3 master and 3 Slave nodes
# redis-cli --cluster create redis1:6379 redis2:6379 redis3:6379 redis4:6379 redis5:6379 redis6:6379 --cluster-replicas 1  
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica redis5:6379 to redis1:6379
Adding replica redis6:6379 to redis2:6379
Adding replica redis4:6379 to redis3:6379
M: 2ac80692b2ccccc1b0f25ca700aaa4265aa2688f redis1:6379
   slots:[0-5460] (5461 slots) master
M: 9884b933acf824f9ea70730aae034e5370bef383 redis2:6379
   slots:[5461-10922] (5462 slots) master
M: ae7efb99e9bc29f4ae26650fdd1c33a0d4801089 redis3:6379
   slots:[10923-16383] (5461 slots) master
S: 46dba1ab8ac4c18a9bf7e2e689d3b2f66caac8e8 redis4:6379
   replicates ae7efb99e9bc29f4ae26650fdd1c33a0d4801089
S: 6191fe21bc34c39a5a012af0f55d4dac3801bd67 redis5:6379
   replicates 2ac80692b2ccccc1b0f25ca700aaa4265aa2688f
S: 3dd391427377c80340cfda9dbb9a4b654a221a91 redis6:6379
   replicates 9884b933acf824f9ea70730aae034e5370bef383
Can I set the above configuration? (type 'yes' to accept): yes

The cluster status will look like that (3 Masters and 3 slaves):

# redis-cli --cluster info redis1:6379
redis1:6379 (2ac80692...) -> 0 keys | 5461 slots | 1 slaves.
172.18.0.28:6379 (9884b933...) -> 0 keys | 5462 slots | 1 slaves.
172.18.0.30:6379 (ae7efb99...) -> 0 keys | 5461 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.

Redis is running, and we can use a simple shell script to generate data and save it inside of Redis. In this case, we run 10 000 times, so 10 000 key value pairs are generated:

# for i in $(seq 1 10000)
  do 
  redis-cli -c SET key$i val$i
  done

redis-cli -c allows to write data not only to the current service, but to all, as data is spreaded across the cluster (not needed for standalone node).

[...]
OK
OK
OK
OK
OK
[...]

One OK for every line. 41 seconds are needed to save it into the cluster.

We can see that it's saved, distributed and balanced:

# redis-cli --cluster info redis1:6379
redis1:6379 (2ac80692...) -> 3331 keys | 5461 slots | 1 slaves.
172.18.0.28:6379 (9884b933...) -> 3341 keys | 5462 slots | 1 slaves.
172.18.0.30:6379 (ae7efb99...) -> 3328 keys | 5461 slots | 1 slaves.
[OK] 10000 keys in 3 masters.
0.61 keys per slot on average.

3331 + 3341 + 3328 = 10 000. And if you configured the cluster using --cluster-replicas 1, the data of each service is additionally replicated to his Slave.

Subscribe to Martin's Blog

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe