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

posted @ 2020-08-02 18:08  木~木  阅读(1738)  评论(6编辑  收藏  举报