As your environment grows, your gateways manage traffic for more and more routes. You might also have more ways of routing to a particular path for an app. To organize all your routes, you can use route table delegation. Delegation means that the routing decision for a route in one table instead gets made by another table.

  • “Parent” or “root” route table: The route table that delegates requests to another route table. This route table often configures the host and matching gateway details so that the routes in all the sub-tables are exposed on the same host. You can also configure the sorting method, such as by weight or specificity.
  • “Child” or “sub” route table: The route table that fulfills the routing request. This sub-table has the routing rules to match and forward traffic to the backing service.

This approach gives you the flexibility to manage a large number of routes in several ways, such as with label and matcher inheritance.

Label inheritance: Routes can inherit labels of their own route table, as well as their parent route table. This way, you can apply the same labels to many routes at once. Then, you can use these labels to select the routes in other resources, such as to apply security policies. For more information, see Route label inheritance.

Matcher inheritance: Routes also inherit matchers from the parent route table. This way, you can route to specific subpaths that share a common element. For more information, see Route matcher inheritance.

Delegation example

The following diagram shows how you can use route table delegation to manage access to multiple apps behind a single host domain. End users can access the apps securely via the ingress gateway along the host domain and route that you configure in the parent and child route tables.

Delegated routing overview
Delegated routing overview

  1. The virtual gateway routes ingress requests from your end users along the api.example.com host to the matching parent route table. In turn, the api.example.com parent route table forwards requests to the matching child route tables for each app.
  2. A parent route table is used for the host, api.example.com, along which end users can send requests to your apps. This parent route table delegates to the Tracks and Petstore child route tables. Your gateway team can apply default policies to the parent route table that all subsequent children route tables inherit. This way, your app teams do not need to worry about duplicating policies to meet internal and security requirements.
  3. Two child route tables configure the routing details of how to send requests to the backing destinations in the previous step. One child route table sets up the routes to the Tracks app, and the other child route table sets up the routes for the Petstore app. The app team lead can use labels for the routes to manage and apply team-specific policies, such as fault injection to test app behavior.
  4. The APIs represent the destinations that you can route requests to, such as Kubernetes services or Gloo VirtualDestinations. Your app developers can deploy and update their apps without having to worry about the routing behavior.

Example YAML configuration files

Review the following example YAML configuration files for the scenario in the previous diagram.

  # Example of delegation scenario
# Parent table with two matchers for the two API products
apiVersion: networking.gloo.solo.io/v2
kind: RouteTable
metadata:
  name: parent
  namespace: source-apps
spec:
  hosts:
    - www.api.example.com
  virtualGateways:
    - name: istio-ingressgateway
      namespace: gloo-mesh-gateways
  http:
    - name: product-tracks
      # Match requests along the path `www.api.example.com/tracks`
      matchers:
      - uri:
          prefix: /tracks
          ignoreCase: true
      # Delegate requests that match this path to child-tracks
      delegate:
        routeTables:
        - labels:
            table: child-tracks
    - name: product-petstore
      # Match requests along the path `www.api.example.com/petstore`
      matchers:
      - uri:
          prefix: /petstore
          ignoreCase: true
      # Delegate requests that match this path to child-petstore
      delegate:
        routeTables:
        - labels:
            table: child-petstore
---
# Tracks child route table
apiVersion: networking.gloo.solo.io/v2
kind: RouteTable
metadata:
  name: child-tracks
  namespace: target-apps
  labels:
    # Matches label in parent route table for delegation
    table: child-tracks
spec:
  http:
  # Table routes matching requests along the path `www.api.example.com/tracks` to tracks-api
  - name: product-tracks
    forwardTo:
      destinations:
      - ref:
          name: tracks-api
          namespace: tracks
        port:
          number: 8080
        kind: VIRTUAL_DESTINATION
---
# Petstore child route table
# with three matchers for each of the backing APIs
apiVersion: networking.gloo.solo.io/v2
kind: RouteTable
metadata:
  name: child-petstore
  namespace: target-apps
  labels:
    # Matches label in parent route table for delegation
    table: child-petstore
spec:
  http:
  # Table routes matching requests to  along the path `www.api.example.com/petstore/pets` to pets-api
  - name: product-beta
    matchers:
    - uri:
        prefix: /pets
        ignoreCase: true    
    forwardTo:
      destinations:
      - ref:
          name: pets-api
          namespace: pets
        port:
          number: 8080
        kind: VIRTUAL_DESTINATION
  # Table routes matching requests to  along the path `www.api.example.com/petstore/store` to store-api
  - name: product-beta
    matchers:
    - uri:
        prefix: /store
        ignoreCase: true    
    forwardTo:
      destinations:
      - ref:
          name: store-api
          namespace: store
        port:
          number: 8080
        kind: VIRTUAL_DESTINATION
  # Table routes matching requests to  along the path `www.api.example.com/petstore/users` to users-api
  - name: product-beta
    matchers:
    - uri:
        prefix: /users
        ignoreCase: true    
    forwardTo:
      destinations:
      - ref:
          name: users-api
          namespace: users
        port:
          number: 8080
        kind: VIRTUAL_DESTINATION
  

Route sorting methods

You can choose between two sorting methods for delegated routes, table weight and specificity.

Table weight sorting

Delegate routing to sub-tables based on an assigned order. Individual routes are kept in the order that they appear relative to their tables, but tables are sorted by the weight that you assign to them. When a service in your mesh sends a request to another service, the request is matched against the routes in the highest-weighted route table first. If the request doesn’t match a route in the first sub-table, it is matched against the routes in the second-highest-weighted table, and so on.

For an example setup, see Delegate to child route tables based on weight.

Specificity sorting

When an incoming request to a host arrives at the ingress gateway, the gateway processes all routes in each sub-table that you select. By default, routes are sorted by table weight. However, you can change the sorting method to sort by specificity instead. Then, the resulting routes are sorted by specificity to reduce the chance that a general route short-circuits a more specific route.

The following specificity rules apply:

  • Exact path matchers are considered more specific than regex path matchers, which are more specific than prefix path matchers.
  • Matchers of the same type are sorted by length of the path in descending order.
  • Only the most specific matcher on each route is used.
  • In the event of a sort tie, table weights are used across sub-tables, and route order is used within sub-tables.

For example, consider the following two sub-tables that are sorted by specificity and the resulting route list.

  • Sub-table A, with a table weight of 1 in case of sort ties:
    • prefix: /foo
    • prefix: /foo/more/specific
    • prefix: /foo/even/more/specific
    • exact: /foo/exact
    • exact: /foo/another/exact
    • regex: /foo/*
    • regex: /fooo/*
  • Sub-table B, with a table weight of 2:
    • prefix: /bar
    • prefix: /bar/more/specific
    • prefix: /bar/even/more/specific
    • exact: /bar/exact
    • regex: /bar/*

The resulting routes are sorted in this order:

  • exact: /foo/another/exact
  • exact: /bar/exact
  • exact: /foo/exact
  • regex: /bar/*
  • regex: /foo/*
  • regex: /fooo/*
  • prefix: /bar/even/more/specific
  • prefix: /foo/even/more/specific
  • prefix: /bar/more/specific
  • prefix: /foo/more/specific
  • prefix: /bar
  • prefix: /foo

For an example setup, see Delegate to child route tables based on route specificity.

Next steps

Now that you have a general idea of what route delegation is, learn how to manage delegated routes by using labels.