部署NestJS后台时主应用内部调用微服务的接口报错 connect ECONNREFUSED
, 最后还是定位到问题原因把整个过程记录下来。下面就是报错信息,我的第一反应,要么是ip不对访问错了容器,要不就是端口用映射错误放到了别的服务。
解决过程
1.Docker 层面的排查
1) 调用接口的 IP 是否与容器IP一致
怀疑主应用调用微服务的接口是IP处理错误了调用到了自己的IP,主应用在引入微服务时配置如下
ts
...
ClientsModule.registerAsync({
clients: [
{
name: 'DATA_SERVICE',
transport: Transport.TCP;
options: {
host: data_service; // 这里是Docker service 名称
port: 9002;
};
},
],
isGlobal: true,
}),
...
检查容器的结果 IP是一致
bash
$ docker inspect data_service
2) 在主应用配置的添加links
添加links的主要目的是想确保代码里面容器名称和IP地址映射正确
yml
# 应用服务
app_service:
image: "app_service"
container_name: app_service
build:
context: .
dockerfile: ./app-service/Dockerfile
...
networks:
- lifyg_dev
links:
- lifyg_data_service
2. NestJS 层面的排查
1) 创建和引入微服务时,传入host 与 port 变量类型是否正确
主要是担心传入类型错了,让这些方法使用了默认配置
ts
// 微服务创建时,确保类型一致
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
transport: Transport.TCP,
options: {
port: Number(process.env.DATA_SERVICE_PORT),
},
},
);
ts
// 主应用工程中,引入时的类型
ClientsModule.registerAsync({
clients: [
{
name: 'DATA_SERVICE',
transport: Transport.TCP;
options: {
host: data_service; // string,Docker service 名称
port: 9002; // number
};
},
],
isGlobal: true,
}),
2) 受下面两篇文章启发定位到问题
上面这些工作,我反复去人后很多次都不行。也找来之前发现的nestjs微服务示例工程做了比较,发现配置都是没问题的,后面在这篇文章中看到,NestJS Microservices (TCP Connection Refused) 看到之前他的调教思路是修改 host。
我才意识到,自己的代码里面创建微服务的时候没有填host这个参数。
我当下就反应过来docker容器内部的网络环境与compose文件里面配置的网络不同。因为开始时NestJS工程在本地运行都是用同一个网络环境,没有填host
参数那么就使用 localhost
,这里面Cannot connect dockerised microservices after v.6.0.5 有提及,所以本地开发时发现不了问题。
将host
参数加上并指定为服务容器的名称后,微服务和主应用就在同一个网络环境中,connect ECONNREFUSED
就没出现了。
结论
创建NestJS微服务时,最好始终传入host
,本地开发时可以设定为 localhost
, 在docker中部署时设定为微服务容器的 docker service name
参考文章
Cannot connect dockerised microservices after v.6.0.5