要在 Kubernetes 中配置 Nginx Ingress 以便转发到后端时去掉 contextPath,你可以通过以下步骤来实现:

单个 path 去掉 contextpath

假设你有一个服务在 /app 路径下运行,并希望通过 Ingress 直接访问后端服务的根路径 /,可以如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2

spec:
rules:
- host: example.com
http:
paths:
- path: /app(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: example-service
port:
number: 80

$2 是什么

假设一个请求路径是 /app1/foo/bar,根据路径匹配规则 /app1(/|$)(.*)

第一组 (/|$) 匹配的是 /
第二组 (.*) 匹配的是 foo/bar
因此,$2 将包含 foo/bar,重写后的目标路径为 /foo/bar

pathType: ImplementationSpecific: 允许路径匹配类型由具体的 Ingress 控制器实现决定。在 Nginx 中,这通常表示使用最长前缀匹配。

如果有多个 location 需要对其中一个 location 去除 contextpath

方法一: 使用多个 Ingress,配置同一个域名

个人比较推荐这种配置

ingress1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
name: ibr-portal
namespace: default
annotations:
kubernetes.io/ingress.class: apple-internet

spec:
tls:
- hosts:
- register.example.com
secretName: example-com
rules:
- host: register.example.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: ibr-wfe
port:
number: 80
- path: /job
pathType: ImplementationSpecific
backend:
service:
name: xxl-job
port:
number: 80

ingress2:
这个 ingress 是需要去除 contextpath 的路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
name: ibr
namespace: default
annotations:
kubernetes.io/ingress.class: apple-internet
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
tls:
- hosts:
- register.example.com
secretName: example-com
rules:
- host: register.example.com
http:
paths:
- path: /ibr(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: ibr
port:
number: 80

方法二:直接使用 Nginx 配置

这个用 ingress 好像实现不了了,需要用到原生的 Nginx 配置,增加一条 server-snippet 注解,记得全局 configmap 也需要开启 server-snippet 支持。这个方案有个缺点,如果我删除了 service 然后再创建个同名的 service,还是访问不了的,这个是 Nginx 的特性,nginx proxy_pass 如果配置了域名,那么 nginx 会将域名解析的 IP 缓存下来,不会更新的。除非你 reload 或 restart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
name: ibr-portal
namespace: default
annotations:
kubernetes.io/ingress.class: apple-internet
nginx.ingress.kubernetes.io/server-snippet: |
location /ibr {
proxy_pass http://ibr.default/;
}

spec:
tls:
- hosts:
- register.example.com
secretName: example-com
rules:
- host: register.example.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: ibr-wfe
port:
number: 80
- path: /job
pathType: ImplementationSpecific
backend:
service:
name: xxl-job
port:
number: 80