🎉 Crossplane Community Day Europe - May 4th, 2021

Schedule is now live and Registration is Open!

Documentation

PLEASE NOTE: This document applies to v0.13 version and not to the latest release v1.1

Documentation for other releases can be found by using the version selector in the top right of any doc page.

Compose Infrastructure

In the last section we learned that Crossplane can be extended by installing providers, which add support for managed resources. A managed resource is a Kubernetes custom resource that offers a high fidelity representation of an infrastructure primitive, like an SQL instance or a firewall rule. Crossplane goes beyond simply modelling infrastructure primitives as custom resources - it enables you to define new custom resources with schemas of your choosing. These resources are composed of managed resources, allowing you to define and offer resources that group and abstract infrastructure primitives. We call these “composite resources” (XRs).

XRs are always cluster scoped - they exist outside of any namespace. This allows an XR to represent infrastructure that might be consumed from several different namespaces. This is often true for VPC networks - an infrastructure operator may wish to define a VPC network XR and an SQL instance XR, only the latter of which may be managed by application operators. The application operators are restricted to their team’s namespace, but their SQL instances should all be attached to the VPC network that the infrastructure operator manages. Crossplane enables scenarios like this by allowing the infrastructure operator to offer their application operators a composite resource claim (XRC). An XRC is a namespaced proxy for an XR; the schema of an XRC is identical to that of its corresponding XR. When an application operator creates an XRC, a corresponding backing XR is created automatically.

We use two special Crossplane resources to define and configure new XRs and XRCs:

XRDs and Compositions may be packaged and installed as a configuration. A configuration is a package of composition configuration that can easily be installed to Crossplane by creating a declarative Configuration resource, or by using kubectl crossplane install configuration. In the examples below we will install a configuration that defines a new CompositePostgreSQLInstance XR that takes a single storageGB parameter, and creates a connection Secret with keys for username, password, and endpoint. A Configuration exists for each provider that can satisfy a PostgreSQLInstance. Let’s get started!

Configure and Claim Your Infrastructure

We will now install a Configuration that:


Note that this configuration will create an RDS instance using your default VPC, which may or may not allow connections from the internet depending on how it is configured. Select the AWS (New VPC) configuration if you wish to create an RDS instance that will allow traffic from the internet.

kubectl crossplane install configuration crossplane/getting-started-with-aws:v0.13

Note that this configuration for AWS also includes several networking managed resources that are required to provision a publicly available PostgreSQL instance. Composition enables scenarios such as this, as well as far more complex ones. See the composition documentation for more information.

kubectl crossplane install configuration crossplane/getting-started-with-aws-with-vpc:v0.13
kubectl crossplane install configuration crossplane/getting-started-with-gcp:v0.13
kubectl crossplane install configuration crossplane/getting-started-with-azure:v0.13
kubectl crossplane install configuration crossplane/getting-started-with-alibaba:v0.13

Crossplane should now be configured to allow us to create a PostgreSQLInstance claim! You can make sure your Configuration installed successfully by running:

kubectl describe configuration

Make sure you’ve setup a ProviderConfig named default for your chosen provider, then create your XRC to provision a PostgreSQL instance and all the supporting infrastructure (VPCs, firewall rules, resource groups, etc) that it may need!


apiVersion: database.example.org/v1alpha1
kind: PostgreSQLInstance
metadata:
  name: my-db
  namespace: default
spec:
  parameters:
    storageGB: 20
  compositionSelector:
    matchLabels:
      provider: aws
      vpc: default
  writeConnectionSecretToRef:
    name: db-conn
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-0.13/docs/snippets/compose/claim-aws.yaml
apiVersion: database.example.org/v1alpha1
kind: PostgreSQLInstance
metadata:
  name: my-db
  namespace: default
spec:
  parameters:
    storageGB: 20
  compositionSelector:
    matchLabels:
      provider: aws
      vpc: new
  writeConnectionSecretToRef:
    name: db-conn
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-0.13/docs/snippets/compose/claim-aws.yaml
apiVersion: database.example.org/v1alpha1
kind: PostgreSQLInstance
metadata:
  name: my-db
  namespace: default
spec:
  parameters:
    storageGB: 20
  compositionSelector:
    matchLabels:
      provider: gcp
  writeConnectionSecretToRef:
    name: db-conn
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-0.13/docs/snippets/compose/claim-gcp.yaml
apiVersion: database.example.org/v1alpha1
kind: PostgreSQLInstance
metadata:
  name: my-db
  namespace: default
spec:
  parameters:
    storageGB: 20
  compositionSelector:
    matchLabels:
      provider: azure
  writeConnectionSecretToRef:
    name: db-conn
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-0.13/docs/snippets/compose/claim-azure.yaml
apiVersion: database.example.org/v1alpha1
kind: PostgreSQLInstance
metadata:
  name: my-db
  namespace: default
spec:
  parameters:
    storageGB: 20
  compositionSelector:
    matchLabels:
      provider: alibaba
  writeConnectionSecretToRef:
    name: db-conn
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-0.13/docs/snippets/compose/claim-alibaba.yaml

After creating the PostgreSQLInstance Crossplane will begin provisioning a database instance on your provider of choice. Once provisioning is complete, you should see READY: True in the output when you run:

kubectl get postgresqlinstance my-db

Note: while waiting for the PostgreSQLInstance to become ready, you may want to look at other resources in your cluster. The following commands will allow you to view groups of Crossplane resources:

  • kubectl get claim: get all resources of all claim kinds, like PostgreSQLInstance.
  • kubectl get composite: get all resources that are of composite kind, like CompositePostgreSQLInstance.
  • kubectl get managed: get all resources that represent a unit of external infrastructure.
  • kubectl get <name-of-provider>: get all resources related to <provider>.
  • kubectl get crossplane: get all resources related to Crossplane.

Try the following command to watch your provisioned resources become ready:

kubectl get crossplane -l crossplane.io/claim-name=my-db

Once your PostgreSQLInstance is ready, you should see a Secret in the default namespace named db-conn that contains keys that we defined in XRD. If they were filled by the composition, then they should appear:

$ kubectl describe secrets db-conn
Name:         db-conn
Namespace:    default
...

Type:  connection.crossplane.io/v1alpha1

Data
====
password:  27 bytes
port:      4 bytes
username:  25 bytes
endpoint:  45 bytes

Consume Your Infrastructure

Because connection secrets are written as a Kubernetes Secret they can easily be consumed by Kubernetes primitives. The most basic building block in Kubernetes is the Pod. Let’s define a Pod that will show that we are able to connect to our newly provisioned database.

apiVersion: v1
kind: Pod
metadata:
  name: see-db
  namespace: default
spec:
  containers:
  - name: see-db
    image: postgres:9.6
    command: ['psql']
    args: ['-c', 'SELECT current_database();']
    env:
    - name: PGDATABASE
      value: postgres
    - name: PGHOST
      valueFrom:
        secretKeyRef:
          name: db-conn
          key: endpoint
    - name: PGUSER
      valueFrom:
        secretKeyRef:
          name: db-conn
          key: username
    - name: PGPASSWORD
      valueFrom:
        secretKeyRef:
          name: db-conn
          key: password
    - name: PGPORT
      valueFrom:
        secretKeyRef:
          name: db-conn
          key: port
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-0.13/docs/snippets/compose/pod.yaml

This Pod simply connects to a PostgreSQL database and prints its name, so you should see the following output (or similar) after creating it if you run kubectl logs see-db:

 current_database
------------------
 postgres
(1 row)

Clean Up

To clean up the Pod, run:

kubectl delete pod see-db

To clean up the infrastructure that was provisioned, you can delete the PostgreSQLInstance XRC:

kubectl delete postgresqlinstance my-db

Don’t clean up your Configuration just yet if you plan to continue on to the next section of the guide! We’ll use them again when we deploy an OAM application.

Next Steps

Now you have seen how to provision and publish more complex infrastructure setups. In the next section you will learn how to consume infrastructure alongside your OAM application manifests.