skip to Main Content

I have nginx ingress installed on my cluster. Here is the yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-client
  annotations:
    kubernetes.io/ingress.class: nginx
  namespace: dev
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: client-service
            port: 
              number: 80
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-service
            port: 
              number: 80

When I hit / prefix it is good.
curl http://example.com (All Good)

Problem:

But when I hit / api prefix, it returns /api of the service not / of the service

curl http://example.com/api (It should link to api-service, but it is linking to api-service/api)

Any help will be appreciated!

2

Answers


  1. You could use nginx.ingress.kubernetes.io/rewrite-target:

    In some scenarios the exposed URL in the backend service differs from the specified path in the Ingress rule. Without a rewrite any request will return 404. Set the annotation nginx.ingress.kubernetes.io/rewrite-target to the path expected by the service.

    So, here you could change your ingress as next:

    metadata:
      name: ingress-client
      annotations:
        kubernetes.io/ingress.class: nginx
        nginx.ingress.kubernetes.io/rewrite-target: /
      namespace: dev
    

    The ingress definition above will result in the following rewrites:

    • api-service/api rewrites to api-service/
    Login or Signup to reply.
  2. This is because a path / with type Prefix will match / and everything after, including /api. So your first rule overshadows the second rule in some sense.


    I don’t know if it’s an option for you, but it would be probably most elegant and idiomatic to use different hostnames for both services. If you deploy cert-manager, this shouldn’t be a problem.

    rules:
    - host: example.com
      http:
        paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: client-service
              port: 
                number: 80
    # use a different hostname for the api
    - host: api.example.com
      http:
        paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: api-service
              port: 
                number: 80
    

    Another option could be to use regex in your frontend path rule. And let it not match when the slash is followed by api. For that, you need to set an annotation.

    annotations:
      nginx.ingress.kubernetes.io/use-regex: "true"
    

    Then you can do something like the below for your frontend service. Using a negative lookahead.

    - path: /(?!api).*
    

    Alternatively, but less pretty, you could add a path prefix to your frontend service and strip it away via path rewrite annotation. But then you may have to write two separate ingress manifests as this is annotation counts for both, or you need to use a more complex path rewrite rule.

    annotations:
      nginx.ingress.kubernetes.io/rewrite-target: /$2
    
    - path: /ui(/|$)(.*)
    

    Perhaps it’s also sufficient to move the more specific route, /api, before the generic / route. In that case, switch the path around in the list. If they end up in that order in the nginx config, nginx should be able to handle it as desired.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search