在docker conatiners中连接到以哨兵模式运行的Redis主节点时出现问题

时间:2019-01-30 06:29:12

标签: docker redis docker-compose redisson

我正在docker容器中运行Redis,并且正在使用Redis标记模式。 我已经设置了以下配置-

3 redis sentinels nodes
1 redis master node
2 redis slave nodes

我正在本地计算机上运行所有这些程序。因此,总共有6个docker容器在网桥联网模式下通过docker-compose运行。 所有conatiners都具有到外部的端口映射。

所有容器都可以彼此访问,就像它们在docker-compose up运行期间创建的同一桥docker网络中一样。

我已经使用Redisson库创建了Java客户端来访问Redis。 将客户端配置为使用redis-sentinel模式,如下所示-

Config config = new Config();
config.useSentinelServers()
       .setMasterName("redis-master")
       .addSentinelAddress("redis://127.0.0.1:26379")
       .addSentinelAddress("redis://127.0.0.1:26380")
       .addSentinelAddress("redis://127.0.0.1:26381")

RedissonClient client = Redisson.create(config);

这是我面临的问题。 每当我尝试通过此客户端在Redis上运行一些命令时,请求都会通过哨兵节点,从而为我提供当前的Redis主节点地址。 但是我的Java客户端无法直接与Redis主机进行通信,因为哨兵节点返回的IP是主机节点的内部Docker网络IP,无法在Docker网络外部访问,并且失败,出现类似以下的异常-

Exception in thread "main" org.redisson.client.RedisConnectionException: Unable to connect to Redis server: 172.21.0.2/172.21.0.2:6379
    at org.redisson.connection.pool.ConnectionPool$2$1.operationComplete(ConnectionPool.java:161)
    at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:511)

如何解决此问题? 我需要在其他网络模式下运行它吗? 或某种方式将此内部docker ip转换为运行docker conatiners的计算机的实际ip?

1 个答案:

答案 0 :(得分:0)

我今天也遇到了这个问题,试图为测试实例进行设置。我最初的撰写文件基于https://blog.alexseifert.com/2016/11/14/using-redis-sentinel-with-docker-compose/,并进行了修改以满足我的需要。我能够找到一种解决方法,方法是:1)将端口绑定到我的主机上; 2)在docker-compose中设置depends_on标志; 3)设置我的sentinel.conf指向我的主服务器正在运行的主机名: https://docs.docker.com/compose/startup-order/

有点难以解释,但我会尽力而为: 您的主服务器/副本在docker-compose中将如下所示:

  redis-master:
    image: redis:5.0.4-alpine
    volumes:
      - <mounted-data-directory>
      - "<local-master-config-directory>/redis.conf:/usr/local/etc/redis/redis.conf"
    ports:
      - "6379:6379"
    command:
      - redis-server
      - /usr/local/etc/redis/redis.conf

  redis-replica:
    image: redis:5.0.4-alpine
    links:
      - redis-master
    volumes:
      - <mounted-data-directory>
      - "<local-replica-config-directory>:/usr/local/etc/redis/redis.conf"
    ports:
      - "6380:6380"
    depends_on:
      - redis-master
    command:
      - redis-server
      - /usr/local/etc/redis/redis.conf
      - --slaveof redis-master 6379

对于我的哨兵,我给了每个Dockerfile和一个sentinel.conf(每个都有不同的端口): Dockerfile:

FROM redis:5.0.4-alpine
RUN mkdir -p /redis
WORKDIR /redis
COPY sentinel.conf .
RUN chown redis:redis /redis/*
ENTRYPOINT ["redis-server", "/redis/sentinel.conf", "--sentinel"]

sentinel.conf

port 26379
dir /tmp
bind 0.0.0.0
sentinel monitor mymaster <hostname> 6379 2
sentinel down-after-milliseconds mymaster 1000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 10000

值得注意的是,我尝试使用127.0.0.1和localhost来执行此操作,但我认为这都不起作用,因此我在运行该程序的计算机上设置了主机名。那时我有点尝试任何事情。

每个哨兵(我有三个)都有一个单独的条目,它们引用他们的构建上下文并将sendinel.conf中的端口映射到本地端口。所以在docker-compose中,我的前哨看起来像这样:

 # Instance 1
  redis-sentinel:
    build:
      context: <path-to-context>
    links:
      - redis-master
    ports:
      - "26379:26379"
    depends_on:
      - redis-replica

我所做的肯定是黑客,我不会在生产中使用它。我很确定有一个针对docker的更好的网络解决方案,我只是不想为需要测试的内容走得太远。希望这会有所帮助。