Kubernetes is gaining popularity as a control plane application programming interface (API), and coupling it with Crossplane further extends its usability. Kubernetes not only orchestrates and schedules containers, but also manages resources by extending the declarative APIs and adding a reconciliation process. The combination is appealing to both DevOps teams and application development teams because they can standardize their practices around similar patterns, particularly in combination with modern delivery technologies such as GitOps.

When GitOps and Kubernetes are coupled, Git repositories are treated as the source of truth, and Kubernetes controllers ensure the resource specifications described in Git match the actual state of deployed resources. While in a traditional Kubernetes ecosystem, resources come in the form of native Kubernetes objects, such as Pods. In a setting with support for the universal cloud infrastructure APIs, they can be extended to entities such as Amazon Elastic Compute Cloud (Amazon EC2).

AWS Controllers for Kubernetes (ACK) and Crossplane are examples of such enablers, extending the Kubernetes APIs to also understand and act on cloud infrastructure constructs. Crossplane is an open source Cloud Native Computing Foundation (CNCF) project released under the Apache 2.0 license which extends existing Kubernetes API and provides the ability to provision and manage cloud infrastructure. In addition to provisioning individual cloud resources, Crossplane offers a higher abstraction layer called Compositions. Compositions allow users to build opinionated templates for deploying cloud resources. For example, organizations may require certain tags to be present to all AWS resources or add specific encryption keys for all Amazon Simple Storage (S3) buckets. Platform teams can define these self-service API abstractions within Compositions and ensure that all the resources created through these Compositions meet the organization’s requirements.

Writing your first Composition and debugging can be intimidating. To help with this, we have open sourced AWS Blueprints for Crossplane. This new project aims to simplify and accelerate your journey to managing AWS resources with Crossplane example Compositions. Crossplane currently offers two providers to manage AWS resources. AWS provider and Terrajet AWS provider. We aim to create the example Compositions for each provider so that users can choose based on their requirements.

About the repository

To help you get started, we have made two methods available for you to create a new Amazon Elastic Kubernetes Service (Amazon EKS) cluster with Crossplane installed. These methods are available under the bootstrap directory within the repository. One uses eksctl, and the other uses the EKS Blueprints for Terraform. Getting started page provides step-by-step instructions to help you bootstrap Amazon EKS Cluster and configure Crossplane with both AWS providers.

The repository contains a directory called compositions. This is the main directory for this repository, and it contains example Compositions for the AWS provider and the new Terrajet AWS provider. You can leverage these Compositions to learn how to define application infrastructure declaratively.


The below example code represents a sample blueprint. Let’s look at deploying Amazon DynamoDB resource with example Compositions. Compositions allow you to define your own API which defines one or more resources specific to your use case. Crossplane provides CustomResourceDefinitions (CRDs) to achieve this.

$ kubectl get crd | grep apiextensions.crossplane.io compositeresourcedefinitions.apiextensions.crossplane.io compositionrevisions.apiextensions.crossplane.io compositions.apiextensions.crossplane.io

To define Compositions, you first define the interface using compositeresourcedefinitions.apiextensions.crossplane.io . Once a CompositeResourceDefinition (XRD) is defined, Compositions are created to provide concrete implementations for the interface. Let’s look at an example.

In the compositions/aws-provider/dynamodb directory, there is a file called definition.yaml . This XRD file defines the interface for DynamoDB table. It defines names for this Composite Resource, some useful information about this resource such as region and table name, and the schema. The schema defines types of each field, constraints, and table properties.

# cat compositions/aws-provider/dynamodb/definition.yaml
apiVersion: apiextensions.crossplane.io/v1 kind: CompositeResourceDefinition metadata: name: xdynamodbtables.awsblueprints.io spec: group: awsblueprints.io names: kind: XDynamoDBTable plural: xdynamodbtables claimNames: kind: DynamoDBTable plural: dynamodbtables connectionSecretKeys: # exposed as Kubernetes secrets - region - tableName - tableArn versions: - name: v1alpha1 schema: ...

The other files in the directory are Composition files. They provide concrete implementation for the interface defined above. Note the spec.compositeTypeRef field. This field tells Crossplane controller which interface this Composition satisfies. In this particular Composition, we define a DynamoDB table with on-demand capacity and partition key.

apiVersion: apiextensions.crossplane.io/v1 kind: Composition metadata: name: dynamo-on-demand-partition.dynamodb.awsblueprints.io labels: awsblueprints.io/provider: aws awsblueprints.io/environment: dev dynamodb.awsblueprints.io/capacity: on-demand dynamodb.awsblueprints.io/pkType: partition spec: writeConnectionSecretsToNamespace: crossplane-system compositeTypeRef: apiVersion: awsblueprints.io/v1alpha1 kind: XDynamoDBTable ...

Step 1: Deploy Compositions

To use the DynamoDB table Composition, apply the directory. It contains several implementation for the interface.

$ kubectl apply -f compositions/aws-provider/dynamodb compositeresourcedefinition.apiextensions.crossplane.io/xdynamodbtables.awsblueprints.io created composition.apiextensions.crossplane.io/dynamo-on-demand-composite.dynamodb.awsblueprints.io created composition.apiextensions.crossplane.io/dynamo-on-demand-partition.dynamodb.awsblueprints.io created composition.apiextensions.crossplane.io/dynamo-provisioned-composite-gsi.dynamodb.awsblueprints.io created composition.apiextensions.crossplane.io/dynamo-provisioned-composite.dynamodb.awsblueprints.io created composition.apiextensions.crossplane.io/dynamo-provisioned-composite-lsi.dynamodb.awsblueprints.io created

Check and make sure the XRD is ready to be used. Note the established field in the output below. The field is set to True when it is ready to be used.

$ kubectl get xrd xdynamodbtables.awsblueprints.io NAME ESTABLISHED OFFERED AGE xdynamodbtables.awsblueprints.io True True 67s

Step2: Deploy a DynamoDB example

To provision a resource using this Composition, take a look at the examples directory. It contains various examples of using Compositions available in this repository. Let’s create a table with on-demand capacity and partition key.

$ kubectl apply -f examples/aws-provider/composite-resources/dynamodb/dynamodb-on-demand-partition.yaml dynamodbtable.awsblueprints.io/test-table-on-demand-partition-key created

While you are waiting for the table to be created, take a look at the yaml file.

# cat examples/aws-provider/composite-resources/dynamodb/dynamodb-on-demand-partition.yaml apiVersion: awsblueprints.io/v1alpha1 kind: DynamoDBTable
metadata: name: test-table-on-demand-partition-key namespace: default
spec: compositionSelector: matchLabels: awsblueprints.io/provider: aws awsblueprints.io/environment: dev dynamodb.awsblueprints.io/capacity: on-demand dynamodb.awsblueprints.io/pkType: partition writeConnectionSecretToRef: name: test-table-on-demand-partition-key resourceConfig: providerConfigName: default region: us-west-2 tags: - key: env value: test - key: anotherKey value: anotherValue tableIndex: hashKeyName: hashKey hashKeyType: S

kind and apiVersion were set according to the spec.apiGroup, spec.claimNames.kind fields in the definition.yaml file.

Notice the spec.compositionSelector.matchLabels field. This field tells Crossplane which Composition you want to use. The DynamoDB Composition directory contains multiple implementations for the interface defined in the definition.yaml file. An implementation may be for a table with composite primary key, while another implementation maybe for a table with on-demand capacity. By specifying the compositionSelector field, we are asking Crossplane to create a DynamoDB table with a specific configuration.

Check the status of table. It should become available after a few minutes.

$ kubectl get dynamodbtable.awsblueprints.io/test-table-on-demand-partition-key NAME READY CONNECTION-SECRET AGE test-table-on-demand-partition-key False test-table-on-demand-partition-key 56s $ kubectl describe dynamodbtable.awsblueprints.io/test-table-on-demand-partition-key ... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning ConfigureCompositeResource 112s (x2 over 113s) offered/compositeresourcedefinition.apiextensions.crossplane.io cannot apply composite resource: cannot patch object: Operation cannot be fulfilled on xdynamodbtables.awsblueprints.io "test-table-on-demand-partition-key-q6nng": the object has been modified; please apply your changes to the latest version and try again Normal BindCompositeResource 111s (x4 over 113s) offered/compositeresourcedefinition.apiextensions.crossplane.io Composite resource is not yet ready Normal PropagateConnectionSecret 11s offered/compositeresourcedefinition.apiextensions.crossplane.io Successfully propagated connection details from composite resource Normal ConfigureCompositeResource 10s (x6 over 113s) offered/compositeresourcedefinition.apiextensions.crossplane.io Successfully applied composite resource Normal BindCompositeResource 10s (x2 over 11s) offered/compositeresourcedefinition.apiextensions.crossplane.io Successfully bound composite resource $ aws dynamodb list-tables { "TableNames": [ "test-table-on-demand-partition-key-q6nng-nwzqb" ] }

Clean up

When finished with this exercise, please clean up using the commands below. These commands will remove the table resources, Compositions, XRDs, and the EKS cluster from your account.

# Remove claim: $ kubectl delete -f examples/aws-provider/composite-resources/dynamodb/dynamodb-on-demand-partition.yaml # Remove compositions and XRDs: $ kubectl delete -f compositions/aws-provider/dynamodb # Remove cluster (eksctl) $ eksctl delete cluster -f eksctl.yaml # Remove cluster (terraform) $ terraform destroy --auto-approve


This tour of the repository is just the beginning. There are more complex examples, such as nested Compositions, available for you to explore. If you would like to become more familiar with Crossplane, check out the Crossplane documentation. To learn more about the inner workings of Crossplane, check out these blog posts. The Crossplane AWS Blueprints project is evolving and we are adding more blueprints. We also want to grow our base of contributors, so if you would like more blueprints for other AWS services or if you have ideas to share, please reach out on the Crossplane AWS Blueprints GitHub. Crossplane and this repository are open source projects, and our community is growing. Join us on Slack and GitHub if you would like to contribute.