How to set a routing rule between two versions of the same app in Istio?
Published: 2021-09-07 17:49:48

With Istio, a lot of tools are available to help us to easily set routing rules. And today, we will use them to set a routing rule to be able to use two versions of the same app.

---

# Prerequisite
First we need to be able to distinct both version of the app.

## Distinct services
If both version of the app has a specific service to expose it, it's ok we can go further.

## Same service
Otherwise, if they are using the same service, we need to add something to be able to distinct them.

Here, we will use a [Destination Rule](https://istio.io/v1.1/docs/reference/config/networking/v1alpha3/destination-rule/). With it, we will say that for our service *(here defined in the host element)*, we have multiple subgroups *(subnets)*.

```yaml
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: my-api
spec:
  host: my-api.default.svc.cluster.local
  trafficPolicy:
    loadBalancer:
      simple: ROUND_ROBIN
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
```

In this example, we have 2 subgroups:
- **v1** with are all the pods of my-api with the label **version: v1**
- **v2** with are all the pods of my-api with the label **version: v2**

---

# Definition of the routing rule
Now that we are able to distinct our versions, we can define the routing rule with a [VirtualService](https://istio.io/v1.1/docs/reference/config/networking/v1alpha3/virtual-service/). 

## URI
First, we can create the rule to redirect traffic depending the URI.

```yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: my-api
  namespace: default
spec:
  hosts:
    - my-api.default.svc.cluster.local
  http:
    - match:
        - uri:
            prefix: "/v1"
      route:
        - destination:
            host: my-api.default.svc.cluster.local
            subnet: v1
    - route:
        - destination:
            host: my-api.default.svc.cluster.local
            subnet: v2
```

In this example, if the uri starts with "/v1" the traffic is redirected to the subnet **v1**. Otherwise, it goes to the **v2**.

> **IMPORTANT: The subnets values here must match to the subnets names defined in the DestinationRule.**

---

## Header

Then, we can update the VirtualService to change the condition and use a header instead.

```yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: my-api
  namespace: default
spec:
  hosts:
    - my-api.default.svc.cluster.local
  http:
    - match:
        - headers:
            version:
              exact: V1
      route:
        - destination:
            host: my-api.default.svc.cluster.local
            subnet: v1
    - route:
        - destination:
            host: my-api.default.svc.cluster.local
            subnet: v2
```
With just this little change, we can redirect traffic to the **v1** subnet with only a header.

---

# Links
- Istio - DestinationRule : https://istio.io/v1.1/docs/reference/config/networking/v1alpha3/destination-rule/
- Istio - VirtualService : https://istio.io/v1.1/docs/reference/config/networking/v1alpha3/virtual-service/
- Istio - Example of a request routing : https://istio.io/latest/docs/tasks/traffic-management/request-routing/

---

If you want to go further, all the links are here to see all the options available as :
- use an exact uri
- use a regex for the uri
- use a regex for the header
- add some retries
- ...

I hope you enjoyed it and it will be helpful! 🍺