Answer a question

Alright, various permutations of this question have been asked and I feel terrible asking; I'm throwing the towel in and was curious if anyone could point me in the right direction (or point out where I'm wrong). I went ahead and tried a number of examples from the docs, but to no avail (see below).

I'm trying to route traffic to the appropriate location under Kubernetes using an Ingress controller.

Server Setup

I have a server, myserver.com and three services running at:

myserver.com/services/

myserver.com/services/service_1/

myserver.com/services/service_2/

Note that I'm not doing anything (purposefully) to myserver.com/.

At each of the three locations, there's a webapp running. For example, myserver.com/services/service_2 needs to load css files at myserver.com/services/service_2/static/css, etc...

Kubernetes Ingress

To manage the networking, I'm using a Kubernetes Ingress controller, which I've defined below. The CORS annotations aren't super relevant, but I've included them to clear up any confusion.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myServices
  namespace: myServices
  annotations:
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, OPTIONS"
    nginx.ingress.kubernetes.io/cors-allow-origin: '$http_origin'
    nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/use-regex: "true"

spec:
  ingressClassName: nginx
  tls:
  - hosts:
      - myserver.com
  rules:
  - host: myserver.com
    http:
      paths:
      - path: /services
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80
      - path: /services/service_1(/|$)
        pathType: Prefix
        backend:
          service:
            name: web-service-1
            port:
              number: 80
      - path: /services/service_2(/|$)
        pathType: Prefix
        backend:
          service:
            name: web-service-2
            port:
              number: 80

Targets

I noticed that one helpful thing to do is give some path examples. From the examples below it looks like the paths aren't that complicated. I think this is what I'm after. Note that I'd like each service to be able to resolve its css and image files.

myserver.com/services -> myserver.com/services
myserver.com/services/xxx/xxx -> myserver.com/services/xxx/xxx
myserver.com/services/service_1 -> myserver.com/services/service_1
myserver.com/services/service_1/xxx/xxx -> myserver.com/services/service_1/xxx/xxx
myserver.com/services/service_2/xxx/xxx -> myserver.com/services/service_2/xxx/xxx


Attempts

I know that this issue has to do a lot with the nginx.ingress.kubernetes.io/rewrite-target rule and its interaction with the paths I've defined.

I know that I don't want nginx.ingress.kubernetes.io/rewrite-target: $1 because that gives a 500 when visiting myserver.com/services

I know that I don't want nginx.ingress.kubernetes.io/rewrite-target: $1/$2 because when I visit myserver.com/services/service_1 I actually get part of the content at myserver.com/services rendered on the page.

SO Attempt 1

I also attempted to replicate the accepted solution from this question.

In this attempt I set

nginx.ingress.kubernetes.io/rewrite-target: "/$1" and one of the service paths to

- path: /(services/service_1(?:/|$).*)

When I visit myserver.com/services/service_1/xyz, the HTML from myserver.com/services/service_1 gets rendered.

Concluding Thoughts

Something ain't quite right with the path rewrite and paths rules. Any suggestions?

Answers

The problem you reported in your most recent comment is resolved by looking at the rewrite example in the nginx-ingress documentation.

The rewrite-target annotation configures the ingress such that matching paths will be rewritten to that value. Since you've specified a static value of /, anything matching your ingress rules will get rewritten to /, which is exactly the behavior you're seeing.

The solution is to capture the portion of the path we care about, and then use that in the rewrite-target annotation. For example:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myservices
  annotations:
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, OPTIONS"
    nginx.ingress.kubernetes.io/cors-allow-origin: '$http_origin'
    nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/ssl-redirect: "false"

spec:
  ingressClassName: nginx
  rules:
  - host: myserver.com
    http:
      paths:
      - path: /services/service_1(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: webservice-service1
            port:
              number: 80
      - path: /services/service_2(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: webservice-service2
            port:
              number: 80
      - path: /services(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: webservice
            port:
              number: 80

Here, we've modified the match expression so that they look like:

      - path: /services/service_1(/|$)(.*)

The second capture group (.*) captures everything after the path portion that matches literally. We then use that capture group ($2, because it's the second group) in the rewrite-target annotation:

    nginx.ingress.kubernetes.io/rewrite-target: /$2

With this configuration in place, a request to /services/service_2 results in:

This is service2.

But a request to /services/service_2/foo/bar results in:

<html><head><title>404 Not Found</title></head><body>
<h1>Not Found</h1>
The URL you requested (/foo/bar) was not found.
<hr>
</body></html>

And looking at the backend server logs, we see:

10.42.0.32 - - [21/Jan/2022:20:33:23 +0000] "GET / HTTP/1.1" 200 211 "" "curl/7.79.1"
10.42.0.32 - - [21/Jan/2022:20:33:45 +0000] "GET /foo/bar HTTP/1.1" 404 311 "" "curl/7.79.1"

I've updated my example repository to match this configuration.

Logo

开发云社区提供前沿行业资讯和优质的学习知识,同时提供优质稳定、价格优惠的云主机、数据库、网络、云储存等云服务产品

更多推荐