Install Crossplane from source code

This document is for an unreleased version of Crossplane.

This document applies to the Crossplane master branch and not to the latest release v2.2.

Building Crossplane from the source code gives you complete control over the build and installation process.

You build the Crossplane container image and Helm chart directly from the source code, push the image to your own registry, and install to your Kubernetes cluster.

Important
Installing Crossplane from source is an advanced installation path for users who require complete control over the build and deployment process. Most users should follow the standard installation instructions.

This approach is useful when you want to:

  • Control the entire build and deployment pipeline
  • Use your own container registry and cluster
  • Deploy to offline or restricted environments
  • Build from a specific commit or branch

Prerequisites

Building Crossplane from source requires:

Crossplane uses Nix for its build system. Nix produces reproducible, sandboxed builds without requiring a system Go toolchain or other language-specific dependencies.

Tip
If you can’t install Nix, the Crossplane repository includes a ./nix.sh wrapper that runs Nix inside a Docker container. Anywhere this guide uses nix <command>, substitute ./nix.sh <command>. The wrapper has some limitations around credential handling and build artifact persistence, so installing Nix natively is the recommended path.

Clone the Crossplane repository

Clone the Crossplane repository and optionally checkout a specific release.

1git clone https://github.com/crossplane/crossplane.git
2cd crossplane
Tip

To build a specific release, checkout the release tag before building.

1git checkout v2.0.2

Determine artifacts destination

Identify the registry and version tag where you will push your built software artifacts and save them in environment variables:

1export REGISTRY="your-registry.com/your-org"; \
2  export VERSION="v2.0.0-yourtag"

${VERSION} should follow the format vMAJOR.MINOR.PATCH[-suffix], for example v2.0.0-yourtag.

The build embeds ${VERSION} into the Crossplane binary and uses it as the container image tag and Helm chart version. Nix’s sandboxed builds only read from files tracked by git, so you must write ${VERSION} into flake.nix before building:

1sed -i "s|buildVersion = null;|buildVersion = \"${VERSION}\";|" flake.nix
Tip

On macOS, use sed -i '' instead of sed -i:

1sed -i '' "s|buildVersion = null;|buildVersion = \"${VERSION}\";|" flake.nix

Build the artifacts

Build Crossplane binaries, container images, and Helm chart for all supported platforms:

1nix build

The first run downloads the build toolchain and takes a few minutes. Later runs reuse the Nix store cache and complete in seconds.

The build output is under ./result/:

  • result/bin/<os>_<arch>/ contains the crossplane and crank binaries for each supported platform.
  • result/charts/crossplane-<version>.tgz is the Helm chart.
  • result/images/linux_<arch>/image.tar.gz is the container image tarball for each supported Linux architecture.

The build doesn’t load images into your local Docker daemon. The push step loads the image tarballs in result/images/ automatically.

Push the image to your registry

Important
If your registry requires authentication, log in with docker login before pushing.

Push the per-architecture images and assemble a multi-arch manifest with a single command:

1nix run .#push-images -- ${REGISTRY}/crossplane
Note

If your host Docker uses a credential helper (for example Docker Desktop on macOS), the helper isn’t available on the sandboxed PATH used by nix run .#push-images. Bypass the helper for the login and push by writing auth directly to a temporary Docker configuration:

1export DOCKER_CONFIG=$(mktemp -d)
2cat > $DOCKER_CONFIG/config.json <<EOF
3{"credHelpers":{"${REGISTRY%%/*}":""}}
4EOF
5docker login ${REGISTRY%%/*}
6nix run .#push-images -- ${REGISTRY}/crossplane
7unset DOCKER_CONFIG

This loads each per-architecture image tarball, tags it with ${REGISTRY}/crossplane:${VERSION}-<arch>, pushes each, and then creates and pushes a multi-arch manifest at ${REGISTRY}/crossplane:${VERSION}.

Install Crossplane with the custom image

Install Crossplane to your cluster using the built Helm chart and your custom image:

1helm install crossplane result/charts/crossplane-${VERSION#v}.tgz \
2  --namespace crossplane-system \
3  --create-namespace \
4  --set image.repository=${REGISTRY}/crossplane \
5  --set image.tag=${VERSION} \
6  --set image.pullPolicy=IfNotPresent
Important

If your registry requires authentication, create an imagePullSecret before installing.

1kubectl create secret docker-registry regcred \
2  --docker-server=${REGISTRY} \
3  --docker-username=<username> \
4  --docker-password=<password> \
5  --namespace crossplane-system

Add the secret reference to the helm install command.

1--set imagePullSecrets[0].name=regcred

Verify the installation

View the installed Crossplane pods with kubectl get pods.

1kubectl get pods -n crossplane-system
2NAME                                       READY   STATUS    RESTARTS   AGE
3crossplane-5644774bd4-zvcwc                1/1     Running   0          72s
4crossplane-rbac-manager-84dc89c564-b9x6q   1/1     Running   0          72s

Verify the Crossplane deployment is using your custom image.

1kubectl get deployment crossplane -n crossplane-system -o jsonpath='{.spec.template.spec.containers[0].image}'
2your-registry.com/your-org/crossplane:v2.0.0-yourtag

Optional: Install the Crossplane CLI

The crossplane CLI provides commands for managing Crossplane resources. The build in the previous steps already produced the CLI binary (named crank) for all supported platforms under result/bin/. Copy the binary for your system to your path.

For macOS ARM64:

1sudo cp result/bin/darwin_arm64/crank /usr/local/bin/crossplane
2chmod +x /usr/local/bin/crossplane

For Linux AMD64:

1sudo cp result/bin/linux_amd64/crank /usr/local/bin/crossplane
2chmod +x /usr/local/bin/crossplane

Verify the installation.

1crossplane version
2v2.0.0-yourtag

Clean up the working tree

The earlier sed step modified flake.nix, a file that git tracks. After all build, push, and install steps are complete, revert the change to keep your working tree clean:

1git checkout flake.nix

Reverting this file before completing the push or install steps causes Nix to rebuild the flake with buildVersion = null, which produces a different version that doesn’t match the artifacts you already built.