Releasing Crossplane Extensions
This document applies to the Crossplane master
branch and not to the latest release v1.19.
Crossplane extensions are built as OCI images in the xpkg format. Authors and maintainers of Crossplane extensions must push their packages to an OCI registry before they can be used and referenced by Crossplane.
Typical Workflow
This guide covers configuring a GitHub Action for building Crossplane
providers and functions and pushing them to an OCI registry such as ghcr.io
.
A typical GitHub workflow definition contains the following steps:
- Fetching the source repository
- Authenticating to a remote registry
- Building and packaging artifacts
- Pushing (publishing) the artifact
push
authorization scope.Fortunately, the template repositories for providers and functions provide
a functional GitHub Action in .github/workflows/ci.yml
. The following
sections of this guide cover configuration options and conventions for each.
Common Configuration
All workflows require references to credentials for a remote registry.
Typically, these are stored as GitHub Actions Secrets, and authentication
is performed via thedocker/login-action
action.
For example, adding the following step to a pipeline will authenticate
the job to ghcr.io
using the workflow’s ephemeral GitHub OIDC token.
1 - name: Login to GHCR
2 uses: docker/login-action@v3
3 with:
4 registry: ghcr.io
5 username: ${{ github.repository_owner }}
6 password: ${{ secrets.GITHUB_TOKEN }}
ghcr.io
. This can be configured in the GitHub repository’s settings, or
declared explicitly in the workflow definition YAML file.For other registries, it is still best practice to reference credentials as custom Secret variables. For example:
1 - name: Login to Upbound
2 uses: docker/login-action@v3
3 if: env.XPKG_ACCESS_ID != ''
4 with:
5 registry: xpkg.upbound.io
6 username: ${{ env.XPKG_ACCESS_ID }}
7 password: ${{ secrets.XPKG_TOKEN }}
Branching Conventions
Repositories for Crossplane extensions follow similar branching conventions
to upstream Crossplane, where the release process is predicated on the workflow
executing in branches with the release-*
prefix. main
is often included,
though a conventional release process would not build and push off of tags on
main
.
For example, when releasing v0.1.0
of an extension, the conventional
process is to cut a release branch release-0.1
at the git commit
where it will be built, and tag it as v0.1.0
.
crossplane-contrib/function-python
is a good example.Configuring Workflows for Functions
Function workflow definitions will differ based on the base language the function is implemented in. For example, a Python function will require a Python environment in the GitHub Action runner:
1 - name: Setup Python
2 uses: actions/setup-python@v5
3 with:
4 python-version: ${{ env.PYTHON_VERSION }}
5
6 - name: Setup Hatch
7 run: pipx install hatch==1.7.0
8
9 - name: Lint
10 run: hatch run lint:check
While the template repository provides a working pipeline definition, users may choose to customize their environment with different tooling.
Functions also require a runtime image of the core business logic to be
built and embedded into the Function package. The default workflow definition
will build for two platforms: linux/amd64
and linux/arm64
.
1 - name: Build Runtime
2 id: image
3 uses: docker/build-push-action@v6
4 with:
5 context: .
6 platforms: linux/${{ matrix.arch }}
7 cache-from: type=gha
8 cache-to: type=gha,mode=max
9 target: image
10 build-args:
11 PYTHON_VERSION=${{ env.PYTHON_VERSION }}
12 outputs: type=docker,dest=runtime-${{ matrix.arch }}.tar
Configuring Workflows for Providers
Providers, unlike Functions, use custom make
targets in the build submodule
for building and pushing Crossplane Provider packages.
Configuring the workflow for a specific registry involves two steps:
- Updating the registry variables in the top-level
Makefile
. - Referencing GitHub Actions Secrets for authorized credentials to the registry.
Configure Target Registry
The provider template repository includes a top-level Makefile
. Edit
the following variables to define the target registry:
XPKG_REG_ORGS
- a space-delimited list of target repositories.XPKG_REG_ORGS_NO_PROMOTE
- for registries that do not use or infer channel tags, such asxpkg.upbound.io
.
For example, the following dual-pushes to xpkg.upbound.io
as well as
index.docker.io
:
1XPKG_REG_ORGS ?= xpkg.upbound.io/crossplane-contrib index.docker.io/crossplanecontrib
2
3XPKG_REG_ORGS_NO_PROMOTE ?= xpkg.upbound.io/crossplane-contrib
Reusable Workflows
The crossplane-contrib/provider-workflows repository provide reusable workflow definitions that can be called from a custom CI pipeline.
For example, the following snippet references the callable workflow to
build and push the provider-kubernetes
package to both ghcr.io
and
xpkg.upbound.io
:
1jobs:
2 publish-provider-package:
3 uses: crossplane-contrib/provider-workflows/.github/workflows/publish-provider-non-family.yml@main
4 with:
5 repository: provider-kubernetes
6 version: ${{ github.event.inputs.version }}
7 go-version: ${{ github.event.inputs.go-version }}
8 cleanup-disk: true
9 secrets:
10 GHCR_PAT: ${{ secrets.GITHUB_TOKEN }}
11 XPKG_UPBOUND_TOKEN: ${{ secrets.XPKG_UPBOUND_TOKEN }}
ghcr.io
by default.
Ensure that the default GitHub Actions OIDC token is granted the
packages: write
permission.Troubleshooting
{{ secrets.* }}
variable substitutions match
what is configured in GitHub.