When you forward requests to a Kubernetes service, virtual destination, or external service, you can configure additional settings in your route table. Review the following sections to set a default destination, route to an application subset, or assign weights to app instances.

Set a default destination

Set a default destination in a route table so that multiple routes can be easily assigned to that destination.

For example, you might want to designate multiple routes for one destination, for the purpose of assigning certain policies to certain routes. Instead of typing out the same destination definition in each of the routes, you can instead define the destination as the default, and leave the forwardTo directive in each route empty. Note that any routes in the route table that do not specify a destination will forward traffic to the default destination.

In this example route table, the information for the ratings destination is defined in the spec.defaultDestination field, rather than repeated in each http route. This way, the two routes can automatically reference the ratings definition.

  apiVersion: networking.gloo.solo.io/v2
kind: RouteTable
metadata:
  name: example
  namespace: bookinfo
spec:
  defaultDestination:
    port:
      number: 9080
    ref:
      name: ratings
      namespace: bookinfo
      cluster: ${REMOTE_CLUSTER1}
  hosts:
  - 'ratings.bookinfo.svc.cluster.local'
  http:
  - forwardTo: {}
    labels:
      "no": auth
    matchers:
    - headers:
      - name: noauth
        value: "true"
    name: ratings-no-auth
  - forwardTo: {}
    labels:
      route: ratings
    name: ratings
  

Weighted routing to an application subset

If you are testing multiple versions of your app within your mesh, you can route to each version by using the version numbers. Additionally, you can optionally assign weights to each version of the app to determine the load or requests that each version receives.

Review the following examples:

  • HTTP example for a weighted subsets that send traffic to two versions.
  • TCP example for splitting TCP traffic to different httpbin and hello world apps on the same host.

HTTP example

Say that your app deployment for each version contains the app: myapp label, and labels such as version: v1 and version: v2. In the route table, you add references to the both versions of the app, and specify the version labels in the subset field of each reference section.

Additionally, this example route table specifies an optional weight for each version of the app. 75% of traffic requests to the /myapp are directed to v1, and 25% of traffic requests are directed to v2. Weighted routing can be useful in scenarios such as controlled rollouts to slowly move traffic from an older to a newer version of your app.

  apiVersion: networking.gloo.solo.io/v2
kind: RouteTable
metadata:
  name: myapp-routes
  namespace: global
spec:
  hosts:
    - 'myapp.global.svc.cluster.local'
  http:
    # Route for the myapp service
    - name: myapp
      # Prefix matching
      matchers:
      - uri:
          prefix: /myapp
      # Forwarding directive
      forwardTo:
        destinations:
          # Reference to the virtual destination that selects v1 of the myapp service
          - ref:
              name: myapp
            kind: VIRTUAL_DESTINATION
            subset:
              version: v1
            # 75% of request traffic to /myapp
            weight: 75
          # Reference to the virtual destination that selects v2 of the myapp service
          - ref:
              name: myapp
            kind: VIRTUAL_DESTINATION
            subset:
              version: v2
            # 25% of request traffic to /myapp
            weight: 25
  

TCP weighted example

Use the following steps to set up weighted routing for TCP routes to your hello world app.

Before you begin, complete the prerequisite steps in the Routing guide.

  1. Create a virtual destination resource for your destination app that receives TCP requests from the initiator app. The following virtual destination listens for requests on the helloworld.vd host on TCP port 9000. Then, the virtual destination forwards requests to any app with the label app: helloworld on the tcp port. Note that because virtual destinations are dynamic, the east-west gateway that handles the request routes it to the closest healthy app instance.

      kubectl --context ${REMOTE_CONTEXT1} apply -f - <<EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: VirtualDestination
    metadata:
      annotations:
        cluster.solo.io/cluster: ""
      name: helloworld-global
      namespace: helloworld
    spec:
      hosts:
      - helloworld.vd
      ports:
      - number: 9000
        protocol: TCP
        targetPort:
          name: tcp
      services:
      - labels:
          app: helloworld
    EOF
      
  2. Route requests initiated from your initiator app to your destination app by using the virtual destination hostname. The following route table listens for requests from any app with the label app: productpage on the httpbin.httpbin.svc.cluster.local host. Then, it forwards the request to the helloworld-global virtual destination that you created in the previous step. By using weighted subsets, the route table splits the traffic evenly between the v1 app on cluster 1 and v3 app on cluster 3.

      kubectl --context ${REMOTE_CONTEXT1} apply -f - <<EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: RouteTable
    metadata:
      annotations:
        cluster.solo.io/cluster: ""
      name: bookinfo
      namespace: bookinfo
    spec:
      hosts:
      - httpbin.httpbin.svc.cluster.local
      tcp:
      - forwardTo:
          destinations:
          - kind: VIRTUAL_DESTINATION
            port:
              number: 9000
            ref:
              name: helloworld-global
              namespace: helloworld
            subset:
              version: v1
            weight: 50
          - kind: VIRTUAL_DESTINATION
            port:
              number: 9000
            ref:
              name: helloworld-global
              namespace: helloworld
            subset:
              version: v3
            weight: 50
        matchers:
        - port: 9000
      workloadSelectors:
      - selector:
          labels:
            app: productpage
    EOF
      
  3. Test the TCP routes from the initiator app to your destination app.

    1. Log into the product page app.
        kubectl -n bookinfo exec -it deploy/productpage-v1 -c netcat --context $REMOTE_CONTEXT1 -- sh
        
    2. Use the netcat command to test the connection to the hello world app along the TCP route on port 9000.
        echo "Hello" | nc -v httpbin.httpbin.svc.cluster.local 9000
        
    3. In the response, check that the connection request succeeds and you get a message from either hello-v1 in cluster 1 or hello-v3 in cluster 2.
        Connection to httpbin.httpbin.svc.cluster.local 9000 port [tcp/*] succeeded!
      hello-v1 Hello
        
    4. Close the connection by entering control+c and repeat the previous command a couple times until you see a response from the other hello app.
        Connection to httpbin.httpbin.svc.cluster.local 9000 port [tcp/*] succeeded!
      hello-v3 Hello
        
    5. To log out of the pod, close the connection by entering control+c and then enter exit.
  4. Optional: Clean up the resources that you created.

      kubectl delete -n helloworld vd helloworld-global --context $REMOTE_CONTEXT1
    kubectl delete -n bookinfo rt bookinfo --context $REMOTE_CONTEXT1
      

Route table annotations for Istio virtual services

You can add annotations to the route table that are populated to the Istio virtual service that the route table is translated to. A common example is to add annotations to exclude the virtual service from being managed by ExternalDNS, such as in cases where you want to manually manage the DNS record or integrate it with a different DNS provider.

Keep in mind the following rules when adding annotations to a virtual service via route tables:

  • Annotations that are automatically set by Gloo Mesh Enterprise, such as cluster.solo.io/cluster cannot be overwritten. If you specify an annotation that is set by Gloo Mesh Enterprise, the annotation is ignored.
  • Annotation keys must be unique. You cannot add multiple annotations with the same key, but different values, such as external-dns.alpha.kubernetes.io/exclude: "true" and external-dns.alpha.kubernetes.io/exclude: "false". If you add multiple annotations with the same key to the route table, the Kubernetes API server randomly selects one of the keys and creates the route table with that key-value pair. All other duplicate keys are ignored. Because of that, the corresponding virtual service is created with the same key-value pair that was added to the route table.
  • If you have a delegated route table setup, annotations can be added only to parent route tables. When you add the annotation to a child or grandchild route table, the annotation is ignored and a warning is added to the status of the child or grandchild route table.

To add annotations via a route table:

  1. Create a route table with the cluster.solo.io/cluster: mycluster annotation to verify that you cannot create a conflicting annotation. This annotation is automatically added by Gloo Mesh Enterprise when the route table is translated into an Istio virtual service. Although you can create the route table, the annotation is not added to the translated virtual service.

      kubectl apply -f- <<EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: RouteTable
    metadata:
      name: annotations
      namespace: bookinfo
    spec:
      hosts:
        - annotations.com
      # Selects the virtual gateway you previously created
      virtualGateways:
        - name: istio-ingressgateway
          namespace: bookinfo
      virtualServiceAnnotations: 
        cluster.solo.io/cluster: mycluster
      http:
        # Route for the main productpage app
        - name: productpage
          matchers:
          - uri:
              prefix: /productpage
          forwardTo:
            destinations:
              - ref:
                  name: productpage
                  namespace: bookinfo
                port:
                  number: 9080
    EOF
      
  2. Get the details of the route table and verify that you see a warning about the existing cluster annotation.

      kubectl get routetable annotations -n bookinfo -o yaml
      

    Example output:

      status:
      common:
        State:
          approval: WARNING
          message: '[1 WARNINGS]: skipping virtualServiceAnnotations with key cluster.solo.io/cluster
            since an annotation with this key is already present in the VirtualService
            metadata '
          observedGeneration: 1
        workspaceConditions:
          WARNING: 1
      
  3. Verify that the annotation is not added to the Istio virtual service.

    1. Get the name of the virtual service.

        kubectl get virtualservices -n gloo-mesh-gateways | grep routetable-annotations
        
    2. Get the details of the virtual service.

        kubectl get virtualservice <name> -n gloo-mesh-gateways -o yaml
        
  4. Modify the route table and add other annotations. For example, you can add an annotation to exclude a service from being managed by ExternalDNS as shown in the following example. This setup can be useful if you want to manually manage the DNS record for the ingress gateway, or integrate and manage it via a different DNS provider.

      kubectl apply -f- <<EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: RouteTable
    metadata:
      name: annotations
      namespace: bookinfo
    spec:
      hosts:
        - annotations.com
      # Selects the virtual gateway you previously created
      virtualGateways:
        - name: istio-ingressgateway
          namespace: bookinfo
      virtualServiceAnnotations: 
        external-dns.alpha.kubernetes.io/exclude: "true" 
        external-dns.alpha.kubernetes.io/ttl: "60"
      http:
        # Route for the main productpage app
        - name: productpage
          matchers:
          - uri:
              prefix: /productpage
          forwardTo:
            destinations:
              - ref:
                  name: productpage
                  namespace: bookinfo
                port:
                  number: 9080
    EOF
      
  5. Get the details of the route table and verify that it shows a status of ACCEPTED.

      kubectl get routetable annotations -n bookinfo -o yaml
      
  6. Verify that the annotations are added to the virtual service.

      kubectl get virtualservice <name> -n gloo-mesh-gateways -o yaml
      

    Example output:

      apiVersion: networking.istio.io/v1
    kind: VirtualService
    metadata:
      annotations:
        cluster.solo.io/cluster: gloo-gateway-docs-mgt
        external-dns.alpha.kubernetes.io/exclude: "true"
        external-dns.alpha.kubernetes.io/ttl: "60"
    ...
      
  7. Optional: Clean up the resources that you created in this guide.

      kubectl delete routetable annotations -n bookinfo