如何在Kubernetes中基于HTTP方法路由同路径微服务请求?
基于K8S实现CQRS模式下的HTTP方法路由
场景
为销售业务的REST服务采用CQRS模式,在K8S集群中部署了两个微服务:
- 一个Pod专门处理GET请求(查询操作)
- 另一个Pod专门处理POST、PUT请求(命令操作)
两个服务操作同一销售资源,期望实现以下路由规则:
- 发往
mydomain.com/api/sales/*的GET请求路由至查询服务Pod - 发往
mydomain.com/api/sales/*的POST、PUT请求路由至命令服务Pod
当前Ingress配置问题
现有Ingress配置将同一路径/api/sales同时映射到两个不同Service,导致路由结果不确定。此外,K8S原生Ingress规范并不支持直接指定HTTP方法的配置项,ChatGPT建议的httpMethods参数属于不存在的伪配置。
原配置代码:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-ingress spec: rules: - host: mydomain.com http: paths: - path: /api/sales pathType: Prefix backend: service: name: sales-queries-service port: name: 80 - path: /api/sales pathType: Prefix backend: service: name: sales-commands-service port: name: 80 ingressClassName: ingress-nginx
解决方案(无需额外API网关)
由于你使用的是ingress-nginx控制器,可以利用其自定义注解实现基于HTTP方法的路由,无需额外安装第三方API网关。以下是具体实现方式:
方案1:拆分Ingress资源(推荐)
分别为查询服务和命令服务创建独立的Ingress资源,通过ingress-nginx专属注解限制允许的HTTP方法:
查询服务Ingress(仅处理GET请求)
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: sales-queries-ingress annotations: # 指定允许的HTTP方法 nginx.ingress.kubernetes.io/allow-methods: "GET" # 添加Nginx片段,对非GET请求返回405 nginx.ingress.kubernetes.io/server-snippet: | if ($request_method !~ ^(GET)$) { return 405; } spec: ingressClassName: ingress-nginx rules: - host: mydomain.com http: paths: - path: /api/sales pathType: Prefix backend: service: name: sales-queries-service port: number: 80
命令服务Ingress(仅处理POST、PUT请求)
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: sales-commands-ingress annotations: nginx.ingress.kubernetes.io/allow-methods: "POST,PUT" nginx.ingress.kubernetes.io/server-snippet: | if ($request_method !~ ^(POST|PUT)$) { return 405; } spec: ingressClassName: ingress-nginx rules: - host: mydomain.com http: paths: - path: /api/sales pathType: Prefix backend: service: name: sales-commands-service port: number: 80
方案2:单个Ingress资源内配置(进阶)
若希望在同一个Ingress中实现规则,可以通过configuration-snippet结合Nginx变量判断请求方法:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: sales-combined-ingress annotations: nginx.ingress.kubernetes.io/configuration-snippet: | # 将GET请求路由到查询服务,其余路由到命令服务 set $service_name "sales-commands-service"; if ($request_method = GET) { set $service_name "sales-queries-service"; } spec: ingressClassName: ingress-nginx rules: - host: mydomain.com http: paths: - path: /api/sales pathType: Prefix backend: service: name: $service_name port: number: 80
关键注解说明
nginx.ingress.kubernetes.io/allow-methods:明确指定该Ingress允许的HTTP方法,多个方法用逗号分隔server-snippet/configuration-snippet:注入自定义Nginx配置片段,实现请求方法的校验和路由逻辑
注意事项
- 确保集群已正确部署
ingress-nginx控制器,上述注解为该控制器专属,不属于K8S原生Ingress规范 - 拆分Ingress资源的方式更易于维护和排查问题,推荐优先使用
内容的提问来源于stack exchange,提问作者Paulo Merson
相关产品推荐
相关产品推荐

