【问题标题】:Redis docker not available on localhost of docker-composeRedis docker 在 docker-compose 的 localhost 上不可用
【发布时间】:2021-05-27 08:25:32
【问题描述】:

我目前遇到了一个我试图解决一个多星期的问题,但我一无所获。我希望你能指出我正确的方向。

初始情况

说明

我正在构建的项目是一个连接到一些 API 的 NestJS 应用程序。在内部,它使用bullmq作为消息队列,它本身使用ioredis连接到一个redis数据库。我已经通过docker-compose up 连接了我自己编写的服务器组件以及redis(使用docker),配置如下:

version: '3'

services:
  server:
    image: myserver:1.4.0
    container_name: myserver
    depends_on:
      - db
    ports:
      - 3001:3000
    environment:
      - REDIS_HOST=redis
  db:
    image: redis:6.0.8
    container_name: redis
    ports:
      - 6379:6379

版本

工作站

  • Docker 版本 19.03.13,构建 4484c46d9d
  • docker-compose 版本 1.27.4,构建 40524192

服务器组件

  • bullmq 1.9.0
  • ioredis 4.17.3

redis 码头工人

  • 6.0.8

问题

我的服务器组件的问题是,它尝试使用以下代码在端口 6379 处连接到给定 REDIS_HOST 下的 redis 实例:

readonly connection = new Redis(
    +(process.env.REDIS_PORT ?? this.configService.get('redis_port')),
    process.env.REDIS_HOST ?? this.configService.get('redis_host'),
  );

但会抛出以下错误:

[ioredis] Unhandled error event: Error: connect ECONNREFUSED 127.0.0.1:6379

我希望它只会在暴露的端口上看到 redis 实例。

所以,它在 127.0.0.1 处看不到 redis 实例:但它不应该使用给定的 ip 吗?

我检查的东西

服务器代码正确,在ioredis调用中正确提交并调用了REDIS_HOST。所以进一步挖掘 ioredis 我发现了 this issue 。因此,考虑到所有提示,它应该在我的工作站本地可用,我使用 0.0.0.0:6379 进行连接,它工作得很好。

Docker compose 确实会自动创建一个网桥,并使用我检查过的 netcat,redis docker 的 ip 上的端口 6379(以及别名 redis 和 db),redis 实例可从服务器 dockers 控制台获得。

然后,我使用 docker-compose 的网络配置以及为容器提供静态 ips 来明确设置子网,但正如我已经描述的:ip 已正确解析。

我在 docker github issue 204 上发现了以下问题。我认为这正是我在这里面临的问题,但是如何解决呢?

tl;dr ioredis 尝试连接到 redis 实例的正确解析 ip,但失败了,因为该实例在服务器组件的本地 ip 上不可用。

我现在的状态是什么

我控制不住地抽泣。

我目前不知道如何让“myserver”容器通过 ioredis 连接到 redis 实例。我的观点是,我遇到的问题必须与 Windows 上的 docker 将 ips 解析为 127.0.0.1 的方式有关。 .

  • 我的观点对吗?
  • 您还有什么其他的建议可以尝试?

提前致以最诚挚的问候和感谢。

编辑(2020-11-27):经过一些挖掘和进一步调查Jeffrey Mixon 的建议,不幸的是,我离解决方案还差得远。我最后的步骤包括:

  • 更新所有依赖项(其中包括将bulmq 更新到v1.11,将ioredis 更新到4.19.2)。这并没有改变任何东西。
  • 然后我在bullmq issue board 上发现了一篇关于类似问题的相对较新的帖子,我从在连接对象中重用连接(如上所示)切换到始终创建新连接,正如bullmq docs 中所解释的那样。但这也无济于事。
new Queue(name, {
        connection: {
          host: this.redisHost,
          port: this.redisPort,
        },
      })
  • 然后我从使用 IORedis 库中的“Redis”对象切换到“IORedis”,但仍然:我的应用程序 docker 的习惯没有任何改变。即使使用 redis 主机正确调用了 Redis 连接,它仍会尝试连接到 127.0.0.1:6379,如上所示。
  • 最后,奇怪的行为,例如,如果我选择一个不可解析的主机 url,应用程序 docker 会正确尝试连接到不可解析的主机)。但是一旦这个主机在 docker-compose 的网络中可用,它就会使用 127.0.0.1。

编辑(2020-12-01): 与此同时,我在干净的 linux 机器上检查了问题是否可能仅发生在 docker-for-windows 上,但它也确实发生在 linux 上。

我本身并没有解决问题,但我只是将所有东西都放在一个 docker 中,从而绕过了它。由于我的应用程序更多的是概念验证,因此这样做并没有太大的痛苦。 如果将来碰巧有解决方案或更多人有相同的问题,我会保留这个问题。

对于那些想知道的人,我的包含 redis 的 dockerfile 现在在 redis 映像之上堆叠了另一层。我正在添加我之前使用的 ng-cli-e2e 图像的部分。所以在我现有的 dockerfile 的开头我添加了:


FROM redis:6.0.9-buster

RUN apt update

RUN apt install nodejs -y

RUN apt install npm -y

最后,我创建了一个小的包装脚本,它可以启动 redis 服务器以及我的应用程序。如果我想从我的机器访问所有内容,我现在还公开了两个端口。

EXPOSE 3000 6379

CMD ./docker-start-wrapper.sh

这不是最漂亮的解决方案,但目前确实有效。

【问题讨论】:

  • +1 这个,无论我尝试什么,我都会得到以下结果。为什么连接ioredis这么难?错误:在 TCPConnectWrap.afterConnect [as oncomplete] 处连接 ECONNREFUSED 127.0.0.1:6379 (net.js:1146:16) { errno:-111,代码:'ECONNREFUSED',系统调用:'connect',地址:'127.0.0.1 ',端口:6379 }
  • 查看此文档 newbedev.com/… , db = redis.Redis(host='db', port=6379, decode_responses=True)
  • 我没有使用烧瓶,所以我不知道这些信息应该给我什么。无论如何,您的评论应该是一个答案。

标签: docker redis docker-compose ioredis


【解决方案1】:

问题是您的应用程序容器使用 localhost 作为连接到 redis 容器的主机名。在这种情况下,它应该使用主机名 redis

考虑以下演示:

version: '3.7'

services:
  server:
    image: busybox
    container_name: myserver
    entrypoint: /bin/sh
    # if redis is replaced by localhost or 127.0.0.1 below, this container will fail
    command: "-c \"sleep 2 && nc -v redis 6379\""
    depends_on:
      - db
    ports:
      - 3001:3000
    environment:
      - REDIS_HOST=redis
  db:
    image: busybox
    container_name: redis
    entrypoint: /bin/nc
    command: "-l -p 6379 -v"
    # is not necessary to publish these ports
    #ports:
    #  - 6379:6379
$ docker-compose -f scratch_2.yml up
Creating network "scratches_default" with the default driver
Creating redis ... done
Creating myserver ... done
Attaching to redis, myserver
redis     | listening on [::]:6379 ...
myserver  | redis (172.25.0.2:6379) open
redis     | connect to [::ffff:172.25.0.2]:6379 from [::ffff:172.25.0.3]:34821 ([::ffff:172.25.0.3]:34821)
myserver exited with code 0
redis exited with code 0

当您发布端口时,它们是为了在主机上的容器外部使用。通过尝试将您的 mysever 容器连接到 127.0.0.1,容器只是在尝试连接到自身。

【讨论】:

  • 抱歉耽搁了。感谢您的回答,尤其是关于“外部”端口的部分。但不幸的是,答案并没有让我更进一步。正如我在我的问题中所说,我知道连接应该是redis。我刚刚再次检查,主机 redis 已正确分配给应用程序容器。但是,正如此处github.com/luin/ioredis/issues/365 所述,ioredis 仍想绑定到本地端口。如何在本地绑定redis docker的端口?
  • @sehe 我的意思是,根据您的错误消息ECONNREFUSED 127.0.0.1:6379,您的应用程序没有尝试连接到主机名redis,尽管您可能正在尝试连接设置它。相反,它显然是在尝试连接到127.0.0.1。我对ioredis一无所知,所以它可能只是那里的一个错误。你试过官方的redis节点客户端redis吗?
  • 我刚刚使用了 ioredis,因为 Bullmq 建议这样做。但也许我会尝试适应这一点。感谢您保持联系!
  • @sehe bullmq 需要连接到任何队列的选项,还需要您实例化的 Worker 或 QueueScheduler。这可能是你的问题吗?
  • @EuberDeveloper 是这样吗? docs.bullmq.io/guide/workers这确实是我的问题。
【解决方案2】:

docker-compose的问题在于redis不在localhost,而是在自己的网络上。默认情况下,docker compose 中的所有容器共享相同的默认网络,因此该 docker-compose 中的所有其他容器应该可以使用您的 redis 容器,主机为 redis(或您的容器)姓名,在您的情况下为 db)。

另外需要说明的是,如果你使用bullmq,不仅Queue选项需要自定义集合,你使用的任何WorkerQueueScheduler都需要,所以你要通过自定义连接他们也可以选择。

【讨论】:

  • 这很好。我所有的工人都用队列实例化,就像在 bullmq 文档中一样。 docs.bullmq.io/guide/workers 没有显示与工作人员共享连接选项的方法。正如我在问题中所说,我尝试了主机名redisdb,但没有成功。
  • 当我遇到这个问题时,向所有队列和工作实例添加“redis”(在我的例子中)解决了这个问题。如果你已经完成了,但它仍然不起作用,那么我什么都不会想到
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-09
  • 2016-05-22
  • 1970-01-01
  • 2019-11-14
  • 2019-02-05
  • 2021-03-02
相关资源
最近更新 更多