Kubernetes path based routing for multiple namespaces

3/26/2018

The environment: I have a kubernetes cluster set up with namespaces for "dev", "sit" and "prod". In each of these namespaces i have multiple services of type:LoadBalancer which target a specific deployment of a dockerised application (i have multiple applications) so i can access each of these by just using the exposed ip address of the service of whichever namespace i want. Example service looks like this an is very simple:

apiVersion: v1
kind: Service
metadata:
  name: application1
spec:
  ports:
  - port: 80
    targetPort: 3000
    protocol: TCP
    name: http
  type: LoadBalancer
  selector:
    app: application1

The problem: I now want to be able to support multiple versions of all applications (ip:/v1/, ip:/v2/ etc) as to allow the users to migrate to the new version when they are ready and i've been trying to implement path-based routing following this guide. I have managed to restructure my architecture so that i have ReplicationControllers and an ingress which looks at the rules of the path to route to the correct service.

This seems to work if i'd only have one exposed service and a single namespace because i only have DNS host names for production environment and want to use the individual ip address of a service for other environments and i can't figure out how to specify the ingress rules for a service which doesn't have a hostname.

I could just have a loadbalancer for every environment and use path based routing to route to each different services for dev and sit which is not ideal because to access any service we'd have to now use something like this ip/application1 and ip/application2 instead of directly using the service ip address of each application. But my biggest problem is that when i followed the guide and created the ingress, replicationController and a service in my SIT namespace it started affecting the loadbalancer services in my other two environments (as i understand the kubernetes would sometimes try to use the nginx controller from SIT environment on my DEV services and therefore would fail, other times it would use the GCE default configuration and would work).

I tried adding the arg "- --watch-namespace=sit" to limit the scope of the ingress controller to only affect sit but it does not seem to work.

-- BroBan
google-cloud-platform
kubernetes
kubernetes-ingress

1 Answer

3/26/2018

I now want to be able to support multiple versions of all applications (ip:/v1/, ip:/v2/ etc.)

That is exactly what Ingress can do, but the problem is that you want to use IP addresses for routing, but Ingress is using DNS names for that.

I think the best way to implement this is to use an Ingress which will handle requests. On GCE Ingress uses the HTTP(S) load balancer. Yes, you will need a DNS name for that, but it will help you to create a routing which you need.
Also, I highly recommend using TLS encryption for connections.
You can check LetsEncrypt to get a free SSL certificate.

So, the solution should like below:

1. Deploy your Services with type "ClusterIP" instead of "LoadBalancer". You can have more than one Service object for an application so you can do it in parallel with your current configuration.
2. Select any namespace (even special one), for instance - "ingress-ns". We need to create there Service objects which will point to your services in other namespaces. Here is an example of a service (let new DNS name be "my.shiny.new.domain"):

kind: Service
apiVersion: v1  
  metadata:
    name: service-v1
    namespace: ingress-ns
 spec:  
   type: ExternalName
   externalName: <service>.<namespace>.svc.cluster.local # here is a service name and namespace of your service with version v1.
  ports:
    - port: 80 

3. Now, we have a namespace with several services which are pointing to different versions of your application in different namespaces. Now, we can create an Ingress object which will create an HTTP(S) Load Balancer on GCE with path-based routing:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
 name: test
 namespace: ingress-ns
spec:
 rules:
 - host: my.shiny.new.domain
   http:
     paths:
     - path: /v1
       backend:
         serviceName: service-v1
         servicePort: 80
     - path: /v2
       backend:
         serviceName: service-v2
         servicePort: 80

Kubernetes will create a new HTTP(S) balancer with rules you set up in an Ingress object, and you will have an entry point with cross-namespaces path-based routing, and you don't have to use multiple IP addresses for that.

Actually, you can also manage by that ingress your primary version of an application and use your primary domain with "/" path to handle requests to your production version.

-- Nick Rak
Source: StackOverflow