--- title: GCP Quickstart Part 3 weight: 120 tocHidden: true --- {{< hint "important" >}} This guide is part 3 of a series. Follow **[part 1]({{}})** to install Crossplane and connect your Kubernetes cluster to GCP. Follow **[part 2]({{}})** to create a _composition_, _custom resource definition_ and a _claim_. {{< /hint >}} [Part 2]({{}}) created a _composite resource definition_ to define the schema of the custom API. Users create a _claim_ to use the custom API and apply their options. Part 2 didn't show how the options set in a _claim_ change or get applied the associated _composite resources_. ## Prerequisites * Complete quickstart [part 1]({{}}) and [Part 2]({{}}) to install Crossplane and the quickstart configurations. {{}} 1. Add the Crossplane Helm repository and install Crossplane. ```shell helm repo add \ crossplane-stable https://charts.crossplane.io/stable helm repo update && helm install crossplane \ crossplane-stable/crossplane \ --namespace crossplane-system \ --create-namespace ``` 2. When the Crossplane pods finish installing and are ready, apply the GCP Provider. ```yaml {label="provider",copy-lines="all"} cat <}} The [GCP documentation](https://cloud.google.com/iam/docs/creating-managing-service-account-keys) provides information on how to generate a service account JSON file. {{< /hint >}} 4. Create a Kubernetes secret from the GCP JSON file ```shell {label="kube-create-secret",copy-lines="all"} kubectl create secret \ generic gcp-secret \ -n crossplane-system \ --from-file=creds=./gcp-credentials.json ``` 5. Create a _ProviderConfig_ Include your {{< hover label="providerconfig" line="7" >}}GCP project ID{{< /hover >}} in the _ProviderConfig_ settings. {{< hint type="warning" >}} Find your GCP project ID from the `project_id` field of the `gcp-credentials.json` file. {{< /hint >}} {{< editCode >}} ```yaml {label="providerconfig",copy-lines="all"} cat <$@ credentials: source: Secret secretRef: namespace: crossplane-system name: gcp-secret key: creds EOF ``` {{< /editCode >}} 6. Create a _composition_ ```yaml {copy-lines="all"} cat <}} ## Enable composition patches In a _composition_, `patches` map fields in the custom API to fields inside the _managed resources_. The example _composition_ has two _managed resources_, a {{}}bucket{{}} and a {{}}topic{{}}. ```yaml {label="compResources"} apiVersion: apiextensions.crossplane.io/v1 kind: Composition # Removed for Brevity resources: - name: crossplane-quickstart-bucket base: apiVersion: storage.gcp.upbound.io/v1beta1 kind: Bucket spec: forProvider: location: US - name: crossplane-quickstart-topic base: apiVersion: pubsub.gcp.upbound.io/v1beta1 kind: Topic spec: forProvider: messageStoragePolicy: - allowedPersistenceRegions: - "us-central1" ``` The custom API defined a single option, {{}}location{{}}. A {{}}location{{}} can be either {{}}EU{{}} or {{}}US{{}}. ```yaml {label="xrdSnip"} apiVersion: apiextensions.crossplane.io/v1 kind: CompositeResourceDefinition # Removed for brevity spec: group: custom-api.example.org names: kind: XDatabase # Removed for brevity spec: type: object properties: location: type: string oneOf: - pattern: '^EU$' - pattern: '^US$' ``` Creating a _composition_ `patch` allows Crossplane to update the settings of a _composite resource_. Patches apply to an individual _managed resource_ inside the _composition_. A {{}}patch{{}} has a {{}}fromField{{}} and a {{}}toField{{}} specifying which value _from_ the custom API should apply _to_ a field in the _managed resource_. Patches can create a {{}}transform{{}} to change the _from_ field before it's applied. The transform {{}}type{{}} is what kind of change to make on the _from_ field. Types of changes could include appending a string, preforming a math operation or mapping one value to another. Applying a {{}}patch{{}} to the {{}}Topic{{}} uses the custom API {{}}spec.location{{}} field to use as the _managed resource_ {{}}allowedPersistenceRegions{{}} value. The custom API value "EU" is {{}}mapped{{}} to the value "europe-central2" and "US" is {{}}mapped{{}} to the value "us-central1." ```yaml {label="patch"} apiVersion: apiextensions.crossplane.io/v1 kind: Composition # Removed for Brevity resources: - 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[*].allowedPersistenceRegions[*]" transforms: - type: map map: EU: "europe-central2" US: "us-central1" ``` Patching is a powerful tool enabling simpler or abstracted APIs. Developers aren't required to know the specific GCP region, just the abstracted option of "EU" or "US." ### Apply the updated composition Apply a similar `patch` to the `Bucket` _managed resource_ and apply the updated _composition_. ```yaml cat <}}location{{}} to "EU." ```yaml {label="claim"} cat <}}europe-central2{{< /hover >}}. ```shell {copy-lines="1",label="topicLocation"} kubectl describe topic | grep "For Provider" -A3 For Provider: Message Storage Policy: Allowed Persistence Regions: europe-central2 ``` Describe the `Bucket` resource to see the GCP location is also set to {{}}EU{{}}. ```shell {copy-lines="1",label="bucketLocation"} kubectl describe bucket | grep "For Provider" -A1 For Provider: Location: EU ``` Using {{}}location: "EU"{{}} in the claim patches the _composite resource_, updating the `Topic` GCP region from `us-central1` to `europe-central-2` and the `Bucket` from GCP region `US` to GCP region `EU`. The developer creating the claim isn't required to know which specific GCP region or the naming conventions. Using the abstract API options of "EU" or "US" the developer places their resources in the desired location. In this example, patching also allows platform teams to ensure all resources are in the same location. Deleting the claim removes the _managed resources_. {{}} The _managed resources_ take up to 5 minutes to delete. {{< /hint >}} ```shell kubectl delete TopicBucket claimed-eu-topic-with-bucket -n test ``` ## Create a Crossplane configuration package Creating a configuration package makes your Crossplane custom APIs portable and versioned. Crossplane _configuration packages_ allow users to combine their _custom resource definition_ and _composition_ files into an OCI image. {{< hint "note" >}} The [Open Container Initiative](https://opencontainers.org/faq/) defines the OCI image standard. An OCI images is a standard way to package data. {{< /hint >}} You can host configuration packages in image registries like [Docker Hub](https://hub.docker.com/) or the [Upbound Marketplace](https://marketplace.upbound.io/). Crossplane can download and install configuration packages into a Kubernetes cluster. Building and installing configuration packages requires an OCI image compatible tool. {{< hint "note" >}} You can use any software that builds OCI images. This includes [Docker](https://www.docker.com/) or [Upbound's Up command-line tool](https://github.com/upbound/up) {{< /hint >}} A configuration package includes three files: * `crossplane.yaml` defines the metadata of the package. * `definition.yaml` is the _composite resource definition_ for the package. * `composition.yaml` is the _composition_ template for the package. ### Create a crossplane.yaml file Configuration packages describe their contents and requirements with a `crossplane.yaml` file. The `crossplane.yaml` file lists the required Crossplane _providers_ and their compatible versions as well as the required Crossplane version. The Crossplane {{}}meta.pkg{{}} API defines the schema for a {{}}Configuration{{}}. Inside the {{}}spec{{}} define the required Crossplane {{}}version{{}}. The {{}}dependsOn{{}} section lists the dependencies for a package. This package lists the Upbound {{}}provider-gcp{{}} version {{}}0.28.0{{}} or later as a dependency. {{}} Crossplane automatically installs dependencies. Dependencies can include other configuration packages. {{< /hint >}} ```yaml {label="xpyaml"} apiVersion: meta.pkg.crossplane.io/v1 kind: Configuration metadata: name: crossplane-gcp-quickstart spec: crossplane: version: ">=v1.11.0" dependsOn: - provider: xpkg.upbound.io/upbound/provider-gcp version: ">=v0.28.0" ``` Create a new directory and save the `crossplane.yaml` file. ```yaml {copy-lines="all"} mkdir crossplane-gcp-quickstart cat < crossplane-gcp-quickstart/crossplane.yaml apiVersion: meta.pkg.crossplane.io/v1 kind: Configuration metadata: name: crossplane-gcp-quickstart spec: crossplane: version: ">=v1.11.0" dependsOn: - provider: xpkg.upbound.io/upbound/provider-gcp version: ">=v0.28.0" EOF ``` ### Create a definition.yaml file A configuration package requires a _composite resource definition_ (XRD) to define the custom API. Save the _XRD_ as `definition.yaml` in the same directory as the `crossplane.yaml` file. ```yaml {copy-lines="all"} cat < crossplane-gcp-quickstart/definition.yaml apiVersion: apiextensions.crossplane.io/v1 kind: CompositeResourceDefinition metadata: name: xtopicbuckets.custom-api.example.org spec: group: custom-api.example.org names: kind: XTopicBucket plural: xtopicbuckets versions: - name: v1alpha1 served: true referenceable: true schema: openAPIV3Schema: type: object properties: spec: type: object properties: location: type: string oneOf: - pattern: '^EU$' - pattern: '^US$' required: - location claimNames: kind: TopicBucket plural: topicbuckets EOF ``` ### Create a composition.yaml file The _composition_ template creates the _managed resources_ and allows _patches_ to customize the _managed resources_. Copy the _composition_ into the `composition.yaml` file in the same directory as `crossplane.yaml`. ```yaml cat < crossplane-gcp-quickstart/composition.yaml apiVersion: apiextensions.crossplane.io/v1 kind: Composition metadata: name: topic-with-bucket spec: compositeTypeRef: apiVersion: custom-api.example.org/v1alpha1 kind: XTopicBucket 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[*].allowedPersistenceRegions[*]" transforms: - type: map map: EU: "europe-central2" US: "us-central1" EOF ``` ### Install the Crossplane command-line To build a configuration package install the Crossplane Kubernetes command-line extension. ```shell wget "https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh" chmod +x install.sh ./install.sh sudo mv crossplane /usr/local/bin ``` Verify the Crossplane command-line installed with `crossplane --help` ```shell crossplane --help Usage: crossplane A command line tool for interacting with Crossplane. Flags: -h, --help Show context-sensitive help. -v, --version Print version and quit. --verbose Print verbose logging statements. # Ouptut removed for brevity ``` ### Build a configuration package Use the `crossplane` CLI to create an `.xpkg` file containing the custom APIs and Crossplane configuration. ```shell crossplane build configuration -f crossplane-gcp-quickstart/ --name="crossplane-gcp-quickstart" ``` Now an `.xpkg` OCI image is inside the `crossplane-gcp-quickstart` directory. ```shell ls crossplane-gcp-quickstart/ composition.yaml crossplane-gcp-quickstart.xpkg crossplane.yaml definition.yaml ``` ## Next steps * Explore GCP resources that Crossplane can configure in the [Provider CRD reference](https://marketplace.upbound.io/providers/upbound/provider-family-gcp/). * Join the [Crossplane Slack](https://slack.crossplane.io/) and connect with Crossplane users and contributors. * Read more about [Crossplane concepts]({{}})