uselagoon / lagoon

Lagoon, the developer-focused application delivery platform
https://docs.lagoon.sh/
Apache License 2.0
552 stars 149 forks source link

Path based routing #3642

Open seanhamlin opened 6 months ago

seanhamlin commented 6 months ago

In order to work around a Next.js core issue in which having two application pods causes 'preview mode' to only work 50% of the time, it would be great to have more flexibility when in comes to path based routing to services.

In this particular use case, we are thinking:

This seems like the most supportable option for running Next.js with Lagoon for now.

shreddedbacon commented 6 months ago

I think this is doable, we'd need to make sure that it is something we can support long term though. And is also somewhat guardrailed, will chat amongst the team with some possible implementation methods

shreddedbacon commented 6 months ago

Might need to move this to the build-deplo-tool repo, but will leave it here for now

dwoods commented 5 months ago

I'm not sure if this is the same thing, but what we'd like to do is have routes in different projects/environments share the same hostname with a different path.

So for example, in project `site-1', we would have the following route:

project: site-1

environments:
  main:
    routes:
      - nginx:
          - "www.example.com/site-1":

And in project site-2:

project: site-2

environments:
  main:
    routes:
      - nginx:
          - "www.example.com/site-2":

Ideally this would result in the hostname and path being split out, and creating the Ingresses appropriately.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: www.example.com--site-1
  namespace: site-1-main
  annotations:
    standard: stuff
  labels:
    lagoon.sh/autogenerated: 'false'
    lagoon.sh/buildType: branch
    lagoon.sh/environment: main
    lagoon.sh/environmentType: production
    lagoon.sh/primaryIngress: 'true'
    lagoon.sh/project: site-1
    lagoon.sh/service-type: custom-ingress
spec:
  ingressClassName: nginx
  rules:
    - host: www.example.com
      http:
        paths:
          - backend:
              service:
                name: nginx
                port:
                  name: http
            path: /site-1
            pathType: Prefix
  tls:
    - hosts:
        - www.example.com
      secretName: www.example.com-tls

And the other:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: www.example.com--site-2
  namespace: site-2-main
  annotations:
    standard: stuff
  labels:
    lagoon.sh/autogenerated: 'false'
    lagoon.sh/buildType: branch
    lagoon.sh/environment: main
    lagoon.sh/environmentType: production
    lagoon.sh/primaryIngress: 'true'
    lagoon.sh/project: site-2
    lagoon.sh/service-type: custom-ingress
spec:
  ingressClassName: nginx
  rules:
    - host: www.example.com
      http:
        paths:
          - backend:
              service:
                name: nginx
                port:
                  name: http
            path: /site-2
            pathType: Prefix
  tls:
    - hosts:
        - www.example.com
      secretName: www.example.com-tls

I believe the standard ingress-nginx controller will handle this and merge the definitions into the same server block.

In our case we're using the NGINX Plus ingress controller which requires an additional annotation for this to work, but that's easy enough.

We're currently working around this by having another handler that proxies to the Ingresses (domain masking). But this is clunky and the URLs of the routes in Lagoon don't accurately reflect the actual external URL.

Does this sound like the same feature?

shreddedbacon commented 5 months ago

Does this sound like the same feature?

No, what you're describing is something different. The feature described in the first post is for path based routing within the same environment, ie, directing traffic for www.example.com/site-2 to a service/pod/container running within the same environment that serves the primary traffic, but instead directing it to the service for site-2.

I don't think we would be able to support what you're describing very easily, and it isn't something we've had a lot of requests for. It would also be difficult to be able to manage this properly currently. Lagoon has no real way to control which projects/environments have which ingress on them, which means if someone in project notsite-2 decides to add www.example.com/site-2 to their project. Lagoon currently has no good way to verify if notsite-2 project is actually allowed to use www.example.com as their domain. We would need to do a lot of work in the API to support that. The ability to define ingress/routes in the API is something we have discussed in the past, which could pave the way for support for what you're describing in the future though.

Alternatively, if you're running your own Lagoon installation, and you see this feature as extremely important for your usecase, we are open to reviewing PR/contributions for new features. The [build-deploy-tool](https://github.com/uselagoon/build-deploy-tool) would likely be a good starting point if you don't care about the API side of validating namespace ingress sharing, but if you want to ensure that only projects allowed to deploy specific ingress can, you'll need to do some work in the API to build out some functionality that doesn't currently exist.

dwoods commented 5 months ago

Ah, that makes sense, thanks for the detailed explanation. Apologies for hijacking the issue.

It is important for us, and we do run our own Lagoon install, so I'll take a stab at it in the build-deploy-tool and see if it makes sense to start a PR for it.

shreddedbacon commented 5 months ago

It is important for us, and we do run our own Lagoon install, so I'll take a stab at it in the build-deploy-tool and see if it makes sense to start a PR for it.

Keen to see how you go with it. Generally though, I don't think this is a great idea to span an ingress between projects like this.

EDIT: From a complexity perspective, you're making it a bit more difficult to trace traffic flows. And without proper ingress validations, anyone could potentially break some other site purely by deploying an environment with a route that is a sub path of an already existing ingress. Say you have www.example.com/site1 and there is a site1/login page. Without validating who can consume www.example.com I could deploy an environment that presents a new place to receive your login traffic by deploying with www.example.com/site1/login

Feel free to create a new issue though if you want to discuss your particular use case further though, rather than continuing here.