Redis-Cluster In Docker Compose

Tricky but solvable.

Michael Böckling 2023-08-17

Contents

# Introduction

If you're a developer working on some backend which depends on Redis Cluster to run, your first course of action is to add the container image to your Docker Compose file and continue fighting Spring Boot. Except its not that easy and you'll soon find out that the connection to Redis fails after an annoyingly long timeout. Why?

# The Problem

Redis shares an annoying trait with Kafka, in that the server communicate the IP addresses of all server nodes known to it to the client, so that the client always has an up-to-date view of all the nodes in the cluster. This makes managing a dynamic set of cluster nodes easy, because the client configuration will not need to be updated very often, even if single cluster nodes fail and later re-join.

The downside is that if the node IPs are behind a NAT, and thus not directly reachable, it starts to get hairy. What to do?

# The Solution

You could get creative with networking, or just do the simplest thing that will work:

  • create a Redis cluster with only a single node
  • tell that node to use to the only IP adress that is guaranteed to be reachable both in the host and in the guest, 'ol reliable 127.0.0.1

# Composefile

This is how it looks like in Docker Compose:

version: '3.8'

services:
  redis-single-node-cluster:
    image: docker.io/bitnami/redis-cluster:7.0
    environment:
      + 'ALLOW_EMPTY_PASSWORD=yes'
      + 'REDIS_CLUSTER_REPLICAS=0'
      + 'REDIS_NODES=127.0.0.1 127.0.0.1 127.0.0.1'
      + 'REDIS_CLUSTER_CREATOR=yes'
      + 'REDIS_CLUSTER_DYNAMIC_IPS=no'
      + 'REDIS_CLUSTER_ANNOUNCE_IP=127.0.0.1'
    ports:
      + '6379:6379'

This tells the startup script to create a single node cluster that is reeachable via 127.0.0.1. Since we tunnel port 6379, clients connecting locally to 127.0.0.1:6379 will get forwarded to Docker.

Don't get confused by REDIS_NODES=127.0.0.1 127.0.0.1 127.0.0.1, the script complains if there are less than three IPs, but as far as I can tell only one node is actually started - good for saving precious RAM.

# Spring Boot application.yaml

In Spring Boot, use this configuration to connect to your local Redis Cluster:

spring:
  redis:
    cluster:
      nodes: [localhost:6379]
    ssl: false

The only downside is that you can run just one instance, otherwise there will be a port conflict.

If you want to setup a multi-node cluster you can also go the more complicated route and define a custom network, but this will be an excercise for the reader.

Of course I ran into this specific problem myself some time ago and posted a short solution to Stack Overflow then, this article expands on this and provides some background - hope you'll find it helpful.