序言
准備寫這一個系列也挺久了,但一直未動手,一方面自身積累不足,另一方面也不知從何處下手。直到最近稍微得空一些,另一方面也有一些新的體驗。
在此純粹作為自己個人的一個回顧記錄吧。正所謂好記性不如爛筆頭么。
總覽
目前規划的整個微服務體系分為三層。
最外面一層就是Ocelot,負責路由轉發,統一認證、限流熔斷等。
然后第二層是各個應用服務,也可以說是聚合服務,webapi形式對外提供接口能力,支撐PC、H5、APP等。
最后面一層就是基於領域驅動划分的各個小的服務,grpc形式互相調用。
但是目前來說其實只做到第一層、第二層。有項目工期很緊的原因,但最主要還是業務場景不夠熟悉。這一次才體會到拋開業務場景,談微服務的話,有點兒耍流氓。
尤其在做微服務拆分的時候相當痛苦,沒有領域專家參與,拆分過程相當痛苦,后來只能做更多的妥協。后續再專門開一篇講一講,回歸正題了。
准備工作
我使用的是Ocelot最新版本,園子里也有關於Ocelot集成K8s的分享,但是最新的Ocelot版本,在集成k8s的過程中,還是存在一些問題的。
下面簡單講述一下具體的操作步驟了。
(1)根據Oclelot版本,引入對應的K8s Provider。我這里因為用的是最新版本的Ocelot,所以直接選用最新版的K8s Provider。
(2)在StartUp類的ConfigureService方法中添加以下代碼:
services.AddOcelot() .AddPolly() .AddKubernetes();
(3)配置文件中,配置k8s支持。在最新版中,已經不需要配置Host、Port、Token信息。只需配置好k8s服務對應的命名空間即可。
{ "ReRoutes": [ { "DownstreamPathTemplate": "/api/values", "DownstreamScheme": "http", "UpstreamPathTemplate": "/values", "ServiceName": "testapiservice", "UpstreamHttpMethod": [ "Get" ] } ], "GlobalConfiguration": { "ServiceDiscoveryProvider": { "Namespace": "dev", "Type": "kube" } }
(4)ocelot中通過k8s服務名轉發,具體的實現機制就是通過KubeClient這個K8s的C#語言客戶端。具體信息在張隊的博客中已經有介紹。因為我們的ocelot網關最終也是運行在pod中的,
在pod中通過api訪問集群服務,是需要經過k8s內部認證的。我們可以通過給serviceaccount進行授權,來解決認證問題。關於k8s中的serviceaccount概念就不多展開了。
在k8s集群節點中執行以下命令:
kubectl create clusterrolebinding permissive-binding –clusterrole=cluster-admin –user=admin –user=kubelet –group=system:serviceaccounts
至此,本來可以開開心心的部署服務,愉快的進行路由轉發了。嗯,等會兒,Unable to find service discovery provider for type: kube。嗯哼,這是個什么鬼,心態爆炸有木有!!!
解決辦法
一開始,我以為是配置問題,然后又覺着是k8s的問題。一通嘗試無果,后來,通過在ocelot的issues中尋找到解決方案。原來這是ocelot最新版本的bug,通過以下擴展代碼可修復。
官方也注意到這個問題,應該也會在后續的版本更新中修復掉。
public static class OcelotBuilderExtensions { private static readonly ServiceDiscoveryFinderDelegate FixedKubernetesProviderFactoryGet = (provider, config, reroute) => { var serviceDiscoveryProvider = KubernetesProviderFactory.Get(provider, config, reroute); if (serviceDiscoveryProvider is KubernetesServiceDiscoveryProvider) { serviceDiscoveryProvider = new Kube(serviceDiscoveryProvider); } else if (serviceDiscoveryProvider is PollKubernetes) { serviceDiscoveryProvider = new PollKube(serviceDiscoveryProvider); } return serviceDiscoveryProvider; }; public static IOcelotBuilder AddKubernetesFixed(this IOcelotBuilder builder, bool usePodServiceAccount = true) { builder.Services.AddSingleton(FixedKubernetesProviderFactoryGet); builder.Services.AddKubeClient(usePodServiceAccount); return builder; } private class Kube : IServiceDiscoveryProvider { private readonly IServiceDiscoveryProvider serviceDiscoveryProvider; public Kube(IServiceDiscoveryProvider serviceDiscoveryProvider) { this.serviceDiscoveryProvider = serviceDiscoveryProvider; } public Task<List<Service>> Get() { return this.serviceDiscoveryProvider.Get(); } } private class PollKube : IServiceDiscoveryProvider { private readonly IServiceDiscoveryProvider serviceDiscoveryProvider; public PollKube(IServiceDiscoveryProvider serviceDiscoveryProvider) { this.serviceDiscoveryProvider = serviceDiscoveryProvider; } public Task<List<Service>> Get() { return this.serviceDiscoveryProvider.Get(); } } }
添加此擴展代碼后,在我們上述步驟中的:AddKubernetes() 需替換成AddKubernetesFixed()
至此,終於可以在k8s中愉快的使用ocelot了。
尾聲
ocelot第一階段的工作可以說是完成了。但在整個體系中,網關還需集成認證。認證我使用的是ids4,在請求到達網關時,直接在網關層進行認證,認證通過后再轉發到下游服務。
所以第二階段是需配置ocelot集成ids4.
然后因為我的所有服務都是通過apollo來進行配置的,而且打包成鏡像后,在通過修改json文件來修改配置也實在繁瑣。
所以第三階段就是ocelot使用apollo來進行配置管理。