Skip to main content
Version: 0.9.x

Application Onboarding and canary release

This document describes a basic workflow for onboarding an application into TSB to perform a basic canary release of a service directing traffic progressively to a new version of it.

Initial application onboarding

An application in TSB maps to a set of services deployed across one or many Kubernetes namespaces. The first step then is to get your application deployed into a Kubernetes namespace which we won't be covering here as that is just following your regular deployment strategy in Kubernetes.

Istio injection

Application services need Istio sidecar to be present. You can label the namespace with the istio-injection=enabled label to get sidecars injected automatically.

Assuming you have the above in place, the next step is to create an application in TSB mapping to your application namespace.

Via API

The API call that will help here is the create application call.

curl --request POST \
-u admin \
--url https://${TCCIP}/v1/tenants/tenant/environments/dev/applications \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data -<<EOF
{
"id": "bookinfo",
"namespaces": [
"bookinfo-ns"
],
"forceMtlsBetweenServices": true
}
EOF

The above creates an application in TSB named bookinfo which is composed of the services deployed in the bookinfo-ns namespace. Additionally, setting the forceMtlsBetweenServices parameter to true causes mTLS to be enforced in communications across all services in the namespace.

Via UI

Log into TSB UI, navigate to Applications in the navigation bar on the left side. You will see the list of applications. Click in the + sign next to the Applications title.

You will see the create application form where you will need to input the application name as well as the list of namespaces conforming it. After you are done, click the Create application button.

Should you want to enable mTLS in the namespace via the UI, you will need to navigate Applications, enter your application by clicking in its name, then navigate to the Reliability settings tab and toggle the Disallow non-mTLS connections between services switch to be activated.

That is it. After creating the application, TSB will sync all services in the namespace automatically.

Canary release

The bookinfo application includes a service called reviews which has multiple versions. When deploying this application without further customization, the Kubernetes service will load balance between all instances (pods).

We will start updating the reviews service making all traffic to reach the pods with label version=v1. We will also set a route that will direct traffic to the pods with label version=v2 if the request has a given header.

Via API

First, we will need to retrieve the service:

curl --request GET \
--url https://${TCCIP}/v1/tenants/tenant/environments/dev/applications/bookinfo/services/reviews \
--header 'accept: application/json' > /tmp/reviews.json

Now we need to update the JSON object to reflect the route changes.

We are going to update the service JSON response and add a first level subsets key in the JSON object so we can route traffic based on these subsets. Also, we will need to update the routing rules in the service so traffic goes to v1 only except if the request includes a header named X-Release-Version with value v2, then we will route the request to the v2 subset.

jq '.subsets = [
{
"labels": {
"version": "v1"
},
"name": "v1"
},
{
"labels": {
"version": "v2"
},
"name": "v2"
}
] | .internalRoutes.httpSettings.routeRules = [
{
"route": {
"destinations": [
{
"local": {
"application": "bookinfo",
"service": "reviews",
"subset": "v1"
},
"weight": 100,
"port": 9080
}
]
}
},
{
"match": [
{
"headers": {
"X-Release-Version": {
"exact": "v2"
}
}
}
],
"route": {
"destinations": [
{
"local": {
"application": "bookinfo",
"service": "reviews",
"subset": "v2"
},
"weight": 100,
"port": 9080
}
]
}
}
]' /tmp/reviews.json | tee /tmp/reviews-updated.json

Now we just need to update the service via API:

curl --request PUT \
-u admin \
--url https://${TSBIP}/v1/tenants/tenant/environments/dev/applications/bookinfo/services/reviews \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--d @/tmp/reviews-updated.json

Via UI

Navigate to the bookinfo application, Services tab, click in the blue link button next to the reviews service, then navigate to Route settings.

  1. Click in the + sign next to the Subsets title to add a subset. By default, the UI will create subsets based on the version label. Click again the + sign to create a second v2 subset.
  2. Save the changes so the subsets are created.
  3. Click the + sign next to the Routing rules title.
  4. For the first rule, create a new match condition by clicking the + button next to the Match Conditions title. Set attribute to Header, header name to X-Release-Version, condition to exact and value to v2. In the Route destinations set the reviews service and select the v2 subset.
  5. Create a new routing rule, this time do not set any match condition, select as route destination the reviews service and the v1 subset.

Traffic shifting to v2

Based on the previous state you'll need to, steering traffic to the v2 subset is possible by once again updating the routing rules in the service. So we will repeat what we did in the previous step, just adding a destination in the default route (the one that does not specify a match condition) to the v2 subset and setting the percentage of traffic directed to each subset as desired.

Via API

First, we will need to retrieve the service as we did before:

curl --request GET \
--url https://${TCCIP}/v1/tenants/tenant/environments/dev/applications/bookinfo/services/reviews \
--header 'accept: application/json' > /tmp/reviews.json

Now we need to update the JSON object to reflect the route changes.

In this case the subsets already exist so we need to set the route destinations as follows:

jq '.internalRoutes.httpSettings.routeRules = [
{
"route": {
"destinations": [
{
"local": {
"application": "bookinfo",
"service": "reviews",
"subset": "v1"
},
"weight": 80,
"port": 9080
},
{
"local": {
"application": "bookinfo",
"service": "reviews",
"subset": "v2"
},
"weight": 20,
"port": 9080
}
]
}
},
{
"match": [
{
"headers": {
"X-Release-Version": {
"exact": "v2"
}
}
}
],
"route": {
"destinations": [
{
"local": {
"application": "bookinfo",
"service": "reviews",
"subset": "v2"
},
"weight": 100,
"port": 9080
}
]
}
}
]' /tmp/reviews.json | tee /tmp/reviews-updated.json

We added a new destination in the default rule and changed the weight attribute in each destination to direct 80% of traffic to the v1 subset and 20% to the v2 subset. Now we just need to update the service via API:

curl --request PUT \
-u admin \
--url https://${TSBIP}/v1/tenants/tenant/environments/dev/applications/bookinfo/services/reviews \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--d @/tmp/reviews-updated.json

Via UI

Navigate to the bookinfo application, Services tab, click in the blue link button next to the reviews service, then navigate to Route settings.

  1. Expand the routing rule that has no match condition (should be rule 2 if you followed the steps above).
  2. Change the % Traffic of the existing destination rule to 80. Don't save yet.
  3. Add a new destination rule, selecting the reviews service and the v2 subset. Set the % Traffic to 20. Save the changes.

You can now repeat the steps above to progressively steer traffic to the new v2 version in gradual steps by changing the weight in each destination (% of traffic) until all traffic is directed to v2.

End-of-life for v1

At this point, with all traffic directed to the v2 subset you may want to clean up the v1 subset and the routes that direct traffic to it.

Via API

Again, we will need to retrieve the service:

curl --request GET \
--url https://${TCCIP}/v1/tenants/tenant/environments/dev/applications/bookinfo/services/reviews \
--header 'accept: application/json' > /tmp/reviews.json

Now we need to update the JSON object to remove the v1 subset and the route destination with weight 0 for it. We are also going to remove the route that routed traffic to the v2 service based on request header as it will have the same effect as the default route now.

jq '.subsets = [
{
"labels": {
"version": "v2"
},
"name": "v2"
}
] | .internalRoutes.httpSettings.routeRules = [
{
"route": {
"destinations": [
{
"local": {
"application": "bookinfo",
"service": "reviews",
"subset": "v2"
},
"weight": 100,
"port": 9080
}
]
}
}
]' /tmp/reviews.json | tee /tmp/reviews-updated.json

Now we just need to update the service via API:

curl --request PUT \
-u admin \
--url https://${TSBIP}/v1/tenants/tenant/environments/dev/applications/bookinfo/services/reviews \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--d @/tmp/reviews-updated.json

Via UI

Navigate to the bookinfo application, Services tab, click in the blue link button next to the reviews service, then navigate to Route settings.

  1. Click in the + sign next to the Subsets title to add a subset. By default, the UI will create subsets based on the version label. Click again the + sign to create a second v2 subset.
  2. Click the red x button for the subset v1. Do not save yet.
  3. Click the red x button for the first destination rule, the one that routes based on the request header. Do not save yet.
  4. In the remaining destination rule, delete the one that targets subset v1 which has a % Traffic of 0.
  5. Save changes