My First Steps With Crossplane: Crossplane 101

At the beginning, we manually configured the servers – each a precious snowflake, maintained and documented with love. But the size of the infrastructure has increased, and this approach could not evolve. The chef and puppets popularized the idea of infrastructure as a code: the engineers would define the state of the machine (s) in text files, stored in Git – hence the name. A global knot will read these files to create a register. Then, a local agent on each machine would check the desired state at regular intervals and reconciled the current state with the register.
The first generation of infrastructure as a code has managed the state of existing machines but assumed that the machine was already there. The migration to the cloud created another problem: how to create the machine in the first place? Another IAC tool appeared in the form of a Hashicorp terraform. Terraform came with its own entirely descriptive language, aptly named the Terraform language.
However, it does not offer a central register and you must execute an order to reconcile the desired state with the current state. Terraform was a huge success. When Hashicorp moved away from an open source license, the community formed it and baptized Openfu. In addition, IBM recently acquired Hashicorp.
Terraform is not without problem, however. Some believe that the descriptive configuration language is limited. Pulumi offers to describe the infrastructure in some existing programming languages, For examplePython, Javascript and Kotlin. Instead of repeating ten configuration lines with a single modified parameter, you can write functions and loops.
Another problem was the absence of a central register and an automated drift correction. In the current technological landscape, which tool offers such features? Kubernetes! It is very logical to use Kubernetes to approach the limits of Terraform; It is the crossplane approach by Upbound.
I work on Kubernetes these days. Recently, I wrote a series on how we could design a full -fledged test pipeline targeting Google Kubernetes Engine. The second part mentions the creation of a Google Kubernetes engine instance in the context of a Github workflow. In this article, I wish to assess the crossplane by creating such an instance.
It seems weird to create a new Kubernetes cluster, you need a Kubernetes cluster. I admit that my use case is a little weird, but I think that if I can make this case, I can make more nominal.
Crossplane 101
Crossplane is like an engine, using a register of Kubernetes and by reconciling behavior to manage resources. Resources include practically anything: cloud resources, GitHub projects and organizations, Terraform (!), Or software batteries, such as Kafka and Keycloak, etc. packages. The packages are of two types:
- Configuration Packages: A configuration package defines a higher level abstraction on Kubernete objects. You may have noticed that the deployment of an application in Kubernetes follows the same model: Defining a
Deployment
(or any other relevant object) and aService
. In most cases, you prefer to offer a singleApplication
abstraction for developers. Crossplane allows you to compose objects to create abstractions and deliver them to configuration packages.
-
Suppliers: A supplier integrates into a third -party system, whether it is a cloud supplier or any other system. For example, Crossplane offers a Google Cloud platform supplier. Crossplane offers three categories of suppliers:
-
Official, developed and supported from above
-
Partner, developed by a third party
-
Community, developed by the community in general
Upbound offers suppliers for the main hyperscalers, while the community has created a couple for the smallest, For exampleScaleway or OVH.
-
First steps with crossplane
The first step is to install Crossplane itself. I use a simple bar graphic with the default configuration. I am the advice to install it in its dedicated name space, crossplane-system
.
helm repo add crossplane-stable
helm repo update
helm install crossplane --create-namespace --namespace crossplane-system crossplane-stable/crossplane
You should see two pods running in the crossplane-system
Name space:
NAME READY STATUS RESTARTS AGE
crossplane-6f88554645-b2xng 1/1 Running 1 (1h ago) 1h
crossplane-rbac-manager-75bc66d6b7-8p2fh 1/1 Running 1 (1h ago) 1h
We are now ready to start the real work. We target Google Cloud Platform, therefore, we must install the GCP supplier. The market offers many available suppliers. The first challenge is to locate the one that contains the abstraction that we want to create. Since we want to create a Cluster
We need the supplier-GCP-Container.
The cluster is the scheme of the clusters API. Create a Google Kubernetes Engine (GKE) cluster.
– Resource managed in cluster
We create a Provider
Object that points to the supplier package:
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-gcp #1
spec:
package: xpkg.upbound.io/upbound/provider-gcp-container:v1 #2
- Providers are on the clusters.
- Upbound requires a paying subscription for specific versions. Because I don't have one, I can only use a major version, with all the stability problems that accompanied it.
We can list the installed suppliers:
kubectl get providers
The result should look like the following:
NAME INSTALLED HEALTHY PACKAGE AGE
provider-gcp True True xpkg.upbound.io/upbound/provider-gcp-container:v1 28m
upbound-provider-family-gcp True True xpkg.upbound.io/upbound/provider-family-gcp:v1.12.1 28m
At this point, we can manage the GKE instances with Crossplane.
Google offers several ways to authenticate. Here, I will use the simple JSON identification information associated with a service account. Get the JSON from the Google Cloud console, then import it as a secret in Kubernetes:
kubectl create secret generic gcp-creds -n crossplane-system --from-file=creds=./gcp-credentials.json
In the transverse circulation model, a Provider
The object is generic and relevant for a single supplier. On the other hand, a ProviderConfig
is relevant for a project, including its references.
apiVersion: gcp.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: gcp-provider
spec:
projectID: xplane-demo #1
credentials:
source: Secret
secretRef: #2
namespace: crossplane-system
name: gcp-creds
key: credentials.json
- The identification of the project we want to manage resources.
- Reference to the secret created previously containing the required identification information.
The last step is to create the cluster. I tried to define the same configuration as in the command line of the original article, but I must admit that I could not map each option.
apiVersion: container.gcp.upbound.io/v1beta1
kind: Cluster
metadata:
name: minimal-cluster
spec:
forProvider:
initialNodeCount: 1 #1
location: europe-west9 #1
nodeLocations: [ "europe-west9-a" ] #1
network: projects/xplane-demo/global/networks/default #1
subnetwork: projects/xplane-demo/regions/europe-west9/subnetworks/default #1
ipAllocationPolicy:
- clusterIpv4CidrBlock: "/17" #1
resourceLabels:
provisioner: crossplane #2
providerConfigRef:
name: gcp-provider #3
writeConnectionSecretToRef: #4
namespace: default
name: kubeconfig
- Same parameters as in the command line
- Define labels to document who is the resource manager. Depending on your context, you can add more, For example,,
environment
- Name of
ProviderConfig
We have created above - Writes it
kubeconfig
To connect to the GKE created
You can follow the creation of the GKE cluster both on the Google Cloud console and via kubectl
.
kubectl get cluster
We can see here that the cluster is not yet ready:
NAME SYNCED READY EXTERNAL-NAME AGE
minimal-cluster True False minimal-cluster 2m46s
We can use the kubeconfig
Secret
This cross circuit created with the Cluster
To connect to the latter. First of all, let's throw it Secret
value to a file:
kubectl get secret kubeconfig -o jsonpath="{.data.kubeconfig}" | base64 --decode > kube.config
At this point, we can use it to send requests to the new creation Cluster
::
kubectl --kubeconfig ./kube.config get pods
To remove the GKE instance, just delete the room Cluster
. Kubernetes and crossplower will take care of the sending of the DELETE
Ask Google Cloud.
kubectl delete cluster.container.gcp.upbound.io minimal-cluster
The command is synchronous: you will not recover the prompt as long as the GKE body is not deleted.
In this article, I used Crossplane to create a simple GKE cluster. The use of Kubernetes for the register and the reconciliation behavior is ingenious. Of course, Crossplane is as good as the number of integrations it offers. Currently, it can already manage all the major hyperscalers, more some smaller ones.
Go further:
Originally published in a Java geek on May 4, 2025