NetCore微服务系列---Ocelot接入K8S
序言
准备写这一个系列也挺久了,但一直未动手,一方面自身积累不足,另一方面也不知从何处下手。直到最近稍微得空一些,另一方面也有一些新的体验。
在此纯粹作为自己个人的一个回顾记录吧。正所谓好记性不如烂笔头么。
总览
目前规划的整个微服务体系分为三层。
最外面一层就是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来进行配置管理。