Promoting CompositionRevisions to v1beta1

In the upcoming Crossplane v1.11.0, we are announcing the beta release of the CompositionRevision feature. It provides a way to track changes to Compositions and create Composite Resources (XRs) with different revisions. It was introduced as an alpha feature in v1.4.0 and has been under active use by the community since then. Please have a look at the design document and the guide for more details. We are excited to announce that we have reached a milestone and look forward to hearing your feedback.

While promoting this feature to beta, we fixed several bugs and made some changes to the behavior of the feature, like how we decided to create a new CompositionRevision or what happens when we roll back to a previous one. This blog post will explain the differences and how they improve the experience of using CompositionRevisions.

What is CompositionRevision, and how is it used?

A Composition is a mutable resource that can be updated over time, whereas CompositionRevision is a snapshot of a Composition at a particular time. This means there is a one-to-many relationship between Compositions and CompositionRevisions. When we create an XR, we can specify which CompositionRevision to use with the compositionRef field. If the compositionRef is not specified, the controller automatically sets the latest revision of the Composition.

The CompositionRevision used by an XR can be updated automatically. This is controlled by the compositionUpdatePolicy field of the XR, which is set to Automatic by default. In this case, whenever a CompositionRevision is created, the XR is updated to use the latest revision. If we want to disable this behavior, we can set the compositionUpdatePolicy to Manual.

How are CompositionRevisions created?

CompositionRevisions are created automatically when a Composition is created or updated. To decide whether to create a new revision or roll back to a previous one, the composition controller calculates the hash of the Composition and compares it with the hashes of previous revisions. If the hash is different, a new revision is created. If the hash is the same as one of the existing revisions, the Composition is rolled back to that revision, and the revision number is incremented.

During the alpha release, only the Composition spec was included in the hash calculation. Now, we start to include the Composition labels and annotations. This change makes it possible to have two different revisions of the same Composition without a spec update. We also started to propagate Composition labels to CompositionRevisions during creation time. Together with these two changes, we can utilize a new feature called CompositionRevision Selectors.

CompositionRevision Selectors

One of the most significant changes in this release is the introduction of the CompositionRevisionSelector field to XR spec. This field can be used with CompositionUpdatePolicy: Automatic to enable channel-based deployments. When this field is set, the XR will be created with the latest Composition revision that matches the selector. This is useful when we want to deploy the latest revision of a Composition to a particular environment. For example, we can update the Composition's spec with the channel: staging label and do some sanity checks. After successful testing, we can update the label to channel: prod and deploy the latest revision to production.

How to use CompositionRevisions

As a beta feature, CompositionRevisions are enabled by default unless they are disabled by the
--enable-composition-revisions=false flag. It is not recommended to interact with CompositionRevisions directly, and all changes should be done on Compositions, including marking a specific composition state with a label.

In the following example, we have a Composition that provisions a Kubernetes cluster. Our Platform Engineer maintains two different release channels for application developers, rapid and stable. The rapid channel is updated with the latest k8s version, whereas the stable channel is updated less frequently and is used in production environments. To achieve this, we switch between the channel: rapid and channel: stable labels while updating the k8sVersion field
on the Composition. Since the Crossplane pod propagates the labels from Composition to CompositionRevision during creation, we can use this label to select the desired channel.



When Application Developers want to create a Kubernetes cluster to test a new feature, they can create an XR with channel: rapid and test it with the latest k8s version. At the same time, they can create an XR with a channel: stable label to reproduce a bug in production. A CompositionRevision will be chosen based on the label selector in the XR spec. If the selector is not set, the latest revision, which is indicated by the largest revision number, will be used. The application developer creates two XRs with different matchLabels in the following example. Therefore, we end up having two different Kubernetes clusters with different k8s versions.


When a new k8s patch version is released, the Platform Engineer can update the Composition with the channel: rapid label. Once this change is done, the XR with channel: rapid will be updated automatically to use the new k8s version, whereas the XR with channel: stable will continue to use the stable version.



We are excited to announce the beta release of CompositionRevisions. This feature will help users to manage their Compositions and XRs safely and reliably. There is a tutorial with example manifests showing how to use CompositionRevisions in the Crossplane docs, which installs the latest version of Crossplane with the following commands:

kubectl create namespace crossplane-system
helm repo add crossplane-master
helm repo update
helm install crossplane -n crossplane-system crossplane-master/crossplane --devel --version 1.11.0-rc.0.101.gc4fb2315

We would love to hear your feedback on this feature. Please feel free to play with it, and let us know if you have any feedback or questions. You can reach us via Slack.

Keep up with Upbound

* indicates required