Не удается подключить SpringBoot к redis-кластеру на докере

Я хочу сделать локальный redis-кластер на докере.

  • Я попытался сделать redis-cluster на локальном докере.
  • I have 3 dockers.
    1. docker redis:5.0.1-alpine 172.18.1.1
    2. докер редис: 5.0.1-альпийский 172.18.1.2
    3. докер редис: 5.0.1-альпийский 172.18.1.3
  • Они связаны через сеть mynet. Конфигурация Docker
  • Я сделал кластер Redis.
docker 172.18.1.1 $> redis-cli --cluster create --cluster-replicas 0 172.18.1.1:6379 172.18.1.2:6379 172.18.1.3:6379

Они хорошо работают!

$> redis-cli -c
127.0.0.1:6379> set hello redis 
OK
127.0.0.1:6379> get hello 
"redis"
127.0.0.1:6379> 

Проблема в том, что не удается подключиться к redis-кластеру из приложения Spring Boot.

  • Версия Springboot: 1.5.7.RELEASE
  • Версия REDIS LIB: redis.clients:jedis:2.9.0
  • вот несколько кодов
spring.redis.cluster.nodes=127.0.0.1:36379,127.0.0.1:36380,127.0.0.1:36381
spring.redis.cluster.max-redirects=6


@Component
@ConfigurationProperties(prefix = "spring.redis.cluster")
public class RedisClusterConfigurationProperties {
    List<String> nodes;

    public List<String> getNodes() {
        return nodes;
    }

    public void setNodes(List<String> nodes) {
        this.nodes = nodes;
    }
}


@Configuration
@Service
public class SomesService {
    @Autowired
    private RedisClusterConfigurationProperties clusterProperties;

    @Bean
    public JedisPoolConfig jedisPoolConfig() {
        final JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();

        return jedisPoolConfig;
    }

    @Bean(name = "redisTemplate")
    public RedisTemplate redisTemplate() {
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());

        redisTemplate.setConnectionFactory(connectionFactory());
        redisTemplate.setExposeConnection(true);
        return redisTemplate;
    }

    private RedisConnectionFactory connectionFactory() {

        final RedisClusterConfiguration clusterConfig = new RedisClusterConfiguration(clusterProperties.getNodes());
        final JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(
            clusterConfig, jedisPoolConfig());
        jedisConnectionFactory.setUsePool(true);
        return jedisConnectionFactory;
    }

}

результат

org.springframework.data.redis.ClusterStateFailureException: Could not retrieve cluster information. CLUSTER NODES returned with error.
    - 172.18.1.1:6379 failed: Could not get a resource from the pool
    - 172.18.1.2:6379 failed: Could not get a resource from the pool
    - 172.18.1.3:6379 failed: Could not get a resource from the pool

    at org.springframework.data.redis.connection.jedis.JedisClusterConnection$JedisClusterTopologyProvider.getTopology(JedisClusterConnection.java:4237)
    at org.springframework.data.redis.connection.ClusterCommandExecutor.getClusterTopology(ClusterCommandExecutor.java:349)
    at org.springframework.data.redis.connection.ClusterCommandExecutor.executeCommandOnAllNodes(ClusterCommandExecutor.java:188)
    at org.springframework.data.redis.connection.jedis.JedisClusterConnection.info(JedisClusterConnection.java:3128)
--- removed my package sorry ;-)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
--- removed my package sorry ;-)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

2019-07-23 15:48:01.579  INFO 13741 --- [       Thread-5] o.s.w.c.s.GenericWebApplicationContext   : Closing org.springframework.web.context.support.GenericWebApplicationContext@305ffe9e: startup date [Tue Jul 23 15:47:42 KST 2019]; root of context hierarchy
2019:07:23 15:48:01.579 INFO  --- [Thread-5] o.s.w.c.s.GenericWebApplicationContext : - 984 Closing org.springframework.web.context.support.GenericWebApplicationContext@305ffe9e: startup date [Tue Jul 23 15:47:42 KST 2019]; root of context hierarchy

Process finished with exit code 255
  • Сообщения об ошибках

Не удалось получить информацию о кластере. CLUSTER NODES возвращен с ошибкой. - Ошибка 172.18.1.1:6379: Could not get a resource from the pool * «172.18.1.1» — это IP-адрес узла докера. * «127.0.0.1:36379» — это значение, которое я указал в файле application.properties.

Он работает на докере

  • Но!!! Если я помещаю результат сборки SpringBoot в докер, подключенный через mynet, он работает!
  • Создайте проект> скопируйте войну в другой докер> запустите войну. Это работает!! Очень хорошо.
    • I think redis-cluster do not allow proxy pass or something...
  • Кто-нибудь знает, как сделать локальный redis-кластер в локальном докере?

person SSaMKJ    schedule 23.07.2019    source источник
comment
В документации кластера Redis говорится, что для того, чтобы сделать Docker совместимым с Redis Cluster, вам необходимо использовать сетевой режим хоста Docker. Пожалуйста, проверьте параметр --net=host в документации Docker для получения дополнительной информации. redis.io/topics/cluster-tutorial   -  person asolanki    schedule 23.07.2019
comment
@asolanki Я нашел документ несколько минут назад. Спасибо.   -  person SSaMKJ    schedule 23.07.2019
comment
да, вам нужно использовать параметр сети хоста в докере для доступа к контейнерам Redis извне, или вам нужно развернуть все в контейнерах докеров в той же сети.   -  person Kuldeep Singh    schedule 23.07.2019


Ответы (1)


Проблема в том, что в Redis Cluster клиенты получают URL-адреса всех узлов Redis от самого узла Redis.

Таким образом, в вашем случае приложение Spring Boot отправляет запрос «узлы кластера» на один из настроенных узлов (127.0.0.1:36379,127.0.0.1:36380,127.0.0.1:36381).

В ответ он получает URL-адрес всех узлов Redis, в вашем случае это 172.18.1.1:6379 172.18.1.2:6379 172.18.1.3:6379, и пытается с ними связаться. Поскольку это внутренняя сеть Docker, вы получаете ошибку сбоя подключения.

Что вы хотите, так это настроить каждый узел Redis так, чтобы он имел другой «объявленный» хост и порт. Таким образом, клиенты получат URL-адрес, к которому они могут получить доступ, вместо внутреннего хоста и порта.

Это параметры конфигурации, которые вы должны добавить:

cluster-announce-ip: The IP address to announce.
cluster-announce-port: The data port to announce.
cluster-announce-bus-port: The cluster bus port to announce.

Подробнее см. этот пост в блоге: https://get-reddie.com/blog/redis4-cluster-docker-compose/

person Elad Tamary    schedule 25.07.2019