如何在Kubernetes Ingress Controller中正确配置Rewrite Target
NGINX Ingress重写规则不生效问题排查
环境与需求
我们有一个Blazor应用,对应两个域名:
domain.com:面向普通用户的前端,已配置完成,domain.com/auth提供用户UI,domain.com/auth/admin直接返回404admin.domain.com:管理面板前端,期望实现:访问https://admin.domain.com/auth/userlist时,后端实际收到的请求路径为/auth/admin/userlist,但当前配置的重写规则未生效
现有完整Ingress配置
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: {{ .Values.label.name }}-service-ingress annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: letsencrypt nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" nginx.ingress.kubernetes.io/client-max-body-size: "0" nginx.ingress.kubernetes.io/proxy-body-size: "0" nginx.ingress.kubernetes.io/proxy-connect-timeout: "3600" nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" nginx.ingress.kubernetes.io/configuration-snippet: | location ~* "^/auth/admin(/|$)(.*)" { return 404; } spec: tls: - hosts: - domain.com secretName: wildcard-domain-com-ingress rules: - host: domain.com http: paths: - path: /auth(/|$)(.*) pathType: Prefix backend: service: name: {{ .Values.label.name }}-service port: number: {{ .Values.service.port }} --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: {{ .Values.label.name }}-service-admin-ingress annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: letsencrypt nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" nginx.ingress.kubernetes.io/client-max-body-size: "0" nginx.ingress.kubernetes.io/proxy-body-size: "0" nginx.ingress.kubernetes.io/proxy-connect-timeout: "3600" nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" nginx.ingress.kubernetes.io/use-regex: "true" nginx.ingress.kubernetes.io/rewrite-target: /auth/admin/$1 spec: tls: - hosts: - admin.domain.com secretName: wildcard-domain-com-ingress rules: - host: admin.domain.com http: paths: - path: /auth/(.*) pathType: Prefix backend: service: name: {{ .Values.label.name }}-service port: number: {{ .Values.service.port }} --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: {{ .Values.label.name }}-service-admin-styles-ingress annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: letsencrypt nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" nginx.ingress.kubernetes.io/client-max-body-size: "0" nginx.ingress.kubernetes.io/proxy-body-size: "0" nginx.ingress.kubernetes.io/proxy-connect-timeout: "3600" nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" spec: tls: - hosts: - admin.domain.com secretName: wildcard-domain-com-ingress rules: - host: admin.domain.com http: paths: - path: /auth/icons(/|$)(.*) pathType: Prefix backend: service: name: {{ .Values.label.name }}-service port: number: {{ .Values.service.port }} - path: /auth/img(/|$)(.*) pathType: Prefix backend: service: name: {{ .Values.label.name }}-service port: number: {{ .Values.service.port }} - path: /auth/js(/|$)(.*) pathType: Prefix backend: service: name: {{ .Values.label.name }}-service port: number: {{ .Values.service.port }} - path: /auth/styles(/|$)(.*) pathType: Prefix backend: service: name: {{ .Values.label.name }}-service port: number: {{ .Values.service.port }} - path: /auth/favicon.ico pathType: Prefix backend: service: name: {{ .Values.label.name }}-service port: number: {{ .Values.service.port }} - path: /auth/_framework(/|$)(.*) pathType: Prefix backend: service: name: {{ .Values.label.name }}-service port: number: {{ .Values.service.port }} - path: /auth/_blazor(/|$)(.*) pathType: Prefix backend: service: name: {{ .Values.label.name }}-service port: number: {{ .Values.service.port }}
问题根源
多Ingress优先级冲突:第三个负责静态资源的Ingress里,路径规则(比如
/auth/icons(/|$)(.*))比第二个Ingress的/auth/(.*)更具体,NGINX Ingress的匹配逻辑是最长前缀优先,所以所有静态资源请求、甚至部分业务请求都会先命中第三个Ingress的规则,跳过了第二个Ingress的重写配置,导致重写根本没触发。静态资源未重写:就算静态资源请求命中了第三个Ingress,当前配置也不会重写路径,后端收到的是
/auth/icons/logo.png,但管理面板的静态资源实际应该在/auth/admin/icons/logo.png,这还会导致页面静态资源加载失败。PathType与正则不兼容:使用正则匹配时,
pathType: Prefix不是最佳选择,NGINX Ingress推荐用ImplementationSpecific来配合正则规则,否则可能出现匹配不符合预期的情况。
修复方案
把管理面板的业务路径和静态资源路径合并到同一个Ingress中,统一应用重写规则,调整匹配顺序:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: {{ .Values.label.name }}-service-admin-ingress annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: letsencrypt nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" nginx.ingress.kubernetes.io/client-max-body-size: "0" nginx.ingress.kubernetes.io/proxy-body-size: "0" nginx.ingress.kubernetes.io/proxy-connect-timeout: "3600" nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" nginx.ingress.kubernetes.io/use-regex: "true" # 统一重写路径,$2对应捕获的具体资源/业务路径 nginx.ingress.kubernetes.io/rewrite-target: /auth/admin/$2 spec: tls: - hosts: - admin.domain.com secretName: wildcard-domain-com-ingress rules: - host: admin.domain.com http: paths: # 先匹配所有静态资源的具体路径,正则分组捕获目录和后续路径 - path: /auth/(icons|img|js|styles|_framework|_blazor)(/|$)(.*) pathType: ImplementationSpecific backend: service: name: {{ .Values.label.name }}-service port: number: {{ .Values.service.port }} # 单独匹配favicon.ico - path: /auth/favicon.ico pathType: ImplementationSpecific backend: service: name: {{ .Values.label.name }}-service port: number: {{ .Values.service.port }} # 最后匹配其他所有/auth下的业务路径 - path: /auth(/|$)(.*) pathType: ImplementationSpecific backend: service: name: {{ .Values.label.name }}-service port: number: {{ .Values.service.port }}
调整说明
- 合并管理面板的所有Ingress规则,避免多Ingress的优先级冲突,确保重写规则能覆盖所有
admin.domain.com下的/auth路径。 - 修改重写规则的分组引用:因为静态资源路径的正则有多个分组,
$2才是我们需要传递给后端的实际路径部分,重写后静态资源路径会变成/auth/admin/icons/logo.png,业务路径变成/auth/admin/userlist。 - 路径按具体到通用的顺序排列,确保静态资源优先匹配,同时统一应用重写。
- 将
pathType改为ImplementationSpecific,适配正则匹配的场景,避免Prefix类型带来的匹配异常。
原普通用户的Ingress配置可以保留,它只作用于domain.com,不会影响admin.domain.com的请求。
内容的提问来源于stack exchange,提问作者Marcin Gadomski
相关产品推荐
相关产品推荐

