100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > Api网关Kong集成Consul做服务发现及在Asp.Net Core中的使用

Api网关Kong集成Consul做服务发现及在Asp.Net Core中的使用

时间:2020-08-15 01:58:57

相关推荐

Api网关Kong集成Consul做服务发现及在Asp.Net Core中的使用



1622219047536

写在前面

Api网关我们之前是用 .netcore写的 Ocelot的,使用后并没有完全达到我们的预期,花了些时间了解后觉得kong可能是个更合适的选择。

简单说下kong对比ocelot打动我的:

1、kong可以直接代替Nginx/OpenRestry做前端服务器。

2、kong的功能强大,性能不俗,生态不错,操作面板,插件丰富,社区活跃;

本文目的

1、对kong和consul做个基本介绍;

2、kong集成consul 做服务发现;

3、 core WebApi 服务自动注册到Consul;

4、 core WebApi 自动注册路由规则到kong,实现程序启动即部署;

运行环境

172.16.1.30 CentOS Linux release 7.6.1810 (Core) (虚拟机单核2g)

Docker version 18.09.3, build 774a1f4

kong apigateway(enterprise) 2.3.x (docker安装)

kong

kong的简介

KONG — The Microservice API Gateway | by faren | Medium

我们熟悉Nginx;

有个一个加强版的Nginx叫做OpenRestry,OpenRestry ≈ lua脚本+Nginx;

那么Kong 网关就是满血版的 OpenRestry,它有许许多多的的插件和各种丰富的功能,且提供对应的Rest Api,让你轻松打造你所能想象到的 网关+ web前端服务器的功能;

特点(翻译)

云原生:平台无关,kong支持任意平台,裸机容器或云平台;

k8s原生:原生支持k8s,有kong-ingress,支持l4+l7协议;

动态负载均衡:负载均衡到多个upstream;

Hash-based的负载均衡:根据cookie、session,ip等hash负载均衡;

断路器:自动剔除不健康的服务;

心跳检测:主动和被动心跳检测;

服务发现:通过第三方dns解析做服务发现,如consul;

Serverless:调用和保护 AWS Lambda or OpenWhisk functions directly ;

WebSockets:支持ws、wss协议;

gRPC:支持gRPC协议,并通过日志和插件监控流量;

OAuth2.0:轻松添加OAuth2.0支持;

日志:轻松记录请求和响应,通过HTTP, TCP, UDP, 或 直接到硬盘;

安全性:访问控制,爬虫检测、ip黑白名单等等;

Syslog:记录到系统日志;

SSL:安装不同的SSL证书到服务;

监控:实时监控,提供关机负责负载均衡和性能指标;

整箱代理:kong可以作为正向代理服务器;

身份认证:HMAC, JWT, Basic, 各种奇奇怪怪的规则都支持.

限制器:流量限制功能;

传输转换:新增、删掉、或者修改你的请求或者响应;

缓存:请求缓存;

CLI:命令行控制支持;

Rest Api:Rest Api控制支持;

Geo-Replicated:夸时区请求支持;

故障检测与恢复:数据库(Cassandra /postgres)节点挂掉不影响kong的服务;

集群:所有kong节点都自动加入集群保持配置同步;

拓展性:分布式拓展原生支持,水平伸缩加减节点就行;

高性能:使用Nginx作为核心负载均衡组件,高性能可伸缩;

插件:高拓展性,插件式添加功能;

详细请看

github:/Kong/kong

官方文档:

kong的安装

拉取镜像

dockerpullkong/kong-gateway:2.3.3.2-alpine

给镜像改个名

dockertag<IMAGE_ID>kong-ee

创建一个网络

dockernetworkcreatekong-ee-net

运行一个postgresSql 9.6,用来存取kong的配置

dockerrun-d--namekong-ee-database\--network=kong-ee-net\-p5432:5432\-e"POSTGRES_USER=kong"\-e"POSTGRES_DB=kong"\-e"POSTGRES_PASSWORD=kong"\postgres:9.6

启动kong

dockerrun-d--namekong-ee2--network=kong-ee-net\-e"KONG_DATABASE=postgres"\-e"KONG_PG_HOST=172.16.1.30"\-e"KONG_PG_PASSWORD=kong"\-e"KONG_PROXY_ACCESS_LOG=/dev/stdout"\-e"KONG_ADMIN_ACCESS_LOG=/dev/stdout"\-e"KONG_PROXY_ERROR_LOG=/dev/stderr"\-e"KONG_ADMIN_ERROR_LOG=/dev/stderr"\-e"KONG_ADMIN_LISTEN=0.0.0.0:8001"\-e"KONG_ADMIN_GUI_URL=http://172.16.1.30:8002"\-e"KONG_DNS_RESOLVER=172.16.1.30:8600"\#注意按需使用,consul的才配-p8000:8000\-p8443:8443\-p8001:8001\-p8444:8444\-p8002:8002\-p8445:8445\-p8003:8003\-p8004:8004\kong-ee//-e"KONG_DNS_RESOLVER=172.16.1.30:8600"注意这个配置,这是我需要用的consul的dns配置,如果不想用consul做服务发现,删掉这行

这里说明一下,kong的配置是用postgres(或者Cassandra )来存配置,但每一次请求都不需要去读取数据库的。修改的配置会直接 reload 到内存中,不影响性能;

另外说说kong的集群;

因为kong 网关其实最终 表现为一个超级前端服务器+网关,所以每个连接到同个数据库的kong实例配置一样,连接同个数据库的kong作为一个集群;

一般在kong的前面是直接做dns解析就行,如果dns不支持多ip的话做keepalive + vip就行;

验证

#adminapi获取所有服务curl-i-XGET--urlhttp://127.0.0.1:8001/services#admin管理后台curl-i-XGET--urlhttp://127.0.0.1:8002

1622292530454
1622292862508

管理后台

1622297057459

consul

consul简介

Consul Service Mesh with Paul Banks - Software Engineering Daily

Consul是HashiCorp公司推出的开源工具,用于实现分布式系统的服务发现与配置。与其他分布式服务注册与发现的方案,比如 Airbnb的SmartStack等相比,Consul的方案更“一站式”,内置了服务注册与发现框 架、分布一致性协议实现、健康检查、Key/Value存储、多数据中心方案,不再需要依赖其他工具(比如ZooKeeper等),使用起来也较 为简单。

其实就是做服务治理的。

github: /hashicorp/consul

官方文档: https://www.consul.io/

consul的安装

直接docker安装

*这是作为开发节点安装

dockerrun-d--name=dev-consul1--network=host-eCONSUL_BIND_INTERFACE=eth0consul:1.8

安装成功

1622295177798

运行一个WebApi服务

先在服务运行一个 Core WebApi (就是是新建的一个包含),我的版本是3.1的,我给服务命名:DemoApi31,监听端口5002

1622294659671

将服务注册到Consul

curl--location--requestPUT'http://172.16.1.30:8500/v1/agent/service/register'\--header'Content-Type:application/json'\--data-raw'{"ID":"DemoApi31_172.16.1.30:5002","Name":"DemoApi31","Address":"172.18.1.30","Port":5002,"EnableTagOverride":false,"Weights":{"Passing":10,"Warning":1}}'

注册成功:

1622295901281

Dns解析验证

#如果没安装dig 安装:yum install bind-utilsdig@172.16.1.30-p8600Demoapi31.service.consulSRV

1622294451840

ok,我们这里已经把服务注册到consul,且能通过dns常解析到了,我们做跟kong的集成吧。

consul提供内置Dns解析和Rest Api 两种方式集成做服务发现,我们这里跟kong的集成选用的Dns方式。

kong集成consul做服务发现

因为consul的角色是dns服务器,所以非常简单,我们已注册好的DemoApi31为例:

1、创建一个名为consul的服务

DemoApi31.service.consul 是consu要求的格式

1622297254563

2、创建一个名为consul的路由

1622297366317

验证

访问我们配置的kong路由:http://172.16.1.30:8000/consul/api/values

1622297455784

ok

到目前为止我们只完成了本文目的1、2

3,和4三请往下看;

在 Core中的使用

以之前的DemoApi31为例,换成5003端口,我需要达到的效果是,程序启动的时候就把服务注册到Consul 做好心跳检测,并同时部署到网关Kong,直接对外服务。

Core 服务自动注册到Consul

安装nuget包

Install-PackagePassport.Infrastructure-Version0.1.4.7-preview-1

加入配置appsettings.json

大家主要各服务器要改成自己的

"ServiceDiscovery":{"ServiceName":"DemoApi31","Consul":{"HttpEndpoint":"http://172.16.1.30:8500","HttpHeathCheck":{"Path":"/healthcheck","TimeOunt":10,"Interval":10},"Tags":["NetCore","DemoApi","v1.0"]}}

StartUp.cs ConfigureServices方法

publicvoidConfigureServices(IServiceCollectionservices){//第一行PassportConfig.InitPassportConfig(Configuration,Environment);......services.AddHealthChecks();services.AddConsul();}

StartUp.cs Configure方法

app.UseHealthChecks("/healthcheck");

启动程序

dotnetDemoApi.Core3.1.dll--healthhost172.16.1.30--urlshttp://*:5003

1622299506567
1622299584100

源码解析

///<summary>///加入consul做服务管理///</summary>///<paramname="services"></param>///<returns></returns>publicstaticIServiceCollectionAddConsul(thisIServiceCollectionservices){varoptions=PassportConfig.GetSection("ServiceDiscovery").Get<ServiceDiscoveryOptions>();if(options?.Disable!=true){varhealthHost=PassportConfig.GetHealthHost();if(string.IsNullOrWhiteSpace(options?.ServiceName)||string.IsNullOrWhiteSpace(options?.Consul?.HttpEndPoint)){thrownewArgumentNullException("ServiceDiscovery.ServiceName/Consul.HttpEndpointcannotbenullorempty!");}//实例化kongclientvarconsulClient=newConsulClient(x=>x.Address=newUri(options.Consul.HttpEndPoint));services.AddSingleton(consulClient);services.Configure(newAction<ConsulOptions>(op=>{op.HttpEndPoint=options.Consul.HttpEndPoint;op.Token=options.Consul.Token;op.TcpEndPoint=options.Consul.TcpEndPoint;}));varcheckOptions=options.Consul.HttpHeathCheck;varcheckUrl=$"http://{healthHost}:{PassportConfig.GetCurrentPort()}{checkOptions.Path}";newConsulBuilder(consulClient).AddHttpHealthCheck(checkUrl,checkOptions.TimeOunt,checkOptions.Interval).RegisterService(options.ServiceName,healthHost,PassportConfig.GetCurrentPort(),options.Consul.Tags).Wait();}returnservices;}

ConsulBuilder.cs 参考晓晨大佬

publicclassConsulBuilder{privatereadonlyConsulClient_client;privatereadonlyList<AgentServiceCheck>_checks=newList<AgentServiceCheck>();publicConsulBuilder(ConsulClientclient){_client=client;}publicConsulBuilderAddHealthCheck(AgentServiceCheckcheck){_checks.Add(check);returnthis;}///<summary>//////</summary>///<paramname="url"></param>///<paramname="timeout">unit:second</param>///<paramname="interval">checkinterval.unit:second</param>///<returns></returns>publicConsulBuilderAddHttpHealthCheck(stringurl,inttimeout=10,intinterval=10){_checks.Add(newAgentServiceCheck(){DeregisterCriticalServiceAfter=TimeSpan.FromSeconds(timeout*3),Interval=TimeSpan.FromSeconds(interval),HTTP=url,Timeout=TimeSpan.FromSeconds(timeout)});PassportConsole.Success($"[Consul]AddHttpHealthcheckSuccess!CheckUrl:{url}");returnthis;}///<summary>//////</summary>///<paramname="endpoint">GPRCserviceaddress.</param>///<paramname="grpcUseTls"></param>///<paramname="timeout">unit:second</param>///<paramname="interval">checkinterval.unit:second</param>///<returns></returns>publicConsulBuilderAddGRPCHealthCheck(stringendpoint,boolgrpcUseTls=false,inttimeout=10,intinterval=10){_checks.Add(newAgentServiceCheck(){DeregisterCriticalServiceAfter=TimeSpan.FromSeconds(20),Interval=TimeSpan.FromSeconds(interval),GRPC=endpoint,GRPCUseTLS=grpcUseTls,Timeout=TimeSpan.FromSeconds(timeout)});PassportConsole.Success($"[Consul]AddGRPCHealthCheckSuccess!Endpoint:{endpoint}");returnthis;}publicasyncTaskRegisterService(stringname,stringhost,intport,string[]tags){varregistration=newAgentServiceRegistration(){Checks=_checks.ToArray(),ID=$"{name}_{host}:{port}",Name=name,Address=host,Port=port,Tags=tags};await_client.Agent.ServiceRegister(registration);PassportConsole.Success($"[Consul]RegisterServiceSuccess!Name:{name}ID:{registration.ID}");AppDomain.CurrentDomain.ProcessExit+=async(sender,e)=>{PassportConsole.Information($"[Consul]ServiceDeregisting....ID:{registration.ID}");await_client.Agent.ServiceDeregister(registration.ID);};}///<summary>///移除服务///</summary>///<paramname="serviceId"></param>publicasyncTaskDeregister(stringserviceId){await_client?.Agent?.ServiceDeregister(serviceId);}}

逻辑简单,确定自己需要用的是注册服务功能,调Consul Api 注册,然后程序退出的时候注销consul的服务就行;

core WebApi 自动注册路由规则到kong

通过Consul

安装nuget包

#已安装跳过Install-PackagePassport.Infrastructure-Version0.1.4.7-preview-1

**加入配置appsettings.json**

guid顺便去/ 生成一个

"Kong":{//"Disable":false,//true=禁用"Host":"http://172.16.1.30:8001","Services":[{"Id":"72e21af8-283f-44c4-a766-53de8bb35c21",//guid"Name":"service-autoapi","Retries":5,"Protocol":"http","Host":"DemoApi31.service.consul","Port":0,"Path":null,"Connect_timeout":60000,//毫秒"Write_timeout":60000,"Read_timeout":60000,"Tags":null}],"Routes":[{"Id":"5370e1b7-6c43-442d-9a44-23c249f958f7","Name":"route-autoapi","Protocols":["http"],"Methods":null,"Hosts":null,"Paths":["/autoapi"],"Https_redirect_status_code":307,"Regex_priority":0,"Strip_path":true,"Preserve_host":false,"Tags":null,"Service":{"Id":"72e21af8-283f-44c4-a766-53de8bb35c21"//这个id跟关联的Services的id一致}}]}

StartUp.cs ConfigureServices方法

publicvoidConfigureServices(IServiceCollectionservices){......services.AddConsul();services.RouteRegistToKong();}

启动程序

dotnetDemoApi.Core3.1.dll--healthhost172.16.1.30--urlshttp://*:5003

验证

查看kong管理后台:

1622301181490

访问 http://172.16.1.30:8000/auto/api/values

1622301195836

大功告成。

不通过Consul,直接配置路由到kong

StartUp.cs ConfigureServices方法

publicvoidConfigureServices(IServiceCollectionservices){......//删掉这行services.AddConsul();services.RouteRegistToKong();}

配置变为

"Kong":{//"Disable":false,//true=禁用"Host":"http://172.16.1.30:8001","Services":[{"Id":"0f86015b-b170-4ada-b045-740ae7d77ed6",//guid"Name":"configupapi","Retries":5,"Protocol":"http","Host":"configupapi","Port":0,"Path":null,"Connect_timeout":60000,//毫秒"Write_timeout":60000,"Read_timeout":60000,"Tags":null}],"Routes":[{"Id":"1be79a57-af87-43b0-a0a0-b7a6cc0c5ade","Name":"configupapi","Protocols":["http"],"Methods":null,"Hosts":null,"Paths":["/configupapi"],"Https_redirect_status_code":307,"Regex_priority":0,"Strip_path":true,"Preserve_host":false,"Tags":null,"Service":{"Id":"0f86015b-b170-4ada-b045-740ae7d77ed6"//这个id跟Services的id一致}}],"Upstream":{"Id":"8efd15af-df78-422f-97a0-9072fa7e7431","Tags":["exampleapi","v1.0"],"Name":"configupapi","Hash_on":"none","Healthchecks":{"Active":{"Unhealthy":{"Http_statuses":[429,500,501,502,503,504,505],"Tcp_failures":1,"Timeouts":2,"Http_failures":1,"Interval":5},"Type":"http","Http_path":"/healthcheck","Timeout":1,"Healthy":{"Successes":1,"Interval":20,"Http_statuses":[200,302]},"Https_verify_certificate":true,"Concurrency":1},"Passive":{"Unhealthy":{"Http_statuses":[429,500,501,502,503,504,505]},"Healthy":{"Http_statuses":[200,201,302]},"Type":"http"}},"Hash_on_cookie_path":"/","Hash_fallback":"none","Slots":10000},"Target":{"Tags":["exampleapi","v1.0"],"Weight":100}}

源码解析

///<summary>///路由注册到kong;///</summary>///<paramname="services"></param>///<returns></returns>publicstaticIServiceCollectionRouteRegistToKong(thisIServiceCollectionservices){if(!PassportConfig.GetBool("Kong:Disable")){varkonghost=PassportConfig.Get("Kong:Host")??thrownewArgumentNullException("Kong:Hostcannotbenullorempty!");varoptions=newKongClientOptions(HttpClientFactory.Create(),konghost);varclient=newKongClient(options);services.AddSingleton<KongClient>(client);varupStream=PassportConfig.GetSection("Kong:Upstream").Get<UpStream>();vartarget=PassportConfig.GetSection("Kong:Target").Get<TargetInfo>();if(upStream!=null&&target!=null){upStream.Created_at=DateTime.Now;upStream=client.UpStream.UpdateOrCreate(upStream).Result;target.Target=$"{PassportConfig.GetHealthHost()}:{PassportConfig.GetCurrentPort()}";target.Id=PassportTools.GuidFromString($"{Dns.GetHostName()}{target.Target}");target.Created_at=DateTime.Now;target.UpStream=newTargetInfo.UpStreamId{Id=upStream.Id.Value};client.Target.Add(target).Wait();PassportConsole.Success($"[Kong]UpStreamregistered:{upStream.Name}Target:{target.Target}");//app.UseKongHealthChecks(upStream,onExecuter);}varkongServices=PassportConfig.GetSection("Kong:Services").Get<ServiceInfo[]>();varkongRoutes=PassportConfig.GetSection("Kong:Routes").Get<RouteInfo[]>();if(kongServices?.Length>0==true){foreach(variteminkongServices){item.Updated_at=DateTime.Now;item.Path=string.IsNullOrWhiteSpace(item.Path)?null:item.Path;client.Service.UpdateOrCreate(item).Wait();PassportConsole.Success($"[Kong]Serviceregistered:{item.Name}");}}if(kongRoutes?.Length>0==true){foreach(variteminkongRoutes){item.Updated_at=DateTime.Now;client.Route.UpdateOrCreate(item).Wait();PassportConsole.Success($"[Kong]Routeregistered:{item.Name}");}}}returnservices;}

逻辑也简单,也是调用kong配置把本该手工配置的路由,分别调用upstream、service、route Api修改配置。有区别的是程序退出时不会去删对应的路由;

总结

我在各技术博客都没有看到总结的比较好的kong+consul+ core的集成文章,特此总结。期待您的点赞留意;

[参考]

/

/stulzq/p/11942691.html

/lianggx/

https://www.consul.io/docs

文章博客园地址请点击“阅读原文”

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。