nginx - Kubernetes NGINX 入口控制器 - 如果存在查询字符串,则路由不同
问题描述
Kubernetes 的 Nginx 入口控制器是否可以有一个入口规则,根据查询字符串是否存在路由到不同的服务?例如..
/foo/bar -> 到 serviceA 的路由
/foo/bar?x=10 -> 路由到 serviceB
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
rules:
- host: xxxx.com
http:
paths:
- path: /foo/bar(/|$)(.*)
pathType: Prefix
backend:
service:
name: serviceA
port:
number: 8001
- path: /foo/bar(/|$)(.*)\?
pathType: Prefix
backend:
service:
name: serviceB
port:
number: 8002
解决方案
我设法为您用两个入口对象描述的内容找到了一个可行的解决方案。使用您提供的示例,入口将无法引导您,service-b
因为 nginx 根本不匹配查询字符串。这在这里得到了很好的解释。
Ingress 根据路径选择适当的支持。所以我为第二个后端准备了单独的路径,并将有条件的重定向到第一个路径,所以当请求到达/tmp
路径时,它使用service-b
后端并从请求中修剪 tmp 部分。
所以这是匹配的/foo/bar
入口backend-a
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($args ~ .+){
rewrite ^ http://xxxx.com/foo/bar/tmp permanent;
}
spec:
rules:
- host: xxxx.com
http:
paths:
- path: /foo/bar
pathType: Prefix
backend:
serviceName: service-a
servicePort: 80
这是匹配的入口/foo/bar?
以及之后的任何内容backend-b
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress-rewrite
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /foo/bar$1
spec:
rules:
- host: xxxx.com
http:
paths:
- path: /foo/bar/tmp(.*)
backend:
serviceName: service-b
servicePort: 80
请注意,以前的配置剩余可能会阻止该解决方案正常运行。在这种情况下,清理、重新部署和重新启动入口控制器应该会有所帮助。
这里有一些测试来证明这一点。首先我添加了xxxx.com
到/etc/hosts
:
➜ ~ cat /etc/hosts
127.0.0.1 localhost
192.168.59.2 xxxx.com
- 在这里我们正在测试第一条路径/foo/bar
:
➜ ~ curl -L -v http://xxxx.com/foo/bar
* Trying 192.168.59.2...
* TCP_NODELAY set
* Connected to xxxx.com (192.168.59.2) port 80 (#0)
> GET /foo/bar HTTP/1.1 <----- See path here!
> Host: xxxx.com
> User-Agent: curl/7.52.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Tue, 13 Apr 2021 12:30:00 GMT
< Content-Type: application/json; charset=utf-8
< Content-Length: 644
< Connection: keep-alive
< X-Powered-By: Express
< ETag: W/"284-P+J4oZl3lklvyqdp6FEGTPVw/VM"
<
{
"path": "/foo/bar",
"headers": {
"host": "xxxx.com",
"x-request-id": "1f7890a47ca1b27d2dfccff912d5d23d",
"x-real-ip": "192.168.59.1",
"x-forwarded-for": "192.168.59.1",
"x-forwarded-host": "xxxx.com",
"x-forwarded-port": "80",
"x-forwarded-proto": "http",
"x-scheme": "http",
"user-agent": "curl/7.52.1",
"accept": "*/*"
},
"method": "GET",
"body": "",
"fresh": false,
"hostname": "xxxx.com",
"ip": "192.168.59.1",
"ips": [
"192.168.59.1"
],
"protocol": "http",
"query": {},
"subdomains": [],
"xhr": false,
"os": {
"hostname": "service-a" <------ Pod hostname that response came from.
- 在这里我们正在测试第一条路径/foo/bar
:
➜ ~ curl -L -v http://xxxx.com/foo/bar\?x\=10
* Trying 192.168.59.2...
* TCP_NODELAY set
* Connected to xxxx.com (192.168.59.2) port 80 (#0)
> GET /foo/bar?x=10 HTTP/1.1 <--------- The requested path!
> Host: xxxx.com
> User-Agent: curl/7.52.1
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Date: Tue, 13 Apr 2021 12:31:58 GMT
< Content-Type: text/html
< Content-Length: 162
< Connection: keep-alive
< Location: http://xxxx.com/foo/bar/tmp?x=10
<
* Ignoring the response-body
* Curl_http_done: called premature == 0
* Connection #0 to host xxxx.com left intact
* Issue another request to this URL: 'http://xxxx.com/foo/bar/tmp?x=10'
* Found bundle for host xxxx.com: 0x55d6673218a0 [can pipeline]
* Re-using existing connection! (#0) with host xxxx.com
* Connected to xxxx.com (192.168.59.2) port 80 (#0)
> GET /foo/bar/tmp?x=10 HTTP/1.1
> Host: xxxx.com
> User-Agent: curl/7.52.1
> Accept: */*
>
{
"path": "/foo/bar",
"headers": {
"host": "xxxx.com",
"x-request-id": "96a949a407dae653f739db01fefce7bf",
"x-real-ip": "192.168.59.1",
"x-forwarded-for": "192.168.59.1",
"x-forwarded-host": "xxxx.com",
"x-forwarded-port": "80",
"x-forwarded-proto": "http",
"x-scheme": "http",
"user-agent": "curl/7.52.1",
"accept": "*/*"
},
"method": "GET",
"body": "",
"fresh": false,
"hostname": "xxxx.com",
"ip": "192.168.59.1",
"ips": [
"192.168.59.1"
],
"protocol": "http",
"query": {
"x": "10"
},
"subdomains": [],
"xhr": false,
"os": {
"hostname": "service-b" <-----Service-b host name!
},
"connection": {}
对于我使用 mendhak/http-https-echo
图像的响应:
apiVersion: v1
kind: Pod
metadata:
name: service-b
labels:
app: echo2
spec:
containers:
- name: service-b #<-------- service-b host name
image: mendhak/http-https-echo
ports:
- containerPort: 80
推荐阅读
- javascript - 基于onclick的子菜单扩展和innerHTML替换,只使用Javascript
- google-apps-script - 使用 App maker 查找并写入列中的下一个空白单元格
- javascript - 安培值替换到位
- python-3.x - 使用python脚本将图像导入odoo 11时出错
- html - 使用 nth-child 时浮动不工作
- javascript - 如何在 angularjs 或核心 javascript 中转换 php 序列化数据(用于移动应用程序)
- groovy - 使用 Groovy 在 SoapUI 中自动保存附件
- python - 一排树视图odoo
- html - 如何使用角度 5 根据屏幕分辨率设置动态 div 高度
- google-chrome - VSTS - 工作(积压板) - 不保存