Crossplane
Updated September 2026: the standalone crossplane CLI and the current Azure provider APIs.
100Days Resources
Learning Resources
- The Website https://crossplane.io/
- The Docs https://docs.crossplane.io/latest/
Example Notes
Some Highlights from their website:
Crossplane is an open source Kubernetes add-on that supercharges your Kubernetes clusters enabling you to provision and manage infrastructure, services, and applications from kubectl.
Crossplane is a graduated CNCF project which extends the Kubernetes API to manage and compose infrastructure.
Crossplane introduces multiple building blocks that enable you to provision, compose, and consume infrastructure using the Kubernetes API. These individual concepts work together to allow for powerful separation of concern between different personas in an organization, meaning that each member of a team interacts with Crossplane at an appropriate level of abstraction.
Crossplane uses Kubernetes Custom Resource Definitions to manage your infrastructure and resources. Basically, all of the resources used are Kubernetes resources themselves, making it possible for Crossplane to interact with any other Kubernetes Resources.
In short, Crossplane manages all of your resources through a Kubernetes API.
The Benefits:
- Manage your infrastructure directly through kubectl
- Supports infrastructure from all major cloud providers + the maintainers are consistently working on new providers
- You can build your own infrastructure abstraction on top of Crossplane
- Crossplane is based on CRD, so you can run it anywhere + it is extensible
- One place of truth for your infrastructure
- Use custom APIs to manage policies, hiding infrastructure complexity and safely customise application
- Declarative Infrastructure Configuration — infrastructure managed through Crossplane is accessible via kubectl, configurable with YAML, and self-healing right out of the box.
GitOps best practices
Crossplane can be combined with CI/CD pipelines, this allows to implement GitOps best practices. GitOps is a deployment strategy, whereby everything, the desired state of the application is defined in git.
infrastructure configuration that can be versioned, managed, and deployed using your favorite tools and existing processes
To use crossplane you initially need any type of Kubernetes Cluster — it could be Minikube, where you then install it! Once you have access to the Crossplane Kubernetes resources
On their own, custom resources let you store and retrieve structured data. When you combine a custom resource with a custom controller, custom resources provide a true declarative API.
Install Crossplane
Crossplane combines custom resource definitions and custom controllers — those are both Kubernetes resources. So you install Kubernetes resources that are used to manage Crossplane.
https://docs.crossplane.io/latest/get-started/install/
Prerequisites
- Have kubectl installed
- Have Helm installed
- Have a local Kubernetes cluster, or any Kubernetes cluster
- Have access to the account e.g. Azure or Google where you want to provision your infrastructure
First, you need to install Crossplane on a Kubernetes cluster. Note that this can be any cluster, it does not have to be the cluster that you will be using Crossplane on to provision Infrastructure. This just provides the Crossplane interface for you to be able to use Crossplane. For instance, in my case, I am going to be using Crossplane on my Docker Cluster and then provision Infrastructure on Azure.
Note that we are going the self-provisioned route:
kubectl create namespace crossplane-system
helm repo add crossplane-stable https://charts.crossplane.io/stable
helm repo update
helm install crossplane --namespace crossplane-system crossplane-stable/crossplane
Check that all resources are running properly
helm list -n crossplane-system
kubectl get all -n crossplane-system
Next, we can install the Crossplane CLI. It is a standalone crossplane binary (it replaced the old kubectl crossplane plugin in Crossplane v1.14):
curl -sfL "https://cli.crossplane.io/install.sh" | sh
sudo mv crossplane /usr/local/bin
Depending on the provider that you want to use, you can select Azure, GCP, AWS, or Alibaba (as of the time of writing)
On the same cluster that you installed the previous resources on:
crossplane xpkg install provider xpkg.crossplane.io/crossplane-contrib/provider-azure-containerservice:v2.7.0
Now wait until the Provider becomes healthy:
kubectl get provider.pkg --watch
Now it will get a bit tricks. If you are using Azure, make sure that you are logged into your account. For that, first install the Azure CLI :
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
And then login with:
az login
Once you are logged in, you can run the following commands
# create a service principal with the Owner role on your subscription
az ad sp create-for-rbac --json-auth --role Owner --scopes /subscriptions/<subscription-id> > "creds.json"
Note that some of them might not work if you are not at least an owner within your Azure account.
Lastly we need to set-up a Provider Secret and our Provider
**kubectl create secret generic azure-creds -n crossplane-system --from-file=key=./creds.json**
Now create the following file ProviderConfig.yaml
apiVersion: azure.m.upbound.io/v1beta1
kind: ClusterProviderConfig
metadata:
name: default
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: azure-creds
key: key
And then run
kubectl apply --file ./ProviderConfig.yaml
Note that you might have to modify the file path depending on where the file is stored at.
Provision Infrastructure
This step is pretty straight forward — we can set-up a Kubernetes Yaml file that allows us to create a Kubernetes Service i.e. a Cluster on Azure:
E.g. we will name is aks in our case
apiVersion: azure.m.upbound.io/v1beta1
kind: ResourceGroup
metadata:
name: anais-demo-rg
namespace: default
spec:
forProvider:
location: eastus
---
apiVersion: containerservice.azure.m.upbound.io/v1beta1
kind: KubernetesCluster
metadata:
name: anais-demo
namespace: default
spec:
forProvider:
location: eastus
resourceGroupNameRef:
name: anais-demo-rg
dnsPrefix: dt
defaultNodePool:
name: default
nodeCount: 3
vmSize: Standard_D2_v2
identity:
type: SystemAssigned
Have a look at the Azure documentation on how the YAML has to be defined to create different services.
Once we apply the YAML
kubectl apply --filename ./aks.yaml
We can go ahead and have a look at the created resources
kubectl get resourcegroups.azure.m.upbound.io -n default
We can watch the provisioning of our cluster through
watch kubectl get kubernetesclusters.containerservice.azure.m.upbound.io -n default
kubectl describe kubernetesclusters.containerservice.azure.m.upbound.io -n default
And connect to our Azure cluster as well
az aks get-credentials --resource-group myResourceGroup --name myAKSCluster
az aks get-credentials --resource-group anais-resource --name anais-crossplane-demo
Something that Terraform, Pulumi etc. does not have — this is a feature of Crossplane
- Correct cluster manually — do what should not be done
- Crossplane will keep whatever state we defined before, even if we change the state of our cluster through the UI
Add a node pool to see how crossplane will downscale the pool
az aks nodepool add \
--resource-group myResourceGroup \
--cluster-name myAKSCluster \
--name mynodepool \
--node-count 3
The next step is using GitOps to deploy our infrastructure
Install and application
I have already set-up the example Azure voting app. Now I will deploy those resources
kubectl apply -f ./app/voting.yaml
And we can get the service resource with
kubectl get service azure-vote-front --watch
Since this is a service of type LoadBalancer, we can access it through the External-IP
Uninstall Provider
Let’s check whether there are any managed resources before deleting the provider.
kubectl get managed
If there are any, please delete them first, so you don’t lose the track of them.
Then delete all the ProviderConfigs you created. An example command if you used
AWS Provider:
kubectl delete clusterproviderconfig.azure.m.upbound.io --all
List installed providers:
kubectl get provider.pkg
Delete the one you want to delete:
kubectl delete provider.pkg <provider-name>
Uninstall Crossplane
helm uninstall crossplane --namespace crossplane-system
kubectl delete namespace crossplane-system
Helm does not delete CRD objects. You can delete the ones Crossplane created with the following commands:
kubectl patch lock lock -p '{"metadata":{"finalizers": []}}' --type=merge
kubectl get crd -o name | grep crossplane.io | xargs kubectl delete
Connecting Crossplane with ArgoCD
An independent edition of the open-source 100 Days of Kubernetes book, published under the Apache License 2.0. Not affiliated with or endorsed by the original authors, the Linux Foundation or the Cloud Native Computing Foundation. Kubernetes® is a registered trademark of the Linux Foundation. About this edition · Advertise