Knative Serving 0.7


As you might have heard, Knative 0.7 was out last week. One of the notable changes in this release is that Knative Serving API progressed from v1alpha to v1beta. While you can still use the old v1alpha1 API, if you want to update to v1beta, you need to rewrite your Knative service definition files. The new API also allows named revisions, silent latest deploys and a better traffic splitting configuration. In this post, I want to outline some of these changes.

More compact service definition

In previous version of Knative, if you wanted to deploy a simple Knative service and route 100% traffic to it, you had to use runLatest block as follows:

apiVersion: serving.knative.dev/v1alpha1  
kind: Service  
metadata:  
  name: helloworld  
  namespace: default  
spec:  
  runLatest:  
    configuration:  
      revisionTemplate:  
        spec:  
          container:  
            image: docker.io/meteatamel/helloworld:v1  
            env:  
              - name: TARGET  
                value: "v1"

In the new version, the same service definition looks like this:

apiVersion: serving.knative.dev/v1beta1  
kind: Service  
metadata:  
  name: helloworld  
  namespace: default  
spec:  
  template:  
    spec:  
      containers:  
        - image: docker.io/meteatamel/helloworld:v1  
          env:  
            - name: TARGET  
              value: "v1"

Notice that there’s no runLatest or configuration and revisionTemplate is simply called template now. This allows a more compact service definition file.

Named revisions

In the previous version, when you deployed a change to your Knative Service, you’d get random revision numbers like this:

$ kubectl get revision

NAME
revision.serving.knative.dev/helloworld-c4pmt
revision.serving.knative.dev/helloworld-vkvjt

This is usually OK but made traffic splitting configuration a little cumbersome (more on this later).

In the new version, you still get random revision numbers by default but you can also give your revisions a predictable name. For example, take a look at this service definition file with a revision name:

apiVersion: serving.knative.dev/v1beta1  
kind: Service  
metadata:  
  name: helloworld  
  namespace: default  
spec:  
  template:  
    metadata:  
      name: helloworld-v1  
    spec:  
      containers:  
        - image: docker.io/meteatamel/helloworld:v1  
          env:  
            - name: TARGET  
              value: "v1"  
  traffic:  
  - tag: current  
    **revisionName: helloworld-v1**  
    percent: 100  
  - tag: latest  
    latestRevision: true  
    percent: 0

When you deploy, you get the revision name you specified:

$ kubectl get revision  
  
NAME               SERVICE NAME       GENERATION  
helloworld-f4xvr   helloworld-f4xvr   2           
helloworld-ln8rv   helloworld-ln8rv   3           
**helloworld-v1      helloworld-v1      4 **          
helloworld-z9clz   helloworld-z9clz   1

Ability to deploy latest revision silently

In the previous example, you probably noticed the latest configuration:

traffic:  
  - tag: current  
    revisionName: helloworld-v1  
    percent: 100  
 **- tag: latest  
    latestRevision: true  
    percent: 0**

When you deploy service, it will deploy the latest revision (under a randomly named revision id) but helloworld-v1 will be the one getting all the traffic. In other words, you silently deployed the latest revision. The main url [http://helloworld.default.example.com](http://helloworld.default.example.com) will point to helloworld-v1 revision but you can also access the latest revision under [http://latest-helloworld.default.example.com](http://latest-helloworld.default.example.com%29)

This is useful if you want to deploy some code and test it out before rolling out to users.

More robust traffic splitting configuration

In the previous version of Knative, when you wanted to split traffic between current and candidate revisions, you had to do create a release and define a rollout percentage, something like this:

apiVersion: serving.knative.dev/v1alpha1  
kind: Service  
metadata:  
  name: helloworld  
  namespace: default  
spec:  
  release:  
    # First revision is traffic target "current"  
    # Second revision is traffic target "candidate"  
    revisions: \["helloworld-xyzss", "helloworld-zyxss"\]  
    rolloutPercent: 20 # 20% traffic to route to "candidate"  
    configuration:  
      revisionTemplate:  
        spec:  
          container:  
            image: docker.io/meteatamel/helloworld:v1  
            env:  
              - name: TARGET  
                value: "v4"

This was problematic because the candidate revision id was not known before the initial deployment. You had to apply this configuration to get the candidate version deployed, get the random revision id for the deployed candidate revision and do another deploy again with that revision id to apply traffic splitting. Not ideal.

In the latest version of Knative, you can use named revisions in traffic splitting:

apiVersion: serving.knative.dev/v1beta1  
kind: Service  
metadata:  
  name: helloworld  
  namespace: default  
spec:  
  template:  
    metadata:  
      name: helloworld-v4  
    spec:  
      containers:  
        - image: docker.io/meteatamel/helloworld:v1  
          env:  
            - name: TARGET  
              value: "v4"  
  traffic:  
  - tag: current  
    **revisionName: helloworld-v1**  
    percent: 50  
  - tag: candidate  
    **revisionName: helloworld-v4**  
    percent: 50  
  - tag: latest  
    latestRevision: true  
    percent: 0

This is definitely less cumbersome and more clear way of defining traffic splitting.

That’s all I wanted to cover with Knative Serving 0.7. If you want to try out Knative 0.7, I tested and updated my Knative Tutorial with 0.7 instructions, so check it out.


See also