content/v1.20/getting-started/provider-gcp-part-2.md
{{< hint "important" >}} This guide is part 2 of a series.
[Part 1]({{<ref "provider-gcp" >}}) covers to installing Crossplane and connect your Kubernetes cluster to GCP.
{{< /hint >}}
This guide walks you through building and accessing a custom API with Crossplane.
{{<expand "Skip part 1 and just get started" >}}
helm repo add \
crossplane-stable https://charts.crossplane.io/stable
helm repo update
&&
helm install crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-gcp-storage
spec:
package: xpkg.crossplane.io/crossplane-contrib/provider-gcp-storage:v1.12.1
EOF
gcp-credentials.json with your GCP service account
JSON file.{{< hint "tip" >}} The GCP documentation provides information on how to generate a service account JSON file. {{< /hint >}}
kubectl create secret \
generic gcp-secret \
-n crossplane-system \
--from-file=creds=./gcp-credentials.json
{{< hint type="tip" >}}
Find your GCP project ID from the project_id field of the
gcp-credentials.json file.
{{< /hint >}}
{{< editCode >}}
cat <<EOF | kubectl apply -f -
apiVersion: gcp.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
projectID: $@<PROJECT_ID>$@
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: gcp-secret
key: creds
EOF
{{< /editCode >}}
{{</expand >}}
Part 1 only installed the GCP Storage Provider. This section deploys a PubSub Topic along with a GCP storage bucket. First install the GCP PubSub Provider.
Add the new Provider to the cluster.
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-gcp-pubsub
spec:
package: xpkg.crossplane.io/crossplane-contrib/provider-gcp-pubsub:v1.12.1
EOF
View the new PubSub provider with kubectl get providers.
kubectl get providers
NAME INSTALLED HEALTHY PACKAGE AGE
crossplane-contrib-provider-family-gcp True True xpkg.crossplane.io/crossplane-contrib/provider-family-gcp:v1.12.1 48m
provider-gcp-pubsub True True xpkg.crossplane.io/crossplane-contrib/provider-gcp-pubsub:v1.12.1 14s
provider-gcp-storage True True xpkg.crossplane.io/crossplane-contrib/provider-gcp-storage:v1.12.1 48m
Crossplane allows you to build your own custom APIs for your users, abstracting away details about the cloud provider and their resources. You can make your API as complex or simple as you wish.
<!-- vale alex.Condescending = YES -->The custom API is a Kubernetes object. Here is an example custom API.
apiVersion: database.example.com/v1alpha1
kind: NoSQL
metadata:
name: my-nosql-database
spec:
location: "US"
Like any Kubernetes object the API has a {{<hover label="exAPI" line="1">}}version{{</hover>}}, {{<hover label="exAPI" line="2">}}kind{{</hover>}} and {{<hover label="exAPI" line="5">}}spec{{</hover>}}.
To create your own API start by defining an API group and version.
The group can be any value, but common convention is to map to a fully qualified domain name.
<!-- vale gitlab.SentenceLength = NO -->The version shows how mature or stable the API is and increments when changing, adding or removing fields in the API.
<!-- vale gitlab.SentenceLength = YES -->Crossplane doesn't require specific versions or a specific version naming convention, but following Kubernetes API versioning guidelines is strongly recommended.
v1alpha1 - A new API that may change at any time.v1beta1 - An existing API that's considered stable. Breaking changes are
strongly discouraged.v1 - A stable API that doesn't have breaking changes.This guide uses the group {{<hover label="version" line="1">}}database.example.com{{</hover>}}.
Because this is the first version of the API, this guide uses the version {{<hover label="version" line="1">}}v1alpha1{{</hover>}}.
apiVersion: database.example.com/v1alpha1
The API group is a logical collection of related APIs. In a group are individual kinds representing different resources.
For example a queue group may have a PubSub and CloudTask kinds.
The kind can be anything, but it must be
UpperCamelCased.
This API's kind is {{<hover label="kind" line="2">}}PubSub{{</hover>}}
apiVersion: queue.example.com/v1alpha1
kind: PubSub
The most important part of an API is the schema. The schema defines the inputs accepted from users.
This API allows users to provide a {{<hover label="spec" line="4">}}location{{</hover>}} of where to run their cloud resources.
All other resource settings can't be configurable by the users. This allows Crossplane to enforce any policies and standards without worrying about user errors.
apiVersion: queue.example.com/v1alpha1
kind: PubSub
spec:
location: "US"
Crossplane uses
{{<hover label="xrd" line="3">}}Composite Resource Definitions{{</hover>}}
(also called an XRD) to install your custom API in
Kubernetes.
The XRD {{<hover label="xrd" line="6">}}spec{{</hover>}} contains all the information about the API including the {{<hover label="xrd" line="7">}}group{{</hover>}}, {{<hover label="xrd" line="12">}}version{{</hover>}}, {{<hover label="xrd" line="9">}}kind{{</hover>}} and {{<hover label="xrd" line="13">}}schema{{</hover>}}.
The XRD's {{<hover label="xrd" line="5">}}name{{</hover>}} must be the combination of the {{<hover label="xrd" line="9">}}plural{{</hover>}} and {{<hover label="xrd" line="7">}}group{{</hover>}}.
The {{<hover label="xrd" line="13">}}schema{{</hover>}} uses the {{<hover label="xrd" line="14">}}OpenAPIv3{{</hover>}} specification to define the API {{<hover label="xrd" line="17">}}spec{{</hover>}}.
The API defines a {{<hover label="xrd" line="20">}}location{{</hover>}} that must be {{<hover label="xrd" line="22">}}oneOf{{</hover>}} either {{<hover label="xrd" line="23">}}EU{{</hover>}} or {{<hover label="xrd" line="24">}}US{{</hover>}}.
Apply this XRD to create the custom API in your Kubernetes cluster.
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: pubsubs.queue.example.com
spec:
group: queue.example.com
names:
kind: PubSub
plural: pubsubs
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
location:
type: string
oneOf:
- pattern: '^EU$'
- pattern: '^US$'
required:
- location
served: true
referenceable: true
claimNames:
kind: PubSubClaim
plural: pubsubclaims
EOF
Adding the {{<hover label="xrd" line="29">}}claimNames{{</hover>}} allows users to access this API either at the cluster level with the {{<hover label="xrd" line="9">}}pubsub{{</hover>}} endpoint or in a namespace with the {{<hover label="xrd" line="29">}}pubsubclaim{{</hover>}} endpoint.
The namespace scoped API is a Crossplane Claim.
{{<hint "tip" >}} For more details on the fields and options of Composite Resource Definitions read the [XRD documentation]({{<ref "../concepts/composite-resource-definitions">}}). {{< /hint >}}
View the installed XRD with kubectl get xrd.
kubectl get xrd
NAME ESTABLISHED OFFERED AGE
pubsubs.queue.example.com True True 7s
View the new custom API endpoints with kubectl api-resources | grep pubsub
kubectl api-resources | grep queue.example
pubsubclaims queue.example.com/v1alpha1 true PubSubClaim
pubsubs queue.example.com/v1alpha1 false PubSub
When users access the custom API Crossplane takes their inputs and combines them with a template describing what infrastructure to deploy. Crossplane calls this template a Composition.
The {{<hover label="comp" line="3">}}Composition{{</hover>}} defines all the cloud resources to deploy. Each entry in the template is a full resource definitions, defining all the resource settings and metadata like labels and annotations.
This template creates a GCP {{<hover label="comp" line="10">}}Storage{{</hover>}} {{<hover label="comp" line="11">}}Bucket{{</hover>}} and a {{<hover label="comp" line="25">}}PubSub{{</hover>}} {{<hover label="comp" line="26">}}Topic{{</hover>}}.
This Composition takes the user's {{<hover label="comp" line="16">}}location{{</hover>}} input and uses it as the {{<hover label="comp" line="14">}}location{{</hover>}} used in the individual resource.
{{<hint "important" >}} This Composition uses an array of resource templates. You can patch each template with data copied from the custom API. Crossplane calls this a Patch and Transform Composition.
You don't have to use Patch and Transform. Crossplane supports a variety of alternatives, including Go Templating and CUE. You can also write a function in Go or Python to template your resources.
Read the [Composition documentation]({{<ref "../concepts/compositions">}}) for more information on configuring Compositions and all the available options. {{< /hint >}}
Apply this Composition to your cluster.
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: topic-with-bucket
spec:
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: crossplane-quickstart-bucket
base:
apiVersion: storage.gcp.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
location: "US"
patches:
- fromFieldPath: "spec.location"
toFieldPath: "spec.forProvider.location"
transforms:
- type: map
map:
EU: "EU"
US: "US"
- name: crossplane-quickstart-topic
base:
apiVersion: pubsub.gcp.upbound.io/v1beta1
kind: Topic
spec:
forProvider:
messageStoragePolicy:
- allowedPersistenceRegions:
- "us-central1"
patches:
- fromFieldPath: "spec.location"
toFieldPath: "spec.forProvider.messageStoragePolicy[0].allowedPersistenceRegions[0]"
transforms:
- type: map
map:
EU: "europe-central2"
US: "us-central1"
compositeTypeRef:
apiVersion: queue.example.com/v1alpha1
kind: PubSub
EOF
The {{<hover label="comp" line="40">}}compositeTypeRef{{</hover >}} defines which custom APIs can use this template to create resources.
A Composition uses a pipeline of composition functions to define the cloud resources to deploy. This template uses {{<hover label="comp" line="10">}}function-patch-and-transform{{</hover>}}. You must install the function before you can use it in a Composition.
Apply this Function to install function-patch-and-transform:
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Function
metadata:
name: function-patch-and-transform
spec:
package: xpkg.crossplane.io/crossplane-contrib/function-patch-and-transform:v0.8.2
EOF
{{<hint "tip" >}} Read the [Composition documentation]({{<ref "../concepts/compositions">}}) for more information on configuring Compositions and all the available options.
Read the [Patch and Transform function documentation]({{<ref "../guides/function-patch-and-transform">}}) for more information on how it uses patches to map user inputs to Composition resource templates. {{< /hint >}}
View the Composition with kubectl get composition
kubectl get composition
NAME XR-KIND XR-APIVERSION AGE
topic-with-bucket PubSub queue.example.com 3s
With the custom API (XRD) installed and associated to a resource template (Composition) users can access the API to create resources.
Create a {{<hover label="xr" line="2">}}PubSub{{</hover>}} object to create the cloud resources.
cat <<EOF | kubectl apply -f -
apiVersion: queue.example.com/v1alpha1
kind: PubSub
metadata:
name: my-pubsub-queue
spec:
location: "US"
EOF
View the resource with kubectl get pubsub.
kubectl get pubsub
NAME SYNCED READY COMPOSITION AGE
my-pubsub-queue True True topic-with-bucket 2m12s
This object is a Crossplane composite resource (also called an XR).
It's a
single object representing the collection of resources created from the
Composition template.
View the individual resources with kubectl get managed
kubectl get managed
NAME READY SYNCED EXTERNAL-NAME AGE
topic.pubsub.gcp.upbound.io/my-pubsub-queue-cjswx True True my-pubsub-queue-cjswx 3m4s
NAME READY SYNCED EXTERNAL-NAME AGE
bucket.storage.gcp.upbound.io/my-pubsub-queue-vljg9 True True my-pubsub-queue-vljg9 3m4s
Delete the resources with kubectl delete pubsub.
kubectl delete pubsub my-pubsub-queue
pubsub.queue.example.com "my-pubsub-queue" deleted
Verify Crossplane deleted the resources with kubectl get managed
{{<hint "note" >}} It may take up to 5 minutes to delete the resources. {{< /hint >}}
kubectl get managed
No resources found
Accessing the API pubsub happens at the cluster scope.
Most organizations
isolate their users into namespaces.
A Crossplane Claim is the custom API in a namespace.
Creating a Claim is just like accessing the custom API endpoint, but with the
{{<hover label="claim" line="3">}}kind{{</hover>}}
from the custom API's claimNames.
Create a new namespace to test create a Claim in.
kubectl create namespace crossplane-test
Then create a Claim in the crossplane-test namespace.
cat <<EOF | kubectl apply -f -
apiVersion: queue.example.com/v1alpha1
kind: PubSubClaim
metadata:
name: my-pubsub-queue
namespace: crossplane-test
spec:
location: "US"
EOF
View the Claim with kubectl get claim -n crossplane-test.
kubectl get claim -n crossplane-test
NAME SYNCED READY CONNECTION-SECRET AGE
my-pubsub-queue True True 2m10s
The Claim automatically creates a composite resource, which creates the managed resources.
View the Crossplane created composite resource with kubectl get composite.
kubectl get composite
NAME SYNCED READY COMPOSITION AGE
my-pubsub-queue-7bm9n True True topic-with-bucket 3m10s
Again, view the managed resources with kubectl get managed.
kubectl get managed
NAME READY SYNCED EXTERNAL-NAME AGE
topic.pubsub.gcp.upbound.io/my-pubsub-queue-7bm9n-6kdq4 True True my-pubsub-queue-7bm9n-6kdq4 3m22s
NAME READY SYNCED EXTERNAL-NAME AGE
bucket.storage.gcp.upbound.io/my-pubsub-queue-7bm9n-hhwx8 True True my-pubsub-queue-7bm9n-hhwx8 3m22s
Deleting the Claim deletes all the Crossplane generated resources.
kubectl delete claim -n crossplane-test my-pubsub-queue
kubectl delete pubsubclaim my-pubsub-queue -n crossplane-test
pubsubclaim.queue.example.com "my-pubsub-queue" deleted
{{<hint "note" >}} It may take up to 5 minutes to delete the resources. {{< /hint >}}
Verify Crossplane deleted the composite resource with kubectl get composite.
kubectl get composite
No resources found
Verify Crossplane deleted the managed resources with kubectl get managed.
kubectl get managed
No resources found