.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/weatherforecasthttp://192.168.0.103:5000/ServiceB/weatherforecast,可以正确访问到服务A和服务B。路由及服务注册、服务发现均已实现。

 

 

 

源代码地址:https://gitee.com/lp244392323/LP.Demo/tree/master/OcelotWithConsul/WebAppOcelotWithConsul

posted @ 2020-08-03 21:20  清晨时光  阅读(1157)  评论(0编辑  收藏  举报