TAP 1.5 – Dynamic Service Provisioning With Crossplane

What Is Crossplane

Crossplane is an open source, CNCF project built on the foundation of Kubernetes to orchestrate anything.

Its basically the kubernetes native approach to solve similar issues and challenges that tools like Terraform, Pulumi and IDEM are trying to solve.

Tanzu Application Platform makes use of Crossplane to power a number of capabilities, such as dynamic provisioning of services instances with Services Toolkit as well as the out of the box Bitnami Services.

What Is Dynamic Service Provisioning

One of the strong capabilities in TAP, is the ability to easily bind a workload to backing services like databases or message brokers.

The issue that has existed till now in TAP, is that the provisioning of these services was a manual process, where there was no self service element in play.

This required the Service Operators such as DBAs or dedicated experts in specific services, to be involved in the process of deploying a service, before the application operator could then claim that service, and then, the developer could utilize that claim in their own workload.

While the APIs have been there for the developer to easily bind to a service, all of the manual steps needed to get to that point, was a major stumbling block for many, causing delays in development, and made it so our developers were not truly self sufficient.

Now it is important to note, this is not a trivial issue to solve, and nearly all platforms on the market have this the of issue, and now as of TAP 1.5, VMware have added in some amazing features, which allow us to easily and securely offer self service capabilities to our end users, to provision and lifecycle manage their applications backing services, without needing all of the manual toil.

The idea with dynamic service provisioning, is that a service operator, can define via a Crossplane XRD and composition (just a bunch of YAML), a service they want to provide. they can define what fields a user can change, and which ones they can’t change. they can set validations on values, and really any constraints that they want, which are defined in a simple OpenAPIv3 Schema within the service definition.

Once the service operator has defined these services they want to offer in the cluster to the end users, a developer can simply claim a new instance of that service, and provide the parameters he wants to set (which the service operator defined for him), and the platform will automatically provision a new instance of that service, and create the needed configurations for the TAP workloads to seamlessly bind to the services, just like they would till TAP 1.5, using the Service Bindings for Kubernetes Spec.

Bitnami Services

Out of the box, TAP 1.5 comes with a few very common services packaged as Crossplane compositions and XRDs, for Bitnami helm charts.

The included services are:

  • RabbitMQ
  • PostgreSQL
  • MySQL
  • Redis

While this in it of itself is great, VMware have taken it a step further, and via a few values in your TAP values file, you can configure these compositions to instead of deploying the OSS Bitnami helm charts, deploy VMware Application Catalog based helm charts, as long as you have a VAC subscription and that you provide the needed credentials to make it work.

These services, are probably the most common backing services today in the kubernetes ecosystem, and as such it is great to see them being included out of the box in TAP!

Building Your Own Services

Building your own services based on Crossplane can seem quite overwhelming at the beginning, but once you get a hold of it, its truly easy to do.

Similar to all tools in this area, such as Helm, YTT, Terraform etc., the learning curve is indeed a hurdle one must cross, but once you do, the options are endless, and the value is huge!

Another great feature in TAP 1.5 is the GitOps installation flow, and you can see in my Sample GitOps Repo where I defined my entire TAP installation, I have put together a few examples of custom services including:

  • RabbitMQ Operator based cluster
  • VMware PostgreSQL Operator based clusters
  • VMware MySQL Operator based clusters
  • MongoDB using the Bitnami OSS Helm chart
  • Kafka using the Bitnami OSS Helm chart
  • Microsoft SQL Server using raw kubernetes YAML and the official SQL Server image from Microsoft.

What does the new experience look like for a developer

The first step they would do is see what classes of services are available to them:

$ tanzu services classes list

This will return an output similar to:

  NAME                  DESCRIPTION
  kafka-unmanaged       Kafka by Bitnami
  mongodb-unmanaged     MongoDB by Bitnami
  mysql                 MySQL
  mysql-unmanaged       MySQL by Bitnami
  postgresql            PostgreSQL
  postgresql-unmanaged  PostgreSQL by Bitnami
  rabbitmq              RabbitMQ
  rabbitmq-unmanaged    RabbitMQ by Bitnami
  redis-unmanaged       Redis by Bitnami
  sqlserver-unmanaged   SQL Server by TeraSky

Then the developer can see what parameters were exposed to him for a specific service for example:

$ tanzu services classes get postgresql-unmanaged

Which will return output like the following:

NAME:           postgresql-unmanaged
DESCRIPTION:    PostgreSQL by Bitnami
READY:          true

  KEY        DESCRIPTION                               TYPE     DEFAULT  REQUIRED
  storageGB  The desired storage capacity in GB.       integer  1        false

As we can see, one parameter has been exposed to the developer, where they can set the amount of storage they want allocated to the database.

If the developer wants to now deploy a database with 20 GB of storage for example he simply runs a command like the following:

$ tanzu services class-claim create my-db --class postgresql-unmanaged \
    --parameter storageGB=20

which will return output similar to the following:

Creating claim 'my-db' in namespace 'test-01'.
Please run `tanzu services class-claims get my-db --namespace test-01` to see the progress of create.

And now if the developer runs the command suggested in the output they can see the status of the provisioning, which will look similar to:

Name: my-db
Namespace: test-01
Claim Reference: services.apps.tanzu.vmware.com/v1alpha1:ClassClaim:my-db
Class Reference:
  Name: postgresql-unmanaged
  Ready: True
  Claimed Resource:
    Name: 98ec8a57-7c2a-405e-82fc-9102dc6c0717
    Namespace: test-01
    Version: v1
    Kind: Secret

This shows them all the needed info in order to simply now bind this service to there workload either via the CLI using the –service-ref flag or by adding in a serviceClaims section to their workload YAML pointing at the class claim resource that was created. An example of the imperative command mechanism would look like:

$ tanzu apps workload create -f config/workload.yaml --service-ref db=services.apps.tanzu.vmware.com/v1alpha1:ClassClaim:my-db

And the declarative YAML configuration would look like:

  - name: db
      apiVersion: services.apps.tanzu.vmware.com/v1alpha1
      kind: ClassClaim
      name: my-db

This simple user experience, is extremely powerful, and provides an unprecedented UX for developers, while finding the right balance between developer autonomy and platform and operational needs and concerns.


The new dynamic provisioning functionality is a true game changer in terms of Developer experience, and helps platform teams truly meet their goal of being enablers for the business and not being stumbling blocks in the way to production.

The integration with crossplane is a great choice in my opinion, and I am truly excited to see how this integration deepens and grows over future releases.

Leave a Reply