skip to Main Content

I have a few pods that I am trying to match URLs for their respective services.

Please note that I need to use nginx.ingress.kubernetes.io/rewrite-target to solve this and not nginx.ingress.kubernetes.io/rewrite-target

My ingress config file looks like this. Notice the /api/tile-server/ does not have any regex pattern

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: ingress-service
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/use-regex: "true"
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
  namespace: default
spec:
  tls:
    - hosts:
        - example.com
      secretName: tls-secret
  rules:
    - host: example.com
      http:
        paths:
          - path: /?(.*)
            backend:
              serviceName: client
              servicePort: 80
          - path: /api/auth/?(.*)
            backend:
              serviceName: auth
              servicePort: 8000
          - path: /api/data/?(.*)
            backend:
              serviceName: data
              servicePort: 8001
          - path: /api/tile-server/
            backend:
              serviceName: tile-server
              servicePort: 7800
  • client pod is a react app built inside nginx docker image working fine
  • nginx.conf looks like this (if it’s helpful)
server {
    # listen on port 80
    listen 80;
    # where the root here
    root /usr/share/nginx/html;
    # what file to server as index
    index index.html index.htm;

    location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to redirecting to index.html
        try_files $uri $uri/ /index.html;
    }

    # Media: images, icons, video, audio, HTC
    location ~* .(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
        expires 1M;
        access_log off;
        add_header Cache-Control "public";
    }

    # Javascript and CSS files
    location ~* .(?:css|js)$ {
        try_files $uri =404;
        expires 1y;
        access_log off;
        add_header Cache-Control "public";
    }

    # Any route containing a file extension (e.g. /devicesfile.js)
    location ~ ^.+..+$ {
        try_files $uri =404;
    }
}
  • auth and data are Flask API pods working fine
  • tile-server is also a Flask pod but need not do any pattern matching. I need to match the exact /api/tile-server/ URL

I have tried the following patterns but failed:

  • /api/tile-server/
  • /api/tile-server/?(.*)
  • /api/tile-server(/|$)?(.*)

I can confirm that the pods/services are running on their proper ports and I am able to access them through node ports but not through load balancer/domain.
What would be the right pattern to exactly match /api/tile-server/ URL?

3

Answers


  1. move from v1beta1 to v1 and use pathType: Exact – https://kubernetes.io/docs/concepts/services-networking/ingress/

    Login or Signup to reply.
  2. First solution – create separate ingress object for tile-server with rewrite-target annotation. This will work because ingress rules with the same host are merged together by ingress controller and separate ingress object allow for use of different annotations per object:

    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: tile-ingress-service
      annotations:
        nginx.ingress.kubernetes.io/ssl-redirect: "true"
        nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
        nginx.ingress.kubernetes.io/rewrite-target: "/$2"
        kubernetes.io/ingress.class: "nginx"
        cert-manager.io/cluster-issuer: "letsencrypt-prod"
      namespace: default
    spec:
      tls:
        - hosts:
            - example.com
          secretName: tls-secret
      rules:
        - host: example.com
          http:
            paths:
              - path: /api/tile-server(/|$)(.*)
                backend:
                  serviceName: tile-server
                  servicePort: 7800
    

    Second solution – rewrite current ingress to work with rewrite-path. Some regex changes are necessary.

    Notice the non-capturing group notation: (?:<regex>). This allows to skip numbering for these groups since I need everything relevant to be in the first group in order for it to work, because rewrite-target: "/$1".

    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: ingress-service
      annotations:
        nginx.ingress.kubernetes.io/ssl-redirect: "true"
        nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
        nginx.ingress.kubernetes.io/rewrite-target: "/$1"
        kubernetes.io/ingress.class: "nginx"
        cert-manager.io/cluster-issuer: "letsencrypt-prod"
      namespace: default
    spec:
      tls:
        - hosts:
            - example.com
          secretName: tls-secret
      rules:
        - host: example.com
          http:
            paths:
              - path: /(.*)
                backend:
                  serviceName: client
                  servicePort: 80
              - path: /(api/auth(?:/|$).*)
                backend:
                  serviceName: auth
                  servicePort: 8000
              - path: /(api/data(?:/|$).*)
                backend:
                  serviceName: data
                  servicePort: 8001
              - path: /api/tile-server(?:/|$)(.*)
                backend:
                  serviceName: tile-server
                  servicePort: 7800
    

    Here is how the rewrites will work for:

    • auth service (same applies to data service)
        /api/auth      --->  /api/auth
        /api/auth/     --->  /api/auth/
        /api/auth/xxx  --->  /api/auth/xxx
    
    • tile-server service:
        /api/tile-server      --->  /
        /api/tile-server/     --->  /
        /api/tile-server/xxx  --->  /xxx
    
    • client service
        /xxx  --->  /xxx
    

    Notice that the following paths will be forwarded to client service (where xxx is any alphanumerical string):

        /api/authxxx
        /api/dataxxx
        /api/tile-serverxxx
    

    If you want them to be forwaded to other/matching services, add ? after (?:/|$) in path.

    Login or Signup to reply.
  3. this is my solution

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: "/$1"
      name: ingress-staging
      namespace: staging
    spec:
      ingressClassName: nginx
      rules:
    
      - http:
          paths:
          - path: /(.*)
            pathType: Prefix
            backend:
              service:
                name: acp-service
                port: 
                  number: 80
      
      - http:
          paths:
          - path: /service-ecommerce(?:/|$)(.*)
            pathType: Prefix
            backend:
              service:
                name: ecommerce-service
                port: 
                  number: 80      
    

    Thanks @Matt

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