How do you install Crossplane on a Kubernetes cluster?
Quick Answer
Crossplane is installed on a Kubernetes cluster using Helm, the Kubernetes package manager. You add the Crossplane Helm repository, install the chart into a dedicated namespace called crossplane-system, and then verify that the Crossplane pods and CRDs are running. After installation, you install Providers and configure credentials to start managing cloud infrastructure.
Detailed Answer
Installing Crossplane is straightforward, but understanding what the installation actually does helps you troubleshoot issues and plan capacity. The process has three phases: installing the Crossplane core, installing one or more Providers, and configuring authentication. Each phase builds on the previous one, and skipping or misconfiguring any step results in a non-functional setup that cannot provision infrastructure.
The first phase installs the Crossplane core using Helm. Helm deploys two main components into the crossplane-system namespace: the Crossplane pod itself, which runs the core controllers responsible for package management and Composite Resource reconciliation, and the RBAC manager pod, which automatically creates and manages the Kubernetes RBAC roles needed by Providers. The Crossplane core also registers several foundational CRDs, including Provider, ProviderConfig, Composition, CompositeResourceDefinition, and others. These CRDs are the building blocks that everything else depends on. For a team running the checkout-service and payments-api in the same cluster, the core installation is a one-time operation shared by all teams.
The second phase installs Providers by creating Provider resources that reference OCI images from a registry, typically xpkg.upbound.io. When you create a Provider resource, the Crossplane package manager downloads the Provider image, extracts the CRDs and controller binary, registers the CRDs with the Kubernetes API server, and deploys the controller as a new pod in the crossplane-system namespace. For example, installing provider-aws-rds adds CRDs like Instance, SubnetGroup, and ParameterGroup, and starts a controller pod that knows how to reconcile these resources with the AWS RDS API. Each Provider runs as its own pod, so you can install provider-aws-s3 and provider-aws-rds independently, each with its own resource allocation and lifecycle.
The third phase configures authentication by creating ProviderConfig resources. Without a ProviderConfig, Providers have no credentials and cannot make API calls to the cloud. The ProviderConfig references a Kubernetes Secret containing credentials, or on managed Kubernetes services like EKS, it can use IAM Roles for Service Accounts (IRSA) for a more secure, keyless authentication approach. Platform teams managing infrastructure for the order-processing-service and inventory-sync typically create separate ProviderConfigs for production and development accounts, ensuring that development testing never accidentally modifies production resources.
There are important prerequisites and sizing considerations before installation. Crossplane requires Kubernetes 1.16 or later, and the cluster needs sufficient resources to run the Crossplane pods and Provider controllers. Each Provider consumes memory proportional to the number of CRDs it registers and the number of Managed Resources it watches. A provider-aws with all resource groups can use over 1 GB of RAM, which is why the Provider family pattern of installing granular packages is recommended. The cluster also needs outbound internet access to pull Provider images and make cloud API calls. For air-gapped environments where the user-auth-service runs in a restricted network, you can mirror Provider images to a private registry and configure Crossplane to pull from there instead.
After installation, verification is critical. Check that the Crossplane pods are Running and Ready, that the Providers show Installed and Healthy status, and that the expected CRDs are registered. A common installation failure occurs when the Helm release succeeds but the Provider pod crashes due to insufficient memory or missing RBAC permissions. Running kubectl describe on the Provider resource and checking the pod logs are the first debugging steps when things go wrong.