Nestjs集成Consul服务注册发现

1. consul下载

windows下载

https://developer.hashicorp.com/consul/install#windows

2. consul 角色

dev 开发模式

consul agent -dev

server 服务端模式

保存配置信息,高可用集群,每个数据中心的server数量推荐3-5个

consul agent -server -bind=192.168.10.101 -client=0.0.0.0 -ui -bootstrap-expect=3 -data-dir=/usr/local/consul/data -node=server-01

consul agent -server -bind=192.168.10.102 -client=0.0.0.0 -ui -bootstrap-expect=3 -data-dir=/usr/local/consul/data -node=server-02

consul agent -server -bind=192.168.10.103 -client=0.0.0.0 -ui -bootstrap-expect=3 -data-dir=/usr/local/consul/data -node=server-03

-server: 服务端身份启动

-bind:绑定IP

-client:绑定客户端IP

-ui:开启web页面

-bootstrap-expect:启动集群最低节点数量

-data-dir:数据存放的目录

-node:节点名称

client 客户端模式

无状态,将HTTP和DNS接口请求转发给局域网内的服务端集群

consul agent -client=0.0.0.0 -bind=192.168.10.1 -data-dir=C:\consul\data -node=client-01

关联集群

把节点 102 103 加入到 101中

consul join 192.168.10.101

集群状态

consul members

3. 启动consul

使用单节点启动consul

consul agent -dev

4. 创建项目

初始化项目

nest new nest-monorepo

安装依赖包

pnpm i @nestjs/microservices consul

创建main-app应用

nest g app main-app

创建micro-app应用

nest g app micro-app

创建consul库

nest g lib consul

修改nest-cli.json

{
  "$schema": "https://json.schemastore.org/nest-cli",
  "collection": "@nestjs/schematics",
  "sourceRoot": "apps/main-app/src",
  "compilerOptions": {
    "deleteOutDir": true,
    "webpack": true,
    "tsConfigPath": "apps/main-app/tsconfig.app.json"
  },
  "monorepo": true,
  "root": "apps/main-app",
  "projects": {
    "micro-app": {
      "type": "application",
      "root": "apps/micro-app",
      "entryFile": "main",
      "sourceRoot": "apps/micro-app/src",
      "compilerOptions": {
        "tsConfigPath": "apps/micro-app/tsconfig.app.json"
      }
    },
    "main-app": {
      "type": "application",
      "root": "apps/main-app",
      "entryFile": "main",
      "sourceRoot": "apps/main-app/src",
      "compilerOptions": {
        "tsConfigPath": "apps/main-app/tsconfig.app.json"
      }
    },
    "consul": {
      "type": "library",
      "root": "libs/consul",
      "entryFile": "index",
      "sourceRoot": "libs/consul/src",
      "compilerOptions": {
        "tsConfigPath": "libs/consul/tsconfig.lib.json"
      }
    }
  }
}

5. 设置consul library

5.1 修改consul.module.ts

import { Global, Module } from '@nestjs/common';
import { ConsulService } from './consul.service';
import * as Consul from 'consul';

@Global()
@Module({})
export class ConsulModule {
  static forRoot() {
    const provider = {
      provide: 'CONSUL',
      useFactory: () => {
        return new Consul({
          host: '127.0.0.1',
          port: '8500',
          promisify: true,
        });
      },
    };
    return {
      module: ConsulModule,
      providers: [provider, ConsulService],
      exports: [provider, ConsulService],
    };
  }
}

5.2 修改consul.service.ts

import { Inject, Injectable } from '@nestjs/common';
import * as Consul from 'consul';
import { ConsulServiceNode } from './consul.interface';

@Injectable()
export class ConsulService {
  constructor(@Inject('CONSUL') private consul: Consul.Consul) {}

  async register(options: Consul.Agent.Service.RegisterOptions) {
    return await this.consul.agent.service.register(options);
  }

  async deregister(id: string) {
    return await this.consul.agent.service.deregister(id);
  }

  async maintenance(options: Consul.Agent.Service.MaintenanceOptions) {
    return await this.consul.agent.service.maintenance(options);
  }

  async findService(
    serviceName: string,
  ): Promise<{ host: string; port: number }> {
    const services = await this.consul.catalog.service.nodes<
      ConsulServiceNode[]
    >(serviceName);
    if (!services.length) {
      throw new Error(`Service ${serviceName} not found`);
    }
    const service = services[0];
    return {
      host: service.ServiceAddress,
      port: service.ServicePort,
    };
  }
}

5.3 添加consul.interface.ts

export interface ConsulServiceObj {
  ID: string;
  Service: string;
  Tags: string[];
  Meta: any;
  Port: number;
  Address: string;
  Weights: { Passing: number; Warning: number };
  EnableTagOverride: boolean;
  Datacenter: string;
}

export interface ConsulServiceMap {
  [key: string]: ConsulServiceObj;
}

export interface ConsulServiceNode {
  ID: string;
  Node: string;
  Address: string;
  Datacenter: string;
  TaggedAddresses: {
    lan: string;
    lan_ipv4: string;
    wan: string;
    wan_ipv4: string;
  };
  NodeMeta: Record<string, string>;
  ServiceKind: string;
  ServiceID: string;
  ServiceName: string;
  ServiceTags: string[];
  ServiceAddress: string;
  ServiceTaggedAddresses: { lan_ipv4: any; wan_ipv4: any };
  ServiceWeights: { Passing: number; Warning: number };
  ServiceMeta: any;
  ServicePort: number;
  ServiceSocketPath: string;
  ServiceEnableTagOverride: boolean;
  ServiceProxy: { Mode: string; MeshGateway: any; Expose: any };
  ServiceConnect: any;
  ServiceLocality: null;
  CreateIndex: number;
  ModifyIndex: number;
}

export interface ConsulKV {
  LockIndex: number;
  Key: string;
  Flags: number;
  Value: string;
  CreateIndex: number;
  ModifyIndex: number;
}

5.4 修改consul/src/index.ts

export * from './consul.module';
export * from './consul.service';
export * from './consul.interface';

6. 设置micro-app

6.1 修改main.ts

import { NestFactory } from '@nestjs/core';
import { MicroAppModule } from './micro-app.module';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';

async function bootstrap() {
  const app = await NestFactory.createMicroservice<MicroserviceOptions>(
    MicroAppModule,
    {
      transport: Transport.TCP,
      options: {
        host: '127.0.0.1',
        port: 3003,
      },
    },
  );
  await app.listen();
}
bootstrap();

6.2 修改micro-app.module.ts

import { Module, OnModuleInit } from '@nestjs/common';
import { MicroAppController } from './micro-app.controller';
import { MicroAppService } from './micro-app.service';
import { ConsulModule } from '@app/consul/consul.module';
import { ConsulService } from '@app/consul/consul.service';

@Module({
  imports: [ConsulModule.forRoot()],
  controllers: [MicroAppController],
  providers: [MicroAppService],
})
export class MicroAppModule implements OnModuleInit {
  constructor(private readonly consulService: ConsulService) {}

  async onModuleInit() {
    await this.consulService.register({
      name: 'micro-app',
      address: '127.0.0.1',
      port: 3003,
    });
  }
}

6.3 修改micro-app.controller.ts

import { Controller, Get } from '@nestjs/common';
import { MicroAppService } from './micro-app.service';
import { MessagePattern } from '@nestjs/microservices';

@Controller()
export class MicroAppController {
  constructor(private readonly microAppService: MicroAppService) {}

  @MessagePattern({ cmd: 'hello' })
  async getMicroHello() {
    return 'i am micro-app';
  }

  @Get()
  getHello(): string {
    return this.microAppService.getHello();
  }
}

7. 设置main-app

7.1 修改main.ts

import { NestFactory } from '@nestjs/core';
import { MainAppModule } from './main-app.module';

async function bootstrap() {
  const app = await NestFactory.create(MainAppModule);
  await app.listen(3002);
}
bootstrap();

7.2 修改main-app.module.ts

import { Module, OnModuleInit } from '@nestjs/common';
import { MainAppController } from './main-app.controller';
import { MainAppService } from './main-app.service';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { ConsulModule } from '@app/consul/consul.module';
import { ConsulService } from '@app/consul/consul.service';

@Module({
  imports: [
    ConsulModule.forRoot(),
    ClientsModule.registerAsync([
      {
        name: 'MICRO_APP_SERVICE',
        useFactory: async (consulService: ConsulService) => {
          const { host, port } = await consulService.findService('micro-app');
          return {
            transport: Transport.TCP,
            options: {
              host,
              port,
            },
          };
        },
        inject: [ConsulService],
      },
    ]),
  ],
  controllers: [MainAppController],
  providers: [MainAppService],
})
export class MainAppModule implements OnModuleInit {
  constructor(private readonly consulService: ConsulService) {}

  async onModuleInit() {
    await this.consulService.register({
      name: 'main-app',
      address: '127.0.0.1',
      port: 3002,
    });
  }
}

7.3 修改main-app.controller.ts

import { Controller, Get, Inject } from '@nestjs/common';
import { MainAppService } from './main-app.service';
import { ClientProxy } from '@nestjs/microservices';

@Controller()
export class MainAppController {
  constructor(
    private readonly mainAppService: MainAppService,
    @Inject('MICRO_APP_SERVICE')
    private readonly microAppService: ClientProxy,
  ) {}

  @Get('/micro')
  getMicroHello() {
    return this.microAppService.send({ cmd: 'hello' }, {});
  }

  @Get()
  getHello(): string {
    return this.mainAppService.getHello();
  }
}

8. 测试

8.1 启动 micro-app

nest start micro-app --watch

8.2 启动 main-app

nest start main-app --watch

8.3 使用postman测试

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值