I managed to find a working solution for what you described with two ingress objects. With the example that you provided ingress won't be able to direct you towards service-b since nginx does not match query string at all. This is very well explained here.
Ingress selects the proper backed based on path. So I have prepared separate path for the second backend and put a conditional redirect to it to the first path so when request reach the /tmp path it uses service-b backend and trims the tmp part from the request.
So here's the ingress that matches /foo/bar for the 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
And here is the ingress that matches /foo/bar? and whatever comes after for the 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
Please note, that previous configuration leftovers can prevent that solution from working well. Clean up, redeploy and ingress controller restart should help in that situation.
Here are some tests to prove the case. First I have added the xxxx.com to /etc/hosts:
➜ ~ cat /etc/hosts
127.0.0.1 localhost
192.168.59.2 xxxx.com
- Here we are testing the firs path /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.
- And here we are testing the firs path /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": {}
For the responses I've used the mendhak/http-https-echo image:
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