我目前遇到了一个问题,我已经尝试解决了一个多星期,但一无所获。我希望你能给我指明正确的方向。
初始情况
说明
我正在构建的项目是一个NestJS应用程序,它连接到一些API。在内部,它使用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 docker
- 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吗?
我检查过的东西
服务器代码正确,REDIS_HOST在ioredis调用中正确提交和调用。因此,在深入挖掘ioredis的过程中,我发现了这个问题。因此,如果在我的工作站上有所有提示,它应该是可用的,我使用0.0.0.0:6379进行连接,它运行得很好。
Docker compose确实自动创建了一个网桥,使用netcat i checked,redis Docker ip上的6379端口(以及别名redis&db),redis实例可以从服务器dockers控制台获得。
然后,我使用docker compose的网络配置明确地设置了子网,并为容器提供了静态ip,但正如我已经描述的:ip已正确解析。
我在docker github第204期上发现了以下问题。我想这正是我在这里面临的问题,但如何解决呢?
tl;dr ioredis尝试连接到redis实例的正确解析的ip,但失败了,因为该实例在服务器组件的本地ip上不可用。
我目前的状态是什么
我无法控制地哭泣。
我目前不知道如何获得";myserver"-容器通过ioredis连接到redis实例。我的观点是,我遇到的问题必须与windows上的docker将ips解析为127.0.0.1的方式有关。
- 我的观点对吗
- 你还建议用什么方法试试
致以最良好的问候&提前谢谢。
编辑(2020-11-27):在对Jeffrey Mixon的建议进行了一些挖掘和进一步调查后,我暂时还没有找到解决方案。我最后的步骤包括:
- 更新所有依赖项(其中bullmq更新到v1.11,ioredis更新到4.19.2)。这并没有改变任何事情
- 然后,我在bullmq问题板上发现了一篇关于类似问题的相对较新的帖子,我从如上所示在连接对象中重用连接切换到始终创建新连接,这在bullmq文档中也有解释。但这也于事无补
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机器上检查了这个问题是否只会发生在windows的docker上,但它也会发生在linux上。
我自己并没有解决这个问题,但我只是把所有的东西都放在一个码头里,绕过了它。由于我的应用程序更多的是一种概念验证,所以这样做没有什么大的痛苦。如果将来碰巧有解决方案或更多的人有同样的问题,我会保留这个问题。
对于那些想知道的人来说,我的包括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
这不是最漂亮的解决方案,但目前确实有效。
问题是您的应用程序容器使用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
,容器只是尝试连接到自身。
docker compose的问题是redis不在localhost
上,而是在自己的网络上。默认情况下,docker compose中的所有容器共享同一个默认网络,因此您的redis容器应该可供该docker composed中的所有其他容器使用主机redis
(或者您的容器名称,在您的情况下为db
)使用。
另一点需要注意的是,如果您使用bullmq
,不仅Queue
选项需要自定义集合,而且您使用的任何Worker
或QueueScheduler
都需要,因此您也应将自定义连接选项传递给它们。
希望这能有所帮助,我刚刚遇到了这个问题,结果发现这是一个代码问题,设置正确的方式通过客户端对象连接到redis是我的问题的原因,请确保您的代码与redis模块的版本相匹配。
在我的情况下,redis v4.6.6,以下操作有效:
//创建redis客户端并确保连接const redisClient=redis.createClient({网址:CCD_ 11,});