0

I'm trying to deploy my frontend client application and backend API on the same domain and I want the frontend on the base path: /

However, I realized that the frontend and the backend need two different rewrite-target to accomplish this.

front-end works with:

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

while the backend works with:

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

I tried using two different ingress services in order to accommodate different rewrite-target, but that fails because the host was the same domain.

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  namespace: test
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-staging
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/add-base-url: "true"
    nginx.ingress.kubernetes.io/service-upstream: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/proxy-buffer-size: 128k
    nginx.ingress.kubernetes.io/proxy-buffering: "on"
    nginx.ingress.kubernetes.io/proxy-buffers-number: "4"
    nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      more_set_headers "server: hide";
      more_set_headers "X-Content-Type-Options: nosniff";
      more_set_headers "X-Xss-Protection: 1";
spec:
  tls:
  - hosts:
    - test.eastus.cloudapp.azure.com
    secretName: tls-secret
  rules:
  - host: test.eastus.cloudapp.azure.com
    http:
      paths:
      - backend:
          serviceName: webapp
          servicePort: 80
        path: /
      - backend:
          serviceName: api
          servicePort: 80
        path: /api(/|$)(.*)

I know I can make both work with the same rewrite-target /$2 if I change the frontend path to path: /app(/|$)(.*) but I don't want to that except it is the only option.

Is there a way for me to better configure a single ingress to work for 2 different rewrite-target?

3 Answers 3

4

Ingress with API version networking.k8s.io/v1 with k8s version 1.19+ can solve your problem. I have given an example below.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: simple-fanout-example
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: frontend-service
            port:
              number: 80
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: backend-service
            port:
              number: 8080

According to kubernetes documentation:

In some cases, multiple paths within an Ingress will match a request. In those cases precedence will be given first to the longest matching path. If two paths are still equally matched, precedence will be given to paths with an exact path type over prefix path type.

So, when you are looking for a resource located at path "/home.html", it only matches with your frontend service. But when you are looking for a resource located at path "/api/something" then it matches both service. But it will go to backend service always because of maximum path match stated above.

Sign up to request clarification or add additional context in comments.

2 Comments

Great! That's the easiest solution, the only drawback I can see is that it cannot redirect requests removing prefix, e.g. /api/cars/activate -> /cars/activate, so you forced to explicitly specify api prefix in the backend service code itself.
uhm.. This won't work if you're doing client-side routing in vue: let's say you go to yourdomain.com, then use the ui to navigate to yourdomain.com/search. Vue's router will handle this. However, if you refresh, you now get no match for /search in your ingress, so you get 404
2

I don't know would you take it or not but it can a be solution. You can use two ingress for achieving your target. Each one will use different annotations. It will work fine.

Just as like your current ingress yaml, make another yaml and put two different annotations in them and also put your front-end and back-end in them separately. host (host: test.eastus.cloudapp.azure.com) will be same as you provided here.

Comments

1

[My original answer was closed on a technicality by @Samuel Liew - Samuel, the answer was actually a better fit for this question since it specifically addresses the issue of not getting a blank page on refresh when using Vue frontend routing]

TLDR: The trick is to use "nginx.ingress.kubernetes.io/configuration-snippet" = "if ($request_uri !~* ^/(api|assets)) { rewrite ^/.*$ / break; }" which rewrites all paths except /api and /assets. The other thing to point out, I put my favicon within the assets folder and then <link rel="shortcut icon" href="/assets/favicon.ico"> in main.ts

For the full solution, see: https://stackoverflow.com/a/75913365/7182570

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.