docker - Redis docker 在 docker-compose 的 localhost 上不可用
问题描述
我目前遇到了一个我试图解决一个多星期的问题,但我无处可去。我希望你能指出我正确的方向。
初始情况
描述
我正在构建的项目是一个连接到一些 API的NestJS应用程序。在内部,它使用bulmq作为消息队列,它本身使用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
服务器组件
- 公牛MQ 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 我发现了这个问题。因此,它应该在我的工作站上本地提供所有提示,我使用 0.0.0.0:6379 进行连接,它工作得很好。
Docker compose 确实会自动创建一个网桥,并使用我检查过的 netcat,redis docker 的 ip 上的端口 6379(以及别名 redis 和 db),redis 实例可从服务器 dockers 控制台获得。
然后,我使用 docker-compose 的网络配置以及为容器提供静态 IP 来明确设置子网,但正如我已经描述的: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问题板上找到了一个类似问题的相对较新的帖子,并且我从重用连接对象中的连接(如上所示)切换到始终创建新连接,正如它也在bulmq 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
这不是最漂亮的解决方案,但目前确实有效。
解决方案
问题是您的应用程序容器使用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
,容器只是在尝试连接到自身。
推荐阅读
- angular - 角度测试 - 类型错误:无法读取未定义的属性“7”
- redirect - Wiremock 如何在 JSON 中映射 302 响应以进行独立运行
- angular - 从另一个组件引用模板
- python - 从动态字符串中提取 ID SET
- terraform - 用于创建地图的 Terraform 插值
- javascript - Angular:两个没有名字的网点仍然有效
- java - Spring Boot 应用程序 jar 无法运行
- typescript - 如何断言导入的值是某种类型
- sql - Oracle:比较两个不同表中没有主键的字符串列以查找匹配/不匹配的字符串
- python - 使用 os.system('./myProgram') 调用另一个程序时,Python 脚本无法正确执行