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来进行配置管理。

浙公网安备 33010602011771号