Api网关Kong集成Consul做服务发现及在Asp.Net Core中的使用
1622219047536寫在前面
??Api網(wǎng)關(guān)我們之前是用 .netcore寫的 Ocelot的,使用后并沒有完全達到我們的預(yù)期,花了些時間了解后覺得kong可能是個更合適的選擇。
簡單說下kong對比ocelot打動我的:
1、kong可以直接代替Nginx/OpenRestry做前端服務(wù)器。
2、kong的功能強大,性能不俗,生態(tài)不錯,操作面板,插件豐富,社區(qū)活躍;
本文目的
1、對kong和consul做個基本介紹;
2、kong集成consul 做服務(wù)發(fā)現(xiàn);
3、Asp.net core WebApi 服務(wù)自動注冊到Consul;
4、Asp.net core WebApi 自動注冊路由規(guī)則到kong,實現(xiàn)程序啟動即部署;
運行環(huán)境
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 網(wǎng)關(guān)就是滿血版的 OpenRestry,它有許許多多的的插件和各種豐富的功能,且提供對應(yīng)的Rest Api,讓你輕松打造你所能想象到的 網(wǎng)關(guān)+ web前端服務(wù)器的功能;
特點(翻譯)
云原生:平臺無關(guān),kong支持任意平臺,裸機容器或云平臺;
k8s原生:原生支持k8s,有kong-ingress,支持l4+l7協(xié)議;
動態(tài)負(fù)載均衡:負(fù)載均衡到多個upstream;
Hash-based的負(fù)載均衡:根據(jù)cookie、session,ip等hash負(fù)載均衡;
斷路器:自動剔除不健康的服務(wù);
心跳檢測:主動和被動心跳檢測;
服務(wù)發(fā)現(xiàn):通過第三方dns解析做服務(wù)發(fā)現(xiàn),如consul;
Serverless:調(diào)用和保護 AWS Lambda or OpenWhisk functions directly ;
WebSockets:支持ws、wss協(xié)議;
gRPC:支持gRPC協(xié)議,并通過日志和插件監(jiān)控流量;
OAuth2.0:輕松添加OAuth2.0支持;
日志:輕松記錄請求和響應(yīng),通過HTTP, TCP, UDP, 或 直接到硬盤;
安全性:訪問控制,爬蟲檢測、ip黑白名單等等;
Syslog:記錄到系統(tǒng)日志;
SSL: 安裝不同的SSL證書到服務(wù);
監(jiān)控:實時監(jiān)控,提供關(guān)機負(fù)責(zé)負(fù)載均衡和性能指標(biāo);
整箱代理:kong可以作為正向代理服務(wù)器;
身份認(rèn)證:HMAC, JWT, Basic, 各種奇奇怪怪的規(guī)則都支持.
限制器:流量限制功能;
傳輸轉(zhuǎn)換:新增、刪掉、或者修改你的請求或者響應(yīng);
緩存:請求緩存;
CLI:命令行控制支持;
Rest Api:Rest Api控制支持;
Geo-Replicated:夸時區(qū)請求支持;
故障檢測與恢復(fù):數(shù)據(jù)庫(Cassandra /postgres)節(jié)點掛掉不影響kong的服務(wù);
集群:所有kong節(jié)點都自動加入集群保持配置同步;
拓展性:分布式拓展原生支持,水平伸縮加減節(jié)點就行;
高性能:使用Nginx作為核心負(fù)載均衡組件,高性能可伸縮;
插件:高拓展性,插件式添加功能;
詳細(xì)請看
github:https://github.com/Kong/kong
官方文檔:https://docs.konghq.com
kong的安裝
拉取鏡像
docker?pull?kong/kong-gateway:2.3.3.2-alpine給鏡像改個名
docker?tag?<IMAGE_ID>?kong-ee創(chuàng)建一個網(wǎng)絡(luò)
docker?network?create?kong-ee-net運行一個postgresSql 9.6,用來存取kong的配置
docker?run?-d?--name?kong-ee-database?\--network=kong-ee-net?\-p?5432:5432?\-e?"POSTGRES_USER=kong"?\-e?"POSTGRES_DB=kong"?\-e?"POSTGRES_PASSWORD=kong"?\postgres:9.6啟動kong
??docker?run?-d?--name?kong-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的才配-p?8000:8000?\-p?8443:8443?\-p?8001:8001?\-p?8444:8444?\-p?8002:8002?\-p?8445:8445?\-p?8003:8003?\-p?8004:8004?\kong-ee//-e?"KONG_DNS_RESOLVER=172.16.1.30:8600"?注意這個配置,這是我需要用的consul的dns配置,如果不想用consul做服務(wù)發(fā)現(xiàn),刪掉這行這里說明一下,kong的配置是用postgres(或者Cassandra )來存配置,但每一次請求都不需要去讀取數(shù)據(jù)庫的。修改的配置會直接 reload 到內(nèi)存中,不影響性能;
另外說說kong的集群;
因為kong 網(wǎng)關(guān)其實最終 表現(xiàn)為一個超級前端服務(wù)器+網(wǎng)關(guān),所以每個連接到同個數(shù)據(jù)庫的kong實例配置一樣,連接同個數(shù)據(jù)庫的kong作為一個集群;
一般在kong的前面是直接做dns解析就行,如果dns不支持多ip的話做keepalive + vip就行;
驗證
#admin?api?獲取所有服務(wù) curl?-i?-X?GET?--url?http://127.0.0.1:8001/services#admin?管理后臺? curl?-i?-X?GET?--url?http://127.0.0.1:8002 16222925304541622292862508管理后臺
1622297057459consul
consul簡介
Consul Service Mesh with Paul Banks - Software Engineering Daily??Consul是HashiCorp公司推出的開源工具,用于實現(xiàn)分布式系統(tǒng)的服務(wù)發(fā)現(xiàn)與配置。與其他分布式服務(wù)注冊與發(fā)現(xiàn)的方案,比如 Airbnb的SmartStack等相比,Consul的方案更“一站式”,內(nèi)置了服務(wù)注冊與發(fā)現(xiàn)框 架、分布一致性協(xié)議實現(xiàn)、健康檢查、Key/Value存儲、多數(shù)據(jù)中心方案,不再需要依賴其他工具(比如ZooKeeper等),使用起來也較 為簡單。
其實就是做服務(wù)治理的。
github: https://github.com/hashicorp/consul
官方文檔: https://www.consul.io/
consul的安裝
直接docker安裝
*這是作為開發(fā)節(jié)點安裝
docker?run??-d?--name=dev-consul1?--network=host?-e?CONSUL_BIND_INTERFACE=eth0?consul:1.8安裝成功
1622295177798運行一個WebApi服務(wù)
先在服務(wù)運行一個Asp.net Core WebApi (就是是新建的一個包含),我的版本是3.1的,我給服務(wù)命名:DemoApi31,監(jiān)聽端口5002
1622294659671將服務(wù)注冊到Consul
curl?--location?--request?PUT?'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} }'注冊成功:
1622295901281Dns解析驗證
#?如果沒安裝dig 安裝:yum install bind-utils dig?@172.16.1.30?-p?8600?Demoapi31.service.consul?SRV 1622294451840ok,我們這里已經(jīng)把服務(wù)注冊到consul,且能通過dns常解析到了,我們做跟kong的集成吧。
consul提供內(nèi)置Dns解析和Rest Api 兩種方式集成做服務(wù)發(fā)現(xiàn),我們這里跟kong的集成選用的Dns方式。
kong集成consul做服務(wù)發(fā)現(xiàn)
因為consul的角色是dns服務(wù)器,所以非常簡單,我們已注冊好的 DemoApi31為例:
1、創(chuàng)建一個名為consul的服務(wù)
DemoApi31.service.consul 是consu要求的格式
16222972545632、創(chuàng)建一個名為consul的路由
1622297366317驗證
訪問我們配置的kong路由:http://172.16.1.30:8000/consul/api/values
1622297455784ok
到目前為止我們只完成了本文目的1、2
3,和4三請往下看;
在Asp.net Core中的使用
??以之前的DemoApi31為例,換成5003端口,我需要達到的效果是,程序啟動的時候就把服務(wù)注冊到Consul 做好心跳檢測,并同時部署到網(wǎng)關(guān)Kong,直接對外服務(wù)。
Asp.net Core 服務(wù)自動注冊到Consul
安裝nuget包
Install-Package?Passport.Infrastructure?-Version?0.1.4.7-preview-1加入配置appsettings.json
大家主要各服務(wù)器要改成自己的
??"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方法
public?void?ConfigureServices(IServiceCollection?services) {//第一行PassportConfig.InitPassportConfig(Configuration,?Environment);......services.AddHealthChecks();services.AddConsul(); }StartUp.cs ?Configure方法
app.UseHealthChecks("/healthcheck");啟動程序
dotnet?DemoApi.Core3.1.dll?--healthhost?172.16.1.30?--urls?http://*:5003? 16222995065671622299584100源碼解析
///?<summary> ///?加入consul做服務(wù)管理 ///?</summary> ///?<param?name="services"></param> ///?<returns></returns> public?static?IServiceCollection?AddConsul(this?IServiceCollection?services) {var?options?=?PassportConfig.GetSection("ServiceDiscovery").Get<ServiceDiscoveryOptions>();if?(options?.Disable?!=?true){var?healthHost?=?PassportConfig.GetHealthHost();if?(string.IsNullOrWhiteSpace(options?.ServiceName)?||?string.IsNullOrWhiteSpace(options?.Consul?.HttpEndPoint)){throw?new?ArgumentNullException("ServiceDiscovery.ServiceName/Consul.HttpEndpoint?cannot?be?null?or?empty!");}//實例化kongclientvar?consulClient?=?new?ConsulClient(x?=>?x.Address?=?new?Uri(options.Consul.HttpEndPoint));services.AddSingleton(consulClient);services.Configure(new?Action<ConsulOptions>(op?=>{op.HttpEndPoint?=?options.Consul.HttpEndPoint;op.Token?=?options.Consul.Token;op.TcpEndPoint?=?options.Consul.TcpEndPoint;}));var?checkOptions?=?options.Consul.HttpHeathCheck;var?checkUrl?=?$"http://{healthHost}:{PassportConfig.GetCurrentPort()}{checkOptions.Path}";new?ConsulBuilder(consulClient).AddHttpHealthCheck(checkUrl,?checkOptions.TimeOunt,?checkOptions.Interval).RegisterService(options.ServiceName,?healthHost,?PassportConfig.GetCurrentPort(),?options.Consul.Tags).Wait();}return?services; }ConsulBuilder.cs ?參考曉晨大佬
?public?class?ConsulBuilder{private?readonly?ConsulClient?_client;private?readonly?List<AgentServiceCheck>?_checks?=?new?List<AgentServiceCheck>();public?ConsulBuilder(ConsulClient?client){_client?=?client;}public?ConsulBuilder?AddHealthCheck(AgentServiceCheck?check){_checks.Add(check);return?this;}///?<summary>//////?</summary>///?<param?name="url"></param>///?<param?name="timeout">unit:?second</param>///?<param?name="interval">check?interval.?unit:?second</param>///?<returns></returns>public?ConsulBuilder?AddHttpHealthCheck(string?url,?int?timeout?=?10,?int?interval?=?10){_checks.Add(new?AgentServiceCheck(){DeregisterCriticalServiceAfter?=?TimeSpan.FromSeconds(timeout?*?3),Interval?=?TimeSpan.FromSeconds(interval),HTTP?=?url,Timeout?=?TimeSpan.FromSeconds(timeout)});PassportConsole.Success($"[Consul]Add?Http?Healthcheck?Success!?CheckUrl:{url}");return?this;}///?<summary>//////?</summary>///?<param?name="endpoint">GPRC?service?address.</param>///?<param?name="grpcUseTls"></param>///?<param?name="timeout">unit:?second</param>///?<param?name="interval">check?interval.?unit:?second</param>///?<returns></returns>public?ConsulBuilder?AddGRPCHealthCheck(string?endpoint,?bool?grpcUseTls?=?false,?int?timeout?=?10,?int?interval?=?10){_checks.Add(new?AgentServiceCheck(){DeregisterCriticalServiceAfter?=?TimeSpan.FromSeconds(20),Interval?=?TimeSpan.FromSeconds(interval),GRPC?=?endpoint,GRPCUseTLS?=?grpcUseTls,Timeout?=?TimeSpan.FromSeconds(timeout)});PassportConsole.Success($"[Consul]Add?GRPC?HealthCheck?Success!?Endpoint:{endpoint}");return?this;}public?async?Task?RegisterService(string?name,?string?host,?int?port,?string[]?tags){var?registration?=?new?AgentServiceRegistration(){Checks?=?_checks.ToArray(),ID?=?$"{name}_{host}:{port}",Name?=?name,Address?=?host,Port?=?port,Tags?=?tags};await?_client.Agent.ServiceRegister(registration);PassportConsole.Success($"[Consul]Register?Service?Success!?Name:{name}?ID:{registration.ID}");AppDomain.CurrentDomain.ProcessExit?+=?async?(sender,?e)?=>{PassportConsole.Information($"[Consul]?Service?Deregisting?....??ID:{registration.ID}");await?_client.Agent.ServiceDeregister(registration.ID);};}///?<summary>///?移除服務(wù)///?</summary>///?<param?name="serviceId"></param>public?async?Task?Deregister(string?serviceId){await?_client?.Agent?.ServiceDeregister(serviceId);}}邏輯簡單,確定自己需要用的是注冊服務(wù)功能,調(diào)Consul Api 注冊,然后程序退出的時候注銷consul的服務(wù)就行;
Asp.net core WebApi 自動注冊路由規(guī)則到kong
通過Consul
安裝nuget包
#已安裝跳過 Install-Package?Passport.Infrastructure?-Version?0.1.4.7-preview-1**加入配置appsettings.json**
guid順便去https://www.guidgen.com/ 生成一個
"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跟關(guān)聯(lián)的Services的id一致}}]}StartUp.cs ?ConfigureServices方法
public?void?ConfigureServices(IServiceCollection?services) {......services.AddConsul();services.RouteRegistToKong(); }啟動程序
dotnet?DemoApi.Core3.1.dll?--healthhost?172.16.1.30?--urls?http://*:5003?驗證
查看kong管理后臺:
1622301181490訪問 http://172.16.1.30:8000/auto/api/values
1622301195836大功告成。
不通過Consul,直接配置路由到kong
StartUp.cs ?ConfigureServices方法
public?void?ConfigureServices(IServiceCollection?services) {......//刪掉這行services.AddConsul();services.RouteRegistToKong(); }配置變?yōu)?/strong>
"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> ///?<param?name="services"></param> ///?<returns></returns> public?static?IServiceCollection?RouteRegistToKong(this?IServiceCollection?services) {if?(!PassportConfig.GetBool("Kong:Disable")){var?konghost?=?PassportConfig.Get("Kong:Host")????throw?new?ArgumentNullException("Kong:Host?cannot?be?null?or?empty!");var?options?=?new?KongClientOptions(HttpClientFactory.Create(),?konghost);var?client?=?new?KongClient(options);services.AddSingleton<KongClient>(client);var?upStream?=?PassportConfig.GetSection("Kong:Upstream").Get<UpStream>();var?target?=?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?=?new?TargetInfo.UpStreamId?{?Id?=?upStream.Id.Value?};client.Target.Add(target).Wait();PassportConsole.Success($"[Kong]UpStream?registered:{upStream.Name}?Target:{target.Target}");//?app.UseKongHealthChecks(upStream,?onExecuter);}var?kongServices?=?PassportConfig.GetSection("Kong:Services").Get<ServiceInfo[]>();var?kongRoutes?=?PassportConfig.GetSection("Kong:Routes").Get<RouteInfo[]>();if?(kongServices?.Length?>?0?==?true){foreach?(var?item?in?kongServices){item.Updated_at?=?DateTime.Now;item.Path?=?string.IsNullOrWhiteSpace(item.Path)???null?:?item.Path;client.Service.UpdateOrCreate(item).Wait();PassportConsole.Success($"[Kong]Service?registered:{item.Name}");}}if?(kongRoutes?.Length?>?0?==?true){foreach?(var?item?in?kongRoutes){item.Updated_at?=?DateTime.Now;client.Route.UpdateOrCreate(item).Wait();PassportConsole.Success($"[Kong]Route?registered:{item.Name}");}}}return?services; }??邏輯也簡單,也是調(diào)用kong配置把本該手工配置的路由,分別調(diào)用upstream、service、route Api修改配置。有區(qū)別的是程序退出時不會去刪對應(yīng)的路由;
總結(jié)
??我在各技術(shù)博客都沒有看到總結(jié)的比較好的kong+consul+asp.net core的集成文章,特此總結(jié)。期待您的點贊留意;
[參考]
https://docs.konghq.com/
https://www.cnblogs.com/stulzq/p/11942691.html
https://github.com/lianggx/Kong.Net
https://www.consul.io/docs
文章博客園地址請點擊“閱讀原文”
總結(jié)
以上是生活随笔為你收集整理的Api网关Kong集成Consul做服务发现及在Asp.Net Core中的使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 看过这么多爆文,依旧走不好异步编程这条路
- 下一篇: ML.NET Cookbook:(10)