NestJS-Docker 部署微服务服务报错connect ECONNREFUSED.md

1,563 阅读2分钟

部署NestJS后台时主应用内部调用微服务的接口报错 connect ECONNREFUSED, 最后还是定位到问题原因把整个过程记录下来。下面就是报错信息,我的第一反应,要么是ip不对访问错了容器,要不就是端口用映射错误放到了别的服务。

image-20230825174747505.png

解决过程

1.Docker 层面的排查

1) 调用接口的 IP 是否与容器IP一致

怀疑主应用调用微服务的接口是IP处理错误了调用到了自己的IP,主应用在引入微服务时配置如下

 ...
   ClientsModule.registerAsync({
      clients: [
        {
          name: 'DATA_SERVICE',
           transport: Transport.TCP;
           options: {
              host: data_service; // 这里是Docker service 名称
              port: 9002;
           };
        },
      ],
      isGlobal: true,
    }),
 ...

检查容器的结果 IP是一致

$ docker inspect data_service

image-20230825180215524.png

2) 在主应用配置的添加links

添加links的主要目的是想确保代码里面容器名称和IP地址映射正确

  # 应用服务
  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 变量类型是否正确

主要是担心传入类型错了,让这些方法使用了默认配置

 // 微服务创建时,确保类型一致
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
    AppModule,
    {
      transport: Transport.TCP,
      options: {
        port: Number(process.env.DATA_SERVICE_PORT),
      },
    },
);
// 主应用工程中,引入时的类型
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。

e070c18a1d60c533cef32986c8f073e12fbd99a5.png

我才意识到,自己的代码里面创建微服务的时候没有填host这个参数。

image-20230825182128988.png

我当下就反应过来docker容器内部的网络环境与compose文件里面配置的网络不同。因为开始时NestJS工程在本地运行都是用同一个网络环境,没有填host参数那么就使用 localhost,这里面Cannot connect dockerised microservices after v.6.0.5 有提及,所以本地开发时发现不了问题。

host 参数加上并指定为服务容器的名称后,微服务和主应用就在同一个网络环境中,connect ECONNREFUSED 就没出现了。

image-20230825182512193.png

结论

创建NestJS微服务时,最好始终传入host,本地开发时可以设定为 localhost, 在docker中部署时设定为微服务容器的 docker service name

参考文章

Cannot connect dockerised microservices after v.6.0.5

NestJS Microservices (TCP Connection Refused)

nestjs-microservices-example