tnblog
首页
视频
资源
登录

.Net6 Ocelot 与 Kubernetes

8653人阅读 2022/5/20 21:27 总访问:3467319 评论:0 收藏:1 手机
分类: .net后台框架

.Net6 Ocelot 与 Kubernetes

前言


这玩意太坑人了。浪费了我一天的时间。
先看我们想实现的效果流程:


首先我们请求svc/ocelot的服务请求,转发到我们ocelot的Pod中,然后ocelot通过转发给svc/ocelotapi服务实现ocelotapi的负载均衡。

部署API项目


创建dev名称空间。

  1. kubectl create ns dev


我这儿容器里面就一个默认的天气接口,以及80服务,负载均衡2个。然后通过kubectl apply -f api.yml部署到k8s集群中。

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: ocelotapi
  5. namespace: dev
  6. labels:
  7. name: ocelotapi
  8. spec:
  9. replicas: 2
  10. selector:
  11. matchLabels:
  12. name: ocelotapi
  13. template:
  14. metadata:
  15. labels:
  16. name: ocelotapi
  17. spec:
  18. containers:
  19. - name: ocelotapi
  20. image: aidasi/ocelotapi:v1
  21. ports:
  22. - containerPort: 80
  23. imagePullPolicy: Always
  24. ---
  25. kind: Service
  26. apiVersion: v1
  27. metadata:
  28. name: ocelotapi
  29. namespace: dev
  30. spec:
  31. ports:
  32. - port: 80
  33. targetPort: 80
  34. selector:
  35. name: ocelotapi

创建K8sOcelot项目


创建一个环境为.net6的K8sOcelot API 项目,并添加相关依赖,添加Docker的支持。

  1. <ItemGroup>
  2. <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.15.1" />
  3. <PackageReference Include="Ocelot" Version="18.0.0" />
  4. <PackageReference Include="Ocelot.Provider.Kubernetes" Version="18.0.0" />
  5. <PackageReference Include="Ocelot.Provider.Polly" Version="18.0.0" />
  6. </ItemGroup>


接着创建我们的ocelot.json,当我们通过Get请求访问默认目录时,将会转发给ocelotapi服务的/weatherforecast接口。
注意服务发现类型这里选择kube,并且这里我设置的命名空间为dev,你也可以根据服务所在的命名空间来进行指定。

  1. {
  2. "Routes": [
  3. {
  4. "UpstreamPathTemplate": "/",
  5. "UpstreamHttpMethod": [ "Get" ],
  6. "DownstreamPathTemplate": "/weatherforecast",
  7. "DownstreamScheme": "http",
  8. "ServiceName": "ocelotapi"
  9. }
  10. ],
  11. "GlobalConfiguration": {
  12. "ServiceDiscoveryProvider": {
  13. "Namespace": "dev",
  14. "Type": "kube"
  15. }
  16. }
  17. }


按照官方的说法,按照以下的代码就可以在Kubernetes中跑了;其实不行。

  1. using K8sOcelot;
  2. using Ocelot.DependencyInjection;
  3. using Ocelot.Middleware;
  4. using Ocelot.Provider.Kubernetes;
  5. var builder = WebApplication
  6. .CreateBuilder(args)
  7. ;
  8. builder.Configuration
  9. .SetBasePath(builder.Environment.ContentRootPath)
  10. .AddJsonFile("ocelot.json")
  11. .AddEnvironmentVariables();
  12. builder.Services
  13. .AddOcelot()
  14. .AddKubernetes();
  15. var app = builder.Build();
  16. app.UseOcelot().Wait();
  17. app.Run();


当我们通过这样的方式进行访问的时候,会抛异常,错误如下。

  1. no previous request id, message: Error Code: UnableToFindServiceDiscoveryProviderError Message: Unable to find service discovery provider for type: kube errors found in ResponderMiddleware. Setting error response for request path:/, request method: GET


原因是由于14版本之后作者做了重大的更新,导致这玩意的出现。你可以降级到14版本以下。
当然作者也提供了一个新的解决方式。添加一个新的类OcelotBuilderExtensions。并且在引用的时候,在Program中添加上AddKubernetesFixed

  1. public static class OcelotBuilderExtensions
  2. {
  3. private static readonly ServiceDiscoveryFinderDelegate FixedKubernetesProviderFactoryGet = (provider, config, reroute) =>
  4. {
  5. var serviceDiscoveryProvider = KubernetesProviderFactory.Get(provider, config, reroute);
  6. if (serviceDiscoveryProvider is KubernetesServiceDiscoveryProvider)
  7. {
  8. serviceDiscoveryProvider = new Kube(serviceDiscoveryProvider);
  9. }
  10. else if (serviceDiscoveryProvider is PollKubernetes)
  11. {
  12. serviceDiscoveryProvider = new PollKube(serviceDiscoveryProvider);
  13. }
  14. return serviceDiscoveryProvider;
  15. };
  16. public static IOcelotBuilder AddKubernetesFixed(this IOcelotBuilder builder, bool usePodServiceAccount = true)
  17. {
  18. builder.Services.AddSingleton(FixedKubernetesProviderFactoryGet);
  19. builder.Services.AddKubeClient(usePodServiceAccount);
  20. return builder;
  21. }
  22. private class Kube : IServiceDiscoveryProvider
  23. {
  24. private readonly IServiceDiscoveryProvider serviceDiscoveryProvider;
  25. public Kube(IServiceDiscoveryProvider serviceDiscoveryProvider)
  26. {
  27. this.serviceDiscoveryProvider = serviceDiscoveryProvider;
  28. }
  29. public Task<List<Service>> Get()
  30. {
  31. return this.serviceDiscoveryProvider.Get();
  32. }
  33. }
  34. private class PollKube : IServiceDiscoveryProvider
  35. {
  36. private readonly IServiceDiscoveryProvider serviceDiscoveryProvider;
  37. public PollKube(IServiceDiscoveryProvider serviceDiscoveryProvider)
  38. {
  39. this.serviceDiscoveryProvider = serviceDiscoveryProvider;
  40. }
  41. public Task<List<Service>> Get()
  42. {
  43. return this.serviceDiscoveryProvider.Get();
  44. }
  45. }
  46. }
  1. builder.Services
  2. .AddOcelot()
  3. .AddKubernetesFixed();


接着我们,将它Builder成容器,并在添加好RBAC 角色绑定后,通过ocelot.yml部署到集群中。
下面是相关命令:

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: ocelot
  5. namespace: dev
  6. labels:
  7. name: ocelot
  8. spec:
  9. replicas: 1
  10. selector:
  11. matchLabels:
  12. name: ocelot
  13. template:
  14. metadata:
  15. labels:
  16. name: ocelot
  17. spec:
  18. containers:
  19. - name: ocelot
  20. image: aidasi/ocelot:v1
  21. ports:
  22. - containerPort: 80
  23. imagePullPolicy: Always
  24. ---
  25. kind: Service
  26. apiVersion: v1
  27. metadata:
  28. name: ocelot
  29. namespace: dev
  30. spec:
  31. ports:
  32. - port: 80
  33. targetPort: 80
  34. selector:
  35. name: ocelot
  1. # 打包
  2. docker build -t aidasi/ocelot:v1 -f ../K8sOcelot/Dockerfile ..
  3. # 上传
  4. docker push aidasi/ocelot:v1
  5. # 绑定角色权限(一般不建议这样做,建议单独创建一个角色权限给它使用)
  6. kubectl create clusterrolebinding permissive-binding --clusterrole=cluster-admin --user=admin --user=kubelet --group=system:serviceaccounts


如果你对权限要求得比较严格的话,可以通过创建一个ServiceAccount并绑定cluster-admin的集群角色。例如:

  1. kind: ServiceAccount
  2. apiVersion: v1
  3. metadata:
  4. name: ocelot-pod
  5. namespace: 你的名称空间
  6. ---
  7. apiVersion: rbac.authorization.k8s.io/v1
  8. kind: RoleBinding
  9. metadata:
  10. name: pod-operator-role
  11. namespace: 你的名称空间
  12. roleRef:
  13. apiGroup: rbac.authorization.k8s.io
  14. kind: ClusterRole
  15. name: cluster-admin
  16. subjects:
  17. - kind: ServiceAccount
  18. name: ocelot-pod
  19. namespace: 你的名称空间
  1. # 创建该ServiceAccount
  2. kubectl apply -f .\OcelotRoleBind.yaml.yml


然后在pod中添加好serviceAccountName

  1. spec:
  2. template:
  3. serviceAccountName: ocelot-pod
  4. metadata:
  5. labels:
  6. name: ocelot
  7. spec:
  8. containers:
  1. # 部署
  2. kubectl apply -f .\ocelot.yml


部署完成后,你会看到我们相关的服务与Pod。


接下来我们通过kubectl port-forward --address 0.0.0.0 -n dev svc/ocelot 5190:80命令端口转发ocelot服务到本地,测试ocelot是否能正常转发到svc/ocelotapi服务。


我们可以看到有数据返回是没问题的。

配置https


生成证书

  1. mkdir -p ${HOME}/.aspnet/https/
  2. dotnet dev-certs https -ep ${HOME}/.aspnet/https/aspnetapp.pfx -p 123456
  3. chmod 777 /root/.aspnet/https/
  4. # 分配给子节点
  5. ssh node01
  6. mkdir -p ${HOME}/.aspnet/https/
  7. chmod 777 /root/.aspnet/https/
  8. scp /root/.aspnet/https/aspnetapp.pfx node01:/root/.aspnet/https/aspnetapp.pfx


配置api.ymlocelot.yml

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: ocelotapi
  5. namespace: dev
  6. labels:
  7. name: ocelotapi
  8. spec:
  9. replicas: 2
  10. selector:
  11. matchLabels:
  12. name: ocelotapi
  13. template:
  14. metadata:
  15. labels:
  16. name: ocelotapi
  17. spec:
  18. containers:
  19. - name: ocelotapi
  20. image: aidasi/ocelotapi:v1
  21. ports:
  22. - containerPort: 80
  23. imagePullPolicy: Always
  24. env:
  25. - name: ASPNETCORE_URLS
  26. value: "https://+:443;http://+:80"
  27. - name: ASPNETCORE_Kestrel__Certificates__Default__Path
  28. value: "/https/aspnetapp.pfx"
  29. - name: ASPNETCORE_Kestrel__Certificates__Default__Password
  30. value: "123456"
  31. volumeMounts:
  32. - mountPath: /https/
  33. name: httpsfile
  34. volumes:
  35. - name: httpsfile
  36. hostPath:
  37. path: /root/.aspnet/https/
  38. type: Directory
  39. ---
  40. kind: Service
  41. apiVersion: v1
  42. metadata:
  43. name: ocelotapi
  44. namespace: dev
  45. spec:
  46. ports:
  47. - port: 80
  48. targetPort: 80
  49. selector:
  50. name: ocelotapi
  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: ocelot
  5. namespace: dev
  6. labels:
  7. name: ocelot
  8. spec:
  9. replicas: 1
  10. selector:
  11. matchLabels:
  12. name: ocelot
  13. template:
  14. metadata:
  15. labels:
  16. name: ocelot
  17. spec:
  18. containers:
  19. - name: ocelot
  20. image: aidasi/ocelot:v1
  21. ports:
  22. - containerPort: 80
  23. imagePullPolicy: Always
  24. env:
  25. - name: ASPNETCORE_URLS
  26. value: "https://+:443;http://+:80"
  27. - name: ASPNETCORE_Kestrel__Certificates__Default__Path
  28. value: "/https/aspnetapp.pfx"
  29. - name: ASPNETCORE_Kestrel__Certificates__Default__Password
  30. value: "123456"
  31. volumeMounts:
  32. - mountPath: /https/
  33. name: httpsfile
  34. volumes:
  35. - name: httpsfile
  36. hostPath:
  37. path: /root/.aspnet/https/
  38. type: Directory
  39. ---
  40. kind: Service
  41. apiVersion: v1
  42. metadata:
  43. name: ocelot
  44. namespace: dev
  45. spec:
  46. ports:
  47. - port: 80
  48. targetPort: 80
  49. selector:
  50. name: ocelot


随后执行如下命令进行更新。

  1. kubectl apply -f api.yml
  2. kubectl apply -f ocelot.yml


测试没有问题。

注意不要加ASPNETCORE_ENVIRONMENT环境变量为Development。【【x3】】

Ingress配置


编写ocelotIngress.yamlIngress的配置,通过请求/testpath路径转发到ocelot中。
内容如下:

  1. apiVersion: networking.k8s.io/v1
  2. kind: Ingress
  3. metadata:
  4. name: ocelot-ingress
  5. namespace: dev
  6. annotations:
  7. nginx.ingress.kubernetes.io/rewrite-target: /
  8. spec:
  9. rules:
  10. - http:
  11. paths:
  12. - path: /testpath
  13. pathType: Prefix
  14. backend:
  15. service:
  16. name: ocelot
  17. port:
  18. number: 80


然后我们通过如下命令进行部署与查看创建情况。

  1. kubectl apply -f ocelotIngress.yaml
  2. kubectl describe ingress ocelot-ingress -n dev


我们发现它并没有生成Address,并且还报错了;是因为ingresses组件不能单独存在,依赖ingresses Controller组件。而创建ingresses Controller的过程,需要配置一个Default Backend。可以通过如下命令创建一个nginx ingress。

  1. kubectl apply -f https://gitee.com/idcf-devops-on-kubernetes/workshop-assets/raw/master/chapter2/assets/ingress-controller-mandatory.yaml
  2. https://gitee.com/idcf-devops-on-kubernetes/workshop-assets/raw/master/chapter2/assets/ingress-controller-cloud-generic.yaml


可以通过如下命令查看创建资源的情况。

  1. kubectl get pod,svc,deploy -n ingress-nginx


当你发现service/ingress-nginxEXTERNAL-IP一直处于Pending状态时,可以通过externalIPs手动配置主机和外网地址。

  1. kubectl edit service/ingress-nginx -n ingress-nginx
  2. ...
  3. spec:
  4. clusterIP: 10.96.81.230
  5. clusterIPs:
  6. - 10.96.81.230
  7. externalIPs:
  8. - 10.9.2.98
  9. ...


然后再次重新创建我们的ocelot就可以了。

  1. kubectl delete -f ocelotIngress.yaml
  2. kubectl create -f ocelotIngress.yaml


如果你遇到了service "ingress-nginx-controller-admission" not found问题。
这是由于你使用了比较新的ingress-nginx,在删除时没有删除掉validatingwebhookconfigurations里面的资源所造成的。
解决方式:

  1. kubectl get validatingwebhookconfigurations
  2. # 删除相关的 ingress-nginx-admission
  3. kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission


接下来我们来看配置信息,我们发现它还是报错<error: endpoints "default-http-backend" not found>的错,原因是因为我这里是内网,你们如果是腾讯云或者阿里云是不会有这个问题的。


所以我这里只好改成NodePoint的方式。创建ingress-controller-cloud-generic-node.yaml文件内容如下:

  1. kind: Service
  2. apiVersion: v1
  3. metadata:
  4. name: ingress-nginx
  5. namespace: ingress-nginx
  6. labels:
  7. app.kubernetes.io/name: ingress-nginx
  8. app.kubernetes.io/part-of: ingress-nginx
  9. spec:
  10. type: NodePort
  11. selector:
  12. app.kubernetes.io/name: ingress-nginx
  13. app.kubernetes.io/part-of: ingress-nginx
  14. ports:
  15. - name: http
  16. port: 80
  17. protocol: TCP
  18. targetPort: http
  19. nodePort: 30080
  20. - name: https
  21. port: 443
  22. protocol: TCP
  23. targetPort: https
  24. nodePort: 30443
  25. ---
  1. kubectl delete -f https://gitee.com/idcf-devops-on-kubernetes/workshop-assets/raw/master/chapter2/assets/ingress-controller-cloud-generic.yaml
  2. # 更新
  3. kubectl apply -f .\ingress-controller-cloud-generic-node.yaml


再次看到我们发现没有问题了。在外网通过nodeport进行访问,也是没有问题的。


欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739

评价

分布式服务架构微服务架构概念的区别联系

分布式:分散压力。微服务:分散能力。当下理解分布式:不同模块部署在不同服务器上作用:分布式解决网站高并发带来问题集...

jsController中分割字符串的方法

js: varstr=OpenRule; varstrs=newArray(); strs=str.split(&quot;,&quot;); for(vari=0;i&lt;strs.length;i++){ $(&q...

Service-stack.redis配置连接池读写分离(处理并发相关等)

配置连接池与读写分类 //写节点(主节点) List&lt;string&gt;writes=newList&lt;string&gt;(); writes.Add(&quot;123456a...

CSS相对定位绝对定位

一般相对定位和绝对定位可以配合起来使用 例如实现如下的效果 只需要在外层div设置为相对定位,在内部设置为绝对定位就...

C委托事件

1.什么是委托?  委托在C#里的意义和在现实里差不多,从字面意思理解即可。举个例子:领导委托小张去传递个文件,这就是...

asp.net core2.0 依赖注入 AddTransientAddScoped的区别

asp.net core主要提供了三种依赖注入的方式其中AddTransient与AddSingleton比较好区别AddTransient瞬时模式:每次都获取一...

Vue.js+Layer实现表格数据绑定更新

一:使用Vue.js绑定好数据与更新事件 使用v-on绑定好事件,在事件里边直接把该行数据传递进去,在更新方法里边就可以直接...

下划线、换行、回车、空格ASCII码值对照表

下划线,ASCII码95换行 , ASCII码10回车 , ASCII码13空格 , ASCII码32ASCII码表:Bin(二进制)Oct(八进制)Dec(十进制)Hex(...

数据读取器指定的"xx"不兼容。某个类型为"xx"的成员在同名的数据读取器中没有对应的列

报错的地方var result= _db.Database.SqlQuery&lt;SMachine&gt;(sql).FirstOrDefault();经过分析,是因为SqlQuery方法查询...

git 下载提交命令

一.先使用git clone下载一个项目 git clone &#39;项目地址&#39; 这里要注意: clone的项目里边会自带git的一些信息,...

微信开发四 接受用户普通消息回复消息

微信接收用户普通消息的文章可以在官方中直接看微信普通消息分类:接受用户文本消息 与 回复文本信息 注意在接收用户普通...

记忆糖的关系【阅读听力】

Link Between Memory and SugarSugar On The BrainIt’s long been understood that there is a connection between memory...

婚姻心脏健康的关系【阅读听力】

Marriage and Heart HealthPlenty of studies have found that being married is generally good for health. One study ze...

iframe自适应高度配合net core使用

去掉iframe边框frameborder=&quot;0&quot;去掉滚动条scrolling=&quot;no&quot;iframe 自适应高度如果内容是固定的,那么就...

net core中使用url编码解码操作

net core中暂时还没有以前asp.net与mvc中的server对象。获取url的编码与解码操作不能使用以前的server对象来获取。使用的是...
这一世以无限游戏为使命!
排名
2
文章
634
粉丝
44
评论
93
docker中Sware集群与service
尘叶心繁 : 想学呀!我教你呀
一个bug让程序员走上法庭 索赔金额达400亿日元
叼着奶瓶逛酒吧 : 所以说做程序员也要懂点法律知识
.net core 塑形资源
剑轩 : 收藏收藏
映射AutoMapper
剑轩 : 好是好,这个对效率影响大不大哇,效率高不高
ASP.NET Core 服务注册生命周期
剑轩 : http://www.tnblog.net/aojiancc2/article/details/167
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术