.net core Ocelot+Consul实现网关及服务注册和服务发现
Ocelot是一个用.NET Core实现并且开源的API网关。对于网关概念不是很清楚的可以参照https://www.jianshu.com/p/7baab672b822。
Consul 是 HashiCorp 公司的一个用于实现分布式系统的服务发现与配置工具。Consul内置了服务注册与发现框 架、分布一致性协议实现、健康检查、Key/Value存储、多数据中心方案。
这篇文章将一步一步介绍如何使用Ocelot+consul实现网关及服务注册和服务发现功能。
一、安装Consul,安装后的效果如下图。
二、建立项目。
使用.net core 新建三个webAPI项目,分别为网关、服务A和服务B,建好后的项目结构如下图
三、网关配置
ApiGateway是网关项目,为其添加Ocelot和consul包,具体的依赖包如下图。
然后在ConfigureServices方法中添加Ocelot和Consul的注入,代码如下,其中AddJsonFile("ocelot.json")指定了ocelot的配置文件。
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); 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.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
添加ocelot.json配置文件,在配置文件中,可以配置服务发现、路由、负载均很、鉴权、熔断限流等。这里只演示路由和服务发现功能,如下图。
Routes配置路由信息, "UseServiceDiscovery": true,表示使用服务发现功能,
"DownstreamPathTemplate": "/{url}",
"DownstreamScheme": "http",
指定了下游的url及使用的通信协议,{url}是通配的意思。
"ServiceName": "ServiceA",指定下游使用的服务名是ServiceA,使用ServiceA这个服务名到consul服务器去发现下游对应的IP及端口。
"UpstreamPathTemplate": "/ServiceA/{url}",
"UpstreamHttpMethod": [ "Get" ]
指定了上游的访问路由格式及请求方式。
"GlobalConfiguration": {
"BaseUrl": "https://192.168.0.103:5000",
"ServiceDiscoveryProvider": {
"Host": "192.168.0.102",
"Port": 8500,
"Type": "Consul"
}
}
这段是全局配置,BaseUrl表示ocelot上游使用的IP及端口。ServiceDiscoveryProvider指定Consul的服务器和端口,用于服务发现。至此,api网关部分已经完成。
四、webapi配置
为ServiceA和ServiceB分别添加consul的nuget包。
然后在appsettings.json中配置consul服务器的配置信息。如下图
这里需要注意ServiceName,在Ocelot中使用的服务发现名也就是ServiceA这个名字,也就是说,服务需要先到Consul上注册,然后才能发现。
添加健康检查接口
[Route("[controller]/[action]")] [ApiController] public class HealthController : ControllerBase { [HttpGet("/healthCheck")] public IActionResult Check() => Ok("ok"); }
接着我们添加两个文件ConsulBuilderExtensions.cs和ConsulOption.cs用于注册Consul.
public static class ConsulBuilderExtensions { 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; } }
然后在startup.cs中使用consul中间件
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApplicationLifetime lifetime) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseAuthorization(); 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); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
至此大功告成,我们看一下效果。将三个项目均设置为启动项目,并启动。
consul服务器看到了注册到的ServiceA和ServiceB
如下图,访问Ocelot上游路由地址http://192.168.0.103:5000/ServiceA/weatherforecast和http://192.168.0.103:5000/ServiceB/weatherforecast,可以正确访问到服务A和服务B。路由及服务注册、服务发现均已实现。
源代码地址:https://gitee.com/lp244392323/LP.Demo/tree/master/OcelotWithConsul/WebAppOcelotWithConsul