rfc7231#关于Kubernetes上的dotnet core入口控制器api访问的第6.5.1节问题

rfc7231#关于Kubernetes上的dotnet core入口控制器api访问的第6.5.1节问题,kubernetes,.net-core,google-kubernetes-engine,asp.net-core-routing,Kubernetes,.net Core,Google Kubernetes Engine,Asp.net Core Routing,我在Kubernetes中部署了一个简单的dotnet核心应用程序。公开的服务如下所示 apiVersion: v1 kind: Service metadata: creationTimestamp: "2020-01-17T18:07:23Z" labels: app.kubernetes.io/instance: expo-api app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: expo-

我在Kubernetes中部署了一个简单的dotnet核心应用程序。公开的服务如下所示

apiVersion: v1
kind: Service
metadata:
  creationTimestamp: "2020-01-17T18:07:23Z"
  labels:
    app.kubernetes.io/instance: expo-api
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: expo-api
    app.kubernetes.io/version: 0.0.4
    helm.sh/chart: expo-api-0.0.4
  name: expo-api-service
  namespace: default
  resourceVersion: "997971"
  selfLink: /api/v1/namespaces/default/services/expo-api-service
  uid: 144b9d1d-87d2-4096-9851-9563266b2099
spec:
  clusterIP: 10.12.0.122
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: http
  selector:
    app.kubernetes.io/instance: expo-api
    app.kubernetes.io/name: expo-api
  sessionAffinity: None
  type: ClusterIP
status:
  loadBalancer: {}
我使用的入口控制器是nginx入口控制器,简单入口规则设置如下-

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/use-regex: "true"
  creationTimestamp: "2020-01-17T18:07:24Z"
  generation: 3
  labels:
    app.kubernetes.io/instance: expo-api
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: expo-api
    app.kubernetes.io/version: 0.0.4
    helm.sh/chart: expo-api-0.0.4
  name: expo-api
  namespace: default
  resourceVersion: "1004650"
  selfLink: /apis/extensions/v1beta1/namespaces/default/ingresses/expo-api
  uid: efef4e15-ed0a-417f-8b34-4e0f46cb1e70
spec:
  rules:
  - http:
      paths:
      - backend:
          serviceName: expo-api-service
          servicePort: 80
        path: /expense
status:
  loadBalancer:
    ingress:
    - ip: 34.70.45.62
dotnet核心应用程序具有简单的启动功能-

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseHttpsRedirection();
            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
这是入口输出-

Name:             expo-api
Namespace:        default
Address:          34.70.45.62
Default backend:  default-http-backend:80 (10.8.0.9:8080)
Rules:
  Host  Path  Backends
  ----  ----  --------
  *     
        /expense   expo-api-service:80 (10.8.0.26:80,10.8.0.27:80,10.8.1.14:80)
Annotations:
  kubernetes.io/ingress.class:            nginx
  nginx.ingress.kubernetes.io/use-regex:  true
Events:                                   <none>

我无法理解这背后的问题是什么。它是从dotnet核心端还是从Kubernetes端出现的?如果是dotnet,可能的解决方案是什么;如果是Kubernetes,预期的解决方案是什么

更新1

我看不到ingress对象中的
nginx.ingres.kubernetes.io/rewrite target
注释。不能说你是不是故意跳过了

如果此注释不存在,则您的应用程序将收到“GET:/expense/weatherforecast”。如果这是你想要的,一切都好。但如果你想让你的应用程序收到“GET:/weatherforecast”,你应该在ingress注释中添加
nginx.ingres.kubernetes.io/rewrite-target://

更新2

Ingress nginx文档中有一篇关于“重写”注释的文章:

这里有一个非常简洁的示例,有助于理解如何公开
/expense/weatherforecast
端点。但不幸的是,我也无法实现公开。我尝试了更复杂的正则表达式,并尝试了那篇文章中的“app root”注释,但没有任何效果-对于
/expense
endpoinnt,Ingress总是返回404

我找不到任何关于如何处理根端点和相对端点的有用信息,所以我开始即兴创作。我发现可以使用两个备份路径使其工作。不知道这是一个bug还是一个功能:)

以下入口规范在我的测试应用程序上非常有效。它可以正确处理
/expense
/expense/weatherforecast

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: "nginx"
    # nginx.ingress.kubernetes.io/use-regex: "true" # can be true or false, no matter
    nginx.ingress.kubernetes.io/rewrite-target: "/$1"
  name: app
spec:
  rules:
  - http:
      paths:
      - backend:
          serviceName: app
          servicePort: 80
        path: "/expense/(.+)" # handle relative path
      - backend: 
          serviceName: app
          servicePort: 80
        path: "/expense" # handle root

更新1

我看不到ingress对象中的
nginx.ingres.kubernetes.io/rewrite target
注释。不能说你是不是故意跳过了

如果此注释不存在,则您的应用程序将收到“GET:/expense/weatherforecast”。如果这是你想要的,一切都好。但如果你想让你的应用程序收到“GET:/weatherforecast”,你应该在ingress注释中添加
nginx.ingres.kubernetes.io/rewrite-target://

更新2

Ingress nginx文档中有一篇关于“重写”注释的文章:

这里有一个非常简洁的示例,有助于理解如何公开
/expense/weatherforecast
端点。但不幸的是,我也无法实现公开。我尝试了更复杂的正则表达式,并尝试了那篇文章中的“app root”注释,但没有任何效果-对于
/expense
endpoinnt,Ingress总是返回404

我找不到任何关于如何处理根端点和相对端点的有用信息,所以我开始即兴创作。我发现可以使用两个备份路径使其工作。不知道这是一个bug还是一个功能:)

以下入口规范在我的测试应用程序上非常有效。它可以正确处理
/expense
/expense/weatherforecast

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: "nginx"
    # nginx.ingress.kubernetes.io/use-regex: "true" # can be true or false, no matter
    nginx.ingress.kubernetes.io/rewrite-target: "/$1"
  name: app
spec:
  rules:
  - http:
      paths:
      - backend:
          serviceName: app
          servicePort: 80
        path: "/expense/(.+)" # handle relative path
      - backend: 
          serviceName: app
          servicePort: 80
        path: "/expense" # handle root

原创:感谢@heyzling insight,我找到了解决方案。我将应用程序路径更改为code
startup.cs
。问题是Api最初不希望所有控制器都有路由前缀。因此,它给出了错误。因此,我不得不在
startup.cs
中做一些细微的更改,以添加
app.UsePathBase(“/expense”)
。以下是我添加的配置-

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UsePathBase("/expense"); // this is the added configuration which identifies the ingress path rule individually. 
            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
理想情况下,我觉得这不是一个好的设计,因为kubernetes入口和dotnet核心路由应该互不了解。理想情况下,它们不应相互依赖以遵守路由规则。如果有人有更好的解决方案?请不要邮寄。上面的一个解决了我的目的,但我不满意

----------------------------------------------------------------------------------
更新2:感谢@heyzling。我终于找到了解决办法- 看起来它必须重写url并将dotnet代码期望的实际API url转发给正在运行的docker映像

下面是代码示例-

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/use-regex: "true"
  labels:
    app.kubernetes.io/name: expo-api
  name: expo-api
  namespace: default
spec:
  rules:
  - http:
      paths:
      - backend:
          serviceName: expo-api-service
          servicePort: 80
          path: /expense(/|$)(.*)
所以现在你可以两者兼得了-

curl 35.192.198.231/expense/weatherforecast
curl 35.192.198.231/expense/fakeapi
它将重写并转发url,如下所示:

localhost:80/weatherforecast
localhost:80/fakeapi

在容器内。因此,它可以按预期工作。这样,我们就不再需要
app.UsePathBase(“/expense”)
,而dotnet core和ingress也不必相互了解

原创:多亏@heyzling insight,我找到了解决方案。我将应用程序路径更改为code
startup.cs
。问题是Api最初不希望所有控制器都有路由前缀。因此,它给出了错误。因此,我不得不在
startup.cs
中做一些细微的更改,以添加
app.UsePathBase(“/expense”)
。以下是我添加的配置-

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UsePathBase("/expense"); // this is the added configuration which identifies the ingress path rule individually. 
            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
理想情况下,我觉得这不是一个好的设计,因为kubernetes入口和dotnet核心路由应该互不了解。理想情况下,它们不应相互依赖以遵守路由规则。如果有人有更好的解决方案?请不要邮寄。上面的一个解决了我的目的,但我不满意

----------------------------------------------------------------------------------
更新2:感谢@heyzling。我终于找到了解决办法- 看起来它必须重写url并将dotnet代码期望的实际API url转发给正在运行的docker映像

下面是代码示例-

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/use-regex: "true"
  labels:
    app.kubernetes.io/name: expo-api
  name: expo-api
  namespace: default
spec:
  rules:
  - http:
      paths:
      - backend:
          serviceName: expo-api-service
          servicePort: 80
          path: /expense(/|$)(.*)
所以现在你可以两者兼得了-

curl 35.192.198.231/expense/weatherforecast
curl 35.192.198.231/expense/fakeapi
它将重写并转发url,如下所示:

localhost:80/weatherforecast
localhost:80/fakeapi
在容器内。因此,它可以按预期工作。这样,我们就不再需要
app.UsePathBase(“/expense”)
,而dotnet core和ingress也不必相互了解

那里