【问题标题】:Issue while connecting to redis master node running in sentinel mode in docker conatiners连接到在 docker 容器中以哨兵模式运行的 redis 主节点时出现问题
【发布时间】:2019-06-23 08:58:47
【问题描述】:

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

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

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

所有容器都可以相互访问,因为它们位于docker-compose up 运行期间创建的同一个桥接 docker 网络中。

我创建了一个使用 Redisson 库来访问 redis 的 Java 客户端。 配置客户端使用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 master 通信,因为 sentinel 节点返回的 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?

【问题讨论】:

    标签: docker redis docker-compose redisson


    【解决方案1】:

    我今天也遇到了这个问题,试图为一个测试实例设置这个。我最初的撰写文件是基于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 执行此操作,但我认为两者都不起作用,因此我在运行它的机器上设置了主机名。在那一点上,我有点尝试任何事情。

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

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

    我所做的绝对是一个 hack,我不会在生产中这样做。我很确定 docker 有一个更好的网络解决方案,我只是不想在兔子洞里走得太远来测试我需要的东西。希望这会有所帮助。

    【讨论】:

    • 是的。我们为测试在主机上公开端口而实施的类似解决方案。但这似乎不是用于生产的完美解决方案。另一种解决方案是为所有使用 redis 的服务和 redis 服务提供一个 docker-compose 文件。然后所有人都将在同一个 docker 网络中运行,并且能够相互通信。
    • 是的,docker compose 非常适合打包的所有服务,但老实说,我不想彻底改造我们现有的测试系统,因为没有足够的时间来重做整个管道。很高兴你得到了你需要的东西!
    猜你喜欢
    • 2020-11-29
    • 1970-01-01
    • 2021-09-05
    • 1970-01-01
    • 2018-03-14
    • 1970-01-01
    • 1970-01-01
    • 2021-09-22
    • 2014-11-12
    相关资源
    最近更新 更多