无法从 Docker 容器内连接到 Redis 集群

Unable to connect to Redis Cluster from inside Docker container

我有一个使用此 ioredis javascript 客户端库的 Node 应用程序。我的问题是我无法将这个同样 docker 化的应用程序连接到我的 Redis 集群(端口 7000 到 7005)及其容器。这是我的设置和结果:

我克隆了这个 Docker-redis-cluster 存储库并按照说明从 Dockerfile.

构建映像
$ docker build -t gsccheng/redis-cluster .

然而,在构建之前,我唯一的改变是设置我自己的版本,我已将其更改为

ARG redis_version=3.2.1

按照我的指示 运行

docker run -i -t -p 7000:7000 -p 7001:7001 -p 7002:7002 -p 7003:7003 -p 7004:7004 -p 7005:7005 -p 7006:7006 -p 7007:7007 gsccheng/redis-cluster

到目前为止很棒...

除了一些警告,如:WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.,到目前为止还不错。为什么?:

  1. 这是 output 的屏幕截图。
  2. 我可以使用 redis-cli -c -p 7000
  3. 进入 CLI
  4. 使用 docker inspect [container id] 我看到它有一个 NetworkSettings > IPAddress 172.17.0.2 在 NetworkSettings > Ports 我看到

    "Ports": {
                "6379/tcp": null,
                "7000/tcp": [
                    {
                        "HostIp": "0.0.0.0",
                        "HostPort": "7000"
                    }
                ],
                ...
             }
    

接下来,我停止并删除所有容器。我导航到我的 Web 应用程序的根目录,其中有一个 Dockerfile 和一个 docker-compose.yml,它们位于此处:

docker-compose.yml

version: '2.1'
services:
  web:
    build: .
    ports:
      - '8080:8080'
    depends_on:
        - redis
  redis:
    image: gsccheng/redis-cluster
    ports:
      - '7000:7000'
      - '7001:7001'
      - '7002:7002'
      - '7003:7003'
      - '7004:7004'
      - '7005:7005'

Dockerfile

FROM node:4.4.7

# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Install app dependencies
COPY package.json /usr/src/app/
RUN npm install

# Bundle app source
COPY . /usr/src/app

EXPOSE 8080
CMD [ "npm", "run", "prod" ]

connect.js

import Redis from 'ioredis';
console.log('I am totally in here');

// The commented out host options shows the many different configurations I tried too.
const node = [{
            // Just need to connect to at least one of the startup nodes in the cluster. Redis will find the rest of the nodes in the cluster. All nodes only have a single db of 0 and SELECT is disabled.
            port: 7000,
            // host: '0.0.0.0'
            // host: '127.0.0.1'
            // host: '172.18.0.4'
            host: 'redis'
            // host: 'gsccheng/redis-cluster'
        }, {
            port: 7001,
            // host: '0.0.0.0'
            // host: '127.0.0.1'
            // host: '172.18.0.4'
            host: 'redis'
            // host: 'gsccheng/redis-cluster'
        }]

client = new Redis.Cluster(node, {});
...

我然后运行

$ docker-compose build

$ docker-compose up

输出在这个gist。对于这个例子,我从那里删除了一些不相关的行(用“...”表示)。

如果有区别的话,我的应用程序是从这个 React-redux boilerplate 构建的,但它不包括 Redis。

完整性检查

  1. 使用 docker-compose up 运行ning 并且如您在要点中看到的那样不断记录错误,我仍然可以在执行时从容器外部连接到集群:

    $ redis-cli -c -p 7000
    
  2. $ docker ps 显示此 screenshot.

  3. $ docker exec 4b3ec3e53e32 ps aux | grep redis 显示此 screenshot.

  4. 这是来自 $ docker inspect 4b3ec3e53e32 的 redis 容器的完整 output。注意 NetworkSettings...

  5. 下的 "IPAddress": ""

更多问题

  1. ...为什么现在是空白?这就是我的 Redis 客户端无法连接到集群的原因吗?
  2. 那个ip和"HostIp": "0.0.0.0",有什么区别? 0.0.0.0 绑定在 redis.conf 配置中,我认为这意味着服务器只会侦听来自该地址的请求。这是否意味着此处列出的 IP 必须与我的其他 ctn_web_1 容器的 IP 匹配?
  3. 我们还从 docker-compose up 的输出中看到 Redis 服务器已启动 172.18.0.2。我注意到这在我 运行ning docker-compose 的实例之间也发生了很大变化(例如 172.18.0.4172.18.0.3)。为什么?是因为我在再次 运行ning 之前还没有完全删除容器吗?但是,我不应该在我的 connect.js 代码中使用这个 ip 地址,因为这个地址是 redis 容器的内部地址(而我的 web 容器感兴趣的接口是 redis 容器的地址)?

更新:

一个。 $ docker-compose ps 输出为 here。 B. 还要注意 this 问题。更具体地说

redis cluster doesnt support docker yet (unless you do host networking) - >advertised ip address would be different from the one they can talk through

您应该删除该行

host: '0.0.0.0'

来自您的 connect.js。您需要通过它们的 DNS 名称 (redis) 与其他容器建立连接,只要您在同一个 docker 网络中启动它们,它就可以工作。这是 docker-compose 与版本 2 yml 文件的默认行为。

容器可能以不同的 IP 开头。我建议不要尝试将容器的 IP 硬编码到任何配置文件中,因为根据设计,目标容器可能会来来去去。


从您提到的问题来看,上游作者似乎不支持您尝试做的事情。我不确定这如何与您最初发现 redis-cli 的结果相协调。我的回答是基于一个工作的 redis 环境的假设。回应一些其他的困惑:

  • 0.0.0.0是监听IP,表示所有接口都应该被监听。你不从客户端连接0.0.0.0,只作为服务端监听这个地址

  • 您看到的空 IP 地址是重新组织一些 json 输出的结果,现在所有 IP 仅与其特定网络一起列出,顶级不再列出默认 IP .