目的:
1.使用Ocelot实现服务网关,实现一个网关地址访问多个服务
2.使用Consul实现服务注册与发现(非集群,单点学习教程)
步骤:
一.安装Consul客户端
访问https://www.consul.io/downloads.html下载Consul客户端,下载完成后解压,根据选择路径解压完成后,在解压路径下的地址栏输入“cmd”,打开命令行窗口。
输入启动命令:consul.exe agent -dev
访问http://localhost:8500/ 出现以下页面就代表Consul运行成功了
二、创建三个API服务,分别是:Canoe.GateWay(网关服务),Canoe.ServiceA(服务A),Canoe.ServiceB(服务B)
1.Canoe.GateWay(网关服务)创建服务步骤:
打开VS2019,创建Canoe.GateWay网关服务,选择创建新项目——Asp.Net Core Web应用程序——配置新项目选择保存路径
点击创建后选择ASP.NET Core Web API,版本我选的ASP.NET Core5.0
点击创建就可以看到Canoe.GateWay(网关服务)项目生成了,配置网关,需要在NuGet引入Ocelot包和Ocelot.Provider.Consul包
添加一个ocelot.json配置文件
路由信息配置中有两个地方的配置是相同的,因为有两个服务,看服务名就能看出来,配置过后,最后的网管配置是很重要的,我们最后会根据这个网管的地址访问服务A和服务B,项目最后启动会演示。
{
"ReRoutes": [ //配置路由信息
{
"UseServiceDiscovery": true,
"DownstreamPathTemplate": "/{url}", //指定了下游的url及使用的通信协议,{url}是通配的意思
"DownstreamScheme": "http", //下游服务http schema
"ServiceName": "ServiceA", //服务名
"LoadBalancerOptions": {
"Type": "LeastConnection"
},
"UpstreamPathTemplate": "/ServiceA/{url}", //上游也就是用户输入的请求Url模板
"UpstreamHttpMethod": [ "Get" ] //上游请求http方法,可使用数组
},
{
"UseServiceDiscovery": true,
"DownstreamPathTemplate": "/{url}", //指定了下游的url及使用的通信协议,{url}是通配的意思
"DownstreamScheme": "http",
"ServiceName": "ServiceB",
"LoadBalancerOptions": {
"Type": "LeastConnection"
},
"UpstreamPathTemplate": "/ServiceB/{url}",
"UpstreamHttpMethod": [ "Get" ]
}
],
//网关配置
"GlobalConfiguration": {
"BaseUrl": "https://localhost:44355/",//网关地址
"ServiceDiscoveryProvider": {
"Host": "localhost",//请求域名
"Port": 8500,//端口
"Type": "Consul"//类型
}
}
}
参数说明:
Downstream : 下游服务配置
UpStream : 上游服务配置
Aggregates : 服务聚合配置
ServiceName, LoadBalancer, UseServiceDiscovery : 配置服务发现
AuthenticationOptions : 配置服务认证
RouteClaimsRequirement : 配置Claims鉴权
RateLimitOptions : 为限流配置
FileCacheOptions : 缓存配置
QosOptions : 服务质量与熔断
DownstreamHeaderTransform : 头信息转发
DownstreamPathTemplate:下游戏
DownstreamScheme:下游服务http schema
DownstreamHostAndPorts:下游服务的地址,如果使用LoadBalancer的话这里可以填多项
UpstreamPathTemplate: 上游也就是用户输入的请求Url模板
UpstreamHttpMethod: 上游请求http方法,可使用数组
Prioirty优先级: 对多个产生冲突的路由设置优化级
添加完配置文件后在Startup类中,ConfigureServices方法下注入Ocelot和Consul,其中ocelot.json就是我们刚刚创建的配置文件
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Canoe.GateWay", Version = "v1" });
});
//Ocelot和Consul的注入
services.AddOcelot(new ConfigurationBuilder()
.AddJsonFile("ocelot.json")
.Build()).AddConsul();
}
Configure中添加Ocelot中间件
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//添加网关中间件
app.UseOcelot();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Canoe.GateWay v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
至此,网关服务的配置就已经完成了。
接下来创建服务A和服务B
2、Canoe.ServiceA(服务A)
创建项目Canoe.ServiceA的步骤和创建Canoe.GateWay的步骤是一样的,Canoe.ServiceA创建好了以后,在NuGet中引入Consul包
创建一个用于健康检查的控制器,找到Controllers——右键——添加——控制器,选择API控制器空
控制器命名为Health,修改控制器的路由访问,添加GET请求方法,如图:
[Route("[controller]/[action]")]
[ApiController]
public class HealthController : ControllerBase
{
[HttpGet("/healthCheck")]
public IActionResult Check() => Ok("ok");
}
请求该方法时返回ok就证明当前服务是正常的。
在appsettings配置文件里配置Consul的配置信息,其中ServiceHealthCheck代表健康检查地址,这里赋值刚刚创建的健康检查接口地址,如图:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ServiceName": "ServiceA",//服务名
"ServiceIP": "localhost",//服务域名
"ServicePort": 44316,//端口
"ServiceHealthCheck": "https://localhost:44316/healthCheck",//健康检查服务地址
"ConsulAddress": "http://localhost:8500/"//Consul的地址
}
配置完成以后,编写一个Consul的中间件,用于多个服务调用,首先解决方案,右键——添加——新建项目——类库(.NetCore)
该类库命名为:Canoe.Configuration.Consul,创建好类库以后,我们在类库里面创建一个Consul的扩展类ConsulBuilderExtensions用于封装中间件,实体类ConsulOption
代码如下:
public static class ConsulBuilderExtensions
{
//编写Consul中间件
public static IApplicationBuilder RegisterConsul(this IApplicationBuilder app, IApplicationLifetime lifetime, ConsulOption consulOption)
{
var consulClient = new ConsulClient(x =>
{
// consul 服务地址
x.Address = new Uri(consulOption.Address);
});
var registration = new AgentServiceRegistration()
{
ID = Guid.NewGuid().ToString(),
Name = consulOption.ServiceName,// 服务名
Address = consulOption.ServiceIP, // 服务绑定IP
Port = consulOption.ServicePort, // 服务绑定端口
Check = new AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册
Interval = TimeSpan.FromSeconds(10),//健康检查时间间隔
HTTP = consulOption.ServiceHealthCheck,//健康检查地址
Timeout = TimeSpan.FromSeconds(5)
}
};
// 服务注册
consulClient.Agent.ServiceRegister(registration).Wait();
// 应用程序终止时,服务取消注册
lifetime.ApplicationStopping.Register(() =>
{
consulClient.Agent.ServiceDeregister(registration.ID).Wait();
});
return app;
}
}
/// <summary>
/// Consul 注册发现相关参数
/// </summary>
public class ConsulOption
{
/// <summary>
/// 服务名称
/// </summary>
public string ServiceName { get; set; }
/// <summary>
/// 服务IP
/// </summary>
public string ServiceIP { get; set; }
/// <summary>
/// 服务端口
/// </summary>
public int ServicePort { get; set; }
/// <summary>
/// 服务健康检查地址
/// </summary>
public string ServiceHealthCheck { get; set; }
/// <summary>
/// Consul 地址
/// </summary>
public string Address { get; set; }
}
代码中获取的服务名,服务ip,服务端口以及服务的健康检查都是从appsettings里配置信息获取的。
创建完如果报错的话,需要引入ASP.NETCore的包,因为我创建的版本是ASPNetCore5.0,所以我引入的包是Swashbuckle.AspNetCore
到此Consul的扩展类封装完毕,回到Canoe.ServiceA服务,依赖项右键添加项目引用,添加我们上面创建的Canoe.Configuration.Consul库
引入完成以后,在Startup类中Configure下引入封装好的中间件
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, Microsoft.AspNetCore.Hosting.IApplicationLifetime lifetime)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Canoe.ServiceA v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
#region 引入Consul中间件
var consulOption = new ConsulOption
{
ServiceName = Configuration["ServiceName"],
ServiceIP = Configuration["ServiceIP"],
ServicePort = Convert.ToInt32(Configuration["ServicePort"]),
ServiceHealthCheck = Configuration["ServiceHealthCheck"],
Address = Configuration["ConsulAddress"]
};
app.RegisterConsul(lifetime, consulOption);
#endregion
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
好了,Canoe.ServiceA创建好了,Canoe.ServiceB服务也是同样的步骤,就不重复了,现在启动服务看看。
3、启动服务,访问服务
右键解决方案,选择属性——通用属性——启动项目——多个启动项目,然后把网关服务、服务A、服务B选择启动
点击启动按钮,启动程序
启动成功后,刷新Consul地址,发现两个服务已经注册进来了
现在我们通过网关地址来访问两个服务:https://localhost:44355/ServiceA/WeatherForecast访问服务A,成功返回
访问服务B:https://localhost:44355/ServiceB/WeatherForecast 成功返回:
到此,一个简单的.NetCore+Consul+Ocelot实现服务网关,服务注册与发现的操作就完成了。最后奉上一个完整的Demo下载地址https://download.csdn.net/download/huqngqing/13214598
小妹也是在边学边用,有什么不足之处望各位多多指点一二。都看到这了,来,加群:274407988。