Provision Infrastructure

Composite resources (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. This model has similarities to Persistent Volumes (PV) and Persistent Volume Claims (PVC) in Kubernetes.

Claim Your Infrastructure

The Configuration package we installed in the last section:

  • Defines a XPostgreSQLInstance XR.
  • Offers a PostgreSQLInstance claim (XRC) for said XR.
  • Creates a Composition that can satisfy our XR.

This means that we can create a PostgreSQLInstance XRC in the default namespace to provision a PostgreSQL instance and all the supporting infrastructure (VPCs, firewall rules, resource groups, etc) that it may need!

Note that this resource 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.

 1apiVersion: database.example.org/v1alpha1
 2kind: PostgreSQLInstance
 3metadata:
 4  name: my-db
 5  namespace: default
 6spec:
 7  parameters:
 8    storageGB: 20
 9  compositionSelector:
10    matchLabels:
11      provider: aws
12      vpc: default
13  writeConnectionSecretToRef:
14    name: db-conn
1kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.10/docs/snippets/compose/claim-aws.yaml

Note that this resource 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.

 1apiVersion: database.example.org/v1alpha1
 2kind: PostgreSQLInstance
 3metadata:
 4  name: my-db
 5  namespace: default
 6spec:
 7  parameters:
 8    storageGB: 20
 9  compositionSelector:
10    matchLabels:
11      provider: aws
12      vpc: new
13  writeConnectionSecretToRef:
14    name: db-conn
1kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.10/docs/snippets/compose/claim-aws-new.yaml
 1apiVersion: database.example.org/v1alpha1
 2kind: PostgreSQLInstance
 3metadata:
 4  name: my-db
 5  namespace: default
 6spec:
 7  parameters:
 8    storageGB: 20
 9  compositionSelector:
10    matchLabels:
11      provider: gcp
12  writeConnectionSecretToRef:
13    name: db-conn
1kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.10/docs/snippets/compose/claim-gcp.yaml
 1apiVersion: database.example.org/v1alpha1
 2kind: PostgreSQLInstance
 3metadata:
 4  name: my-db
 5  namespace: default
 6spec:
 7  parameters:
 8    storageGB: 20
 9  compositionSelector:
10    matchLabels:
11      provider: azure
12  writeConnectionSecretToRef:
13    name: db-conn
1kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.10/docs/snippets/compose/claim-azure.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:

1kubectl 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 XPostgreSQLInstance.
  • 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:

1kubectl 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:

 1$ kubectl describe secrets db-conn
 2Name:         db-conn
 3Namespace:    default
 4...
 5
 6Type:  connection.crossplane.io/v1alpha1
 7
 8Data
 9====
10password:  27 bytes
11port:      4 bytes
12username:  25 bytes
13endpoint:  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.

Note that if you’re using a hosted Crossplane you’ll need to copy the db-conn connection secret over to your own Kubernetes cluster and run this pod there.

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: see-db
 5  namespace: default
 6spec:
 7  containers:
 8  - name: see-db
 9    image: postgres:12
10    command: ['psql']
11    args: ['-c', 'SELECT current_database();']
12    env:
13    - name: PGDATABASE
14      value: postgres
15    - name: PGHOST
16      valueFrom:
17        secretKeyRef:
18          name: db-conn
19          key: endpoint
20    - name: PGUSER
21      valueFrom:
22        secretKeyRef:
23          name: db-conn
24          key: username
25    - name: PGPASSWORD
26      valueFrom:
27        secretKeyRef:
28          name: db-conn
29          key: password
30    - name: PGPORT
31      valueFrom:
32        secretKeyRef:
33          name: db-conn
34          key: port
1kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.10/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:

1 current_database
2------------------
3 postgres
4(1 row)

Clean Up

To clean up the Pod, run:

1kubectl delete pod see-db

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

1kubectl delete postgresqlinstance my-db

Next Steps

Now you have seen how to provision and consume complex infrastructure via composition. In the next section you will learn how compose and package your own infrastructure APIs.