我已将一个简单的 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 上,预期的分辨率是什么。
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 都不必互相了解。 我在 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-targetnginx.ingress.kubernetes.io/rewrite-target: /
端点。但不幸的是,我也无法实现
/expense/weatherforecast
曝光。我尝试了更复杂的正则表达式,并尝试了该文章中的“app-root”注释,但没有任何效果 - Ingress 总是为 /expense
端点返回 404。我找不到任何关于如何处理根端点和相对端点的有用信息,所以我开始即兴发挥。我发现您可以使用两个备份路径来使其工作。不知道这是一个错误还是功能:)。
以下入口规范在我的测试应用程序上效果很好。它可以正确处理
/expense
和
/expense
。/expense/weatherforecast
和 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 和 边缘://学习/":'"