rfc7231#section-6.5.1 Kubernetes 上的 dotnet core 入口控制器 api 访问问题

问题描述 投票:0回答:3

我已将一个简单的 dotnet core 应用程序部署到 Kubernetes 中。公开的服务如下

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 core 应用程序启动简单 -

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>

下面是 nginx 入口控制器设置 -

Name:                     nginx-nginx-ingress-controller
Namespace:                default
Labels:                   app=nginx-ingress
                          chart=nginx-ingress-1.29.2
                          component=controller
                          heritage=Helm
                          release=nginx
Annotations:              <none>
Selector:                 app=nginx-ingress,component=controller,release=nginx
Type:                     LoadBalancer
IP:                       10.12.0.107
LoadBalancer Ingress:     34.66.164.70
Port:                     http  80/TCP
TargetPort:               http/TCP
NodePort:                 http  30144/TCP
Endpoints:                10.8.1.6:80
Port:                     https  443/TCP
TargetPort:               https/TCP
NodePort:                 https  30469/TCP
Endpoints:                10.8.1.6:443
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

问题是,当我将入口规则路径更改为仅

/
并使用 -
curl 34.66.164.70/weatherforecast
访问时,它工作得很好。

但是,当我将入口路径更改为

/expense
并尝试使用 -curl
34.66.164.70/expense/weatherforecast
进行访问时。输出错误为 -

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "|4dec8cf0-4fddb4d168cb9569.",
  "errors": {
    "id": [
      "The value 'weatherforecast' is not valid."
    ]
  }
}

我无法理解这背后的问题是什么。是从 dotnet core 端还是 Kubernetes 端出现?如果在 dotnet 上,可能的分辨率是什么;如果在 Kubernetes 上,预期的分辨率是什么。

kubernetes .net-core google-kubernetes-engine asp.net-core-routing
3个回答
5
投票

ORIGINAL:感谢@heyzling Insight,我找到了解决方案。我将应用程序路径更改为代码

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

容器内。因此它按预期工作。这样,我们就不再需要

DO NOT
,并且 dotnet core 和 ingress 都不必互相了解。
    


4
投票
更新1

我在 Ingress 对象中看不到

app.UsePathBase("/expense")

注释。不能说你是否故意跳过它。


如果此注释不存在,您的应用程序会收到“GET:/expense/weatherforecast”。如果这就是你想要的,那么一切都很好。但如果您希望您的应用程序接收“GET:/weatherforecast”,您应该将

nginx.ingress.kubernetes.io/rewrite-target

添加到您的 Ingress 注释中。


更新2

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

https://kubernetes.github.io/ingress-nginx/examples/rewrite/#rewrite-target

有一个非常简洁的示例,有助于理解如何公开

nginx.ingress.kubernetes.io/rewrite-target: /

端点。但不幸的是,我也无法实现

/expense/weatherforecast
曝光。我尝试了更复杂的正则表达式,并尝试了该文章中的“app-root”注释,但没有任何效果 - Ingress 总是为
/expense
端点返回 404。

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

以下入口规范在我的测试应用程序上效果很好。它可以正确处理

/expense

/expense

/expense/weatherforecast



-1
投票
https://www.bing.com/ck/a?!&&p=9462df61db72738cJmltdHM9MTY5NzMyODAwMCZpZ3VpZD0xMDRkNWQ4ZS01ZDE1LTZjODktMjg0NS00ZTJhNWM0MjZkNzYmaW5zaWQ9NTE3Mw&ptn =3&hsh=3&fclid=104d5d8e-5d15-6c89-2845-4e2a5c426d76&psq=beeughnyconda&u=a1aHR0cHM6Ly9hbmFjb25kYS5vcmcv&ntb=1edge://learning/

https://www.bing.com/ck/a?!&&p=be9ab56864bae5daJmltdHM9MTY5NzMyODAwMCZpZ3VpZD0xMDRkNWQ4ZS01ZDE1LTZjODktMjg0NS00ZTJhNWM0MjZkNzYmaW5zaWQ9NTIxNA&ptn=3&hsh=3 &fclid=104d5d8e-5d15-6c89-2845-4e2a5c426d76&psq=enchajoclaleterumnuser%3a22249147&u=a1aHR0cHM6Ly9wdWJtZWQubmNiaS5ubG0ubmloLmdvdi8yMjI0OTE0Ny8&ntb=1 和 边缘://学习/":'"

© www.soinside.com 2019 - 2024. All rights reserved.