79371934

Date: 2025-01-20 16:07:29
Score: 0.5
Natty:
Report link

In regards to "Single-Node Cluster":

The problem arises because .withExposedPorts(port) exposes the Redis service on a dynamically allocated local port. Meanwhile, the JedisCluster client uses the seed nodes (provided hosts) to resolve the cluster topology via the CLUSTER SLOTS or CLUSTER NODES command. Then, it will use host/port announced by the nodes themself to create connections to a particular node. As you can see from the output you have provided cluster nodes will announce the actual port they are running on (6379) unless cluster-announce-port is specified.

1f2673c5fdb45ca16d564658ff88f815db5cbf01 172.29.0.2:6379@16379 myself,master ...

Since port 6379 is not accessible outside the docker container (e.g., the test container exposes it on a different dynamically mapped port), call to jedis.set("key", "value"); will try to acquire connection to the node using the announced host/port and will fail.

You can overcome this by using statically mapped port bindin or use Jedis provided option for host/port mapping -DefaultJedisClientConfig.Builder#hostAndPortMapper.

Option 1: Expose redis service on predefined port

int externalPort = 7379;
int port = 6379;
Network network = Network.newNetwork();
RedisContainer redisContainer = new RedisContainer(DockerImageName.parse("redis:7.0.5"))
    // Use static port binding together with  cluster-announce-port
    .withCreateContainerCmdModifier(cmd -> cmd.withPortBindings(
        new PortBinding(Ports.Binding.bindPort(externalPort), ExposedPort.tcp(port))))
    .withCommand("redis-server --port " + port +
        " --requirepass " + redisPassword +  // Password for clients
        " --masterauth " + redisPassword +  // Password for inter-node communication
        " --cluster-announce-port " + externalPort +
        " --cluster-enabled yes" +
        " --cluster-config-file nodes.conf"+
        " --cluster-node-timeout 5000"+
        " --appendonly yes" +
        " --bind 0.0.0.0" )
    .withNetwork(network)
    .withNetworkMode("bridge")
    .withNetworkAliases("redis-" + i)
    .waitingFor(Wait.forListeningPort());

Option 2 : Use Jedis hostAndPortMapper

HostAndPortMapper nat = hostAndPort -> {
  if (hostAndPort.getPort() == port) {
    return new HostAndPort(redisContainer.getHost(), redisContainer.getMappedPort(port));
  }
  return hostAndPort;
};
...
//        Connect to the cluster using Jedis with a password
DefaultJedisClientConfig.Builder jedisClientConfig = DefaultJedisClientConfig.builder()
    .password(redisPassword)
    .hostAndPortMapper(nat)
    .ssl(false)
    .connectionTimeoutMillis(10000)
    .socketTimeoutMillis(4000);

Also, make sure the cluster has reached a stable state after slots were configured.

Reasons:
  • Blacklisted phrase (1): regards
  • Long answer (-1):
  • Has code block (-0.5):
  • Low reputation (1):
Posted by: Ivo Gaydazhiev