Knative journey EP4: route incoming requests to different Knative revisions in clear logic guaranteed

Vincent Hou
6 min readMay 23, 2019

Please make sure you have gone through my previous episodes, and grasped a general idea how Knative works together with IBM cloud. After I searched plenty of examples for Knative revisions and routes, and tried out them one by one, I have found out that it is my turn to re-narrate this classic example for Knative serving again, with clear logic guaranteed. For folks, who touch on Knative for the first time, this article is the one, you should not miss.

The revision in Knative makes it possible to deploy the same service with multiple versions. Revision only makes sense for the same service. What constitutes the same service? The criterion is that they all share the same “metadata.name and metadata.namespace”(There can be something else, but just list the important ones so far). I know it is simple, but do keep it in mind. For example, you did “kubectl apply” command on one yaml file for the first time, then changed the “metadata.name” for that service into another name. When you issued “kubectl apply” to the the same yaml file, it would create a different service without revision meddling, though these two services behaved the same like twins. On the other end, if you changed everything of the yaml files, except the lines of metadata.name, metadata.namespace and the kind, you would create just a new revision for the same service, though the first revision could be an application fond of one party, and the second revision rooted for the opponent. They are still both the same service.

I hope you have your Knative environment set up already, and your terminal connects to the Kubernetes cluster. If not, please follow my previous EP1, and EP2, to start your journey. Currently I am using Knative version 0.6 in the Kubernetes cluster to walk through the following steps. IBM cloud has not supported 0.6 yet. My previous article EP3 can tell you how to install Knative from source code and keep your version up-to-date.

Create the service

Let’s go with the easiest Hello World example. Create a yaml file called service.yaml with the following contents:

apiVersio: serving.knative.dev/v1alpha1
kind: Service
metadata:
name: hello-knative
namespace: default
spec:
template:
metadata:
name: hello-knative-first
spec:
containers:
- image: gcr.io/knative-samples/helloworld-go
env:
- name: TARGET
value: "Knative 1"

The field spec.template.metadata.name specifies the revision name to be created. This feature exists in Knative version 0.6 and later.

To be clear, try to clean up your environment if necessary by running:

kubectl delete -f service.yaml

We need to make sure this service do not exist. Then install the service by running:

kubectl apply -f service.yaml

You can check the pods with the command:

kubectl get pods

As you see I have done a new pod named “hello-knative-4vzvh-deployment-7884458cf5-khwks” running. Your will have a different name, but starting with hello-knative.

Check the configuration with the command:

kubectl get configuration

If you want to see more detailed information, add “-oyaml” to the end of the previous command:

kubectl get configuration -oyaml

As you see close to the bottom, the latestReadyRevisionName and latestCreatedRevisionName both points to the revision “hello-knative-first” I have just created. The Ready status is true, meaning this service is running.

Let’s verify the revision with the command:

kubectl get revision

No surprise that the revision name is “hello-knative-first” as specified, and we have got one revision for hello-knative.

Check the detailed information of the revision:

kubectl get revision -oyaml

Just paste part of the snapshot, that is useful:

If you go with the above commands, you will end up with a different revision name for the service. Like in my environment, it is “hello-knative-first”. Save it, we will refer to it as hello-knative-<revision 1>.

Create second revision and split the traffic

Let’s create the second revision for this service. Create another yaml file called service_second.yaml with the following contents:

apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
name: hello-knative
namespace: default
spec:
template:
metadata:
name: hello-knative-second
spec:
containers:
- image: gcr.io/knative-samples/helloworld-go
env:
- name: TARGET
value: "Knative 2"
traffic
:
- tag: current
revisionName: hello-knative-first
percent: 50
- tag: candidate
revisionName: hello-knative-second
percent: 50
- tag: latest
latestRevision: true
percent: 0

We should change something in this yaml file comparing to service.yaml, but without changing the metadata.name, metadata.namespace, or kind. As you notice, I change the value for TARGET variable into “Knative 2”. All right, you may ask what if I “kubectl apply” the same file for the second time? Here is the bonus: it will tell you “service.serving.knative.dev/hello-knative unchanged” for this example. All the other articles you can find online will tell you the next thing you need to do is to issue “kubectl apply” on a yaml file with the release revision and release rolloutPercent to spit the traffic, like the following:

spec:
release:
# Ordered list of 1 or 2 revisions.
# First revision is traffic target "current"
# Second revision is traffic target "candidate"
revisions: ["hello-test-00001", "hello-test-00002"]
rolloutPercent: 50

Forget about them, since they are still running on old versions, which does not support custom revision name. As you see, you will create the second version as hello-knative-second, and the traffic will be divided 50–50 between these two revisions. OK, let’s run the command:

kubectl apply -f service_second.yaml

If you check the pod and the configuration, we will see the there is still one pod and one configuration for hello-knative service, but the suffix of the name has been changed.

Let’s take a look at the revision by running:

kubectl get revision

Now, we have got two revisions. For my case hello-knative-<revision 2> is hello-knative-second, and hello-knative-<revision 1> is hello-knative-first.

We check the route with the command:

kubectl get route

As you see the service is up and running, but it has no traffic information regarding revisions. Check the detailed information with the command:

kubectl get route -oyaml

As you can see in status.traffic about how the traffic is divided. OK, 50–50 split into two revisions.

We can test the result by sending 10 requests to the URL to see how the revision is called:

for run in {1..10}
do
curl http://<domain_url>
done

How to check the <domain_url> for your service? Run the command:

kubectl get ksvc

The <domain_url> for my service is “hello-knative-default.knative-cluster.us-east.containers.appdomain.cloud”.

After running the test, I received:

It is a perfect 50 versus 50. I hope you have no confusion generated for revisions and traffic splitting of Knative, after reading this episode.

Follow Vincent, (and) you won’t derail!

--

--

Vincent Hou

A Chinese software engineer, used to study in Belgium and currently working in US, as Knative & Tekton Operator Lead and Istio Operator Contributor.