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