Migrating to Upbound control planes
The Upbound migration tool is a CLI command that helps you migrate your existing Crossplane control plane to a control plane in Upbound. This tool works for migrating from self-managed Crossplane installations as well as between Upbound managed control planes (MCPs).
This guide applies to all supported versions (v1.9-v1.14+). Migration procedures are consistent across versions, though you may want to upgrade to a newer version after migration to get the latest features.
For version-specific features and migration considerations, see the . the full compatibility matrix, see the .
To migrate a control plane to Upbound, you must:
- Export your existing Crossplane control plane configuration/state into an archive file.
- Import the archive file into a control plane running in Upbound.
The migration tool is available in the up CLI as
up controlplane migration exportandup controlplane migration importcommands.
Prerequisites
Before you begin, you must have the following:
- The up CLI version 0.23.0 or later.
Migration process
To migrate an existing Crossplane control plane to a control plane in Upbound, do the following:
-
Run the
up controlplane migration exportcommand to export your existing Crossplane control plane configuration/state into an archive file:up controlplane migration export --kubeconfig <path-to-source-kubeconfig> --output <path-to-archive-file>The command exports your existing Crossplane control plane configuration/state into an archive file.
::: note
By default, the export command doesn't make any changes to your existing Crossplane control plane state, leaving it intact. Use the --pause-before-export flag to pause the reconciliation on managed resources before exporting the archive file.
This safety mechanism ensures the control plane you migrate state to doesn't assume ownership of resources before you're ready. :::
-
Use the control plane create command to create a managed control plane in Upbound:
up controlplane create my-controlplane -
Use
up ctxto connect to the control plane created in the previous step:up ctx "<your-org>/<your-space>/<your-group>/my-controlplane"The command configures your local
kubeconfigto connect to the control plane. -
Run the following command to import the archive file into the control plane:
up controlplane migration import --input <path-to-archive-file>
By default, the import command leaves the control plane in an inactive state by pausing the reconciliation on managed
resources. This pause gives you an opportunity to review the imported configuration/state before activating the control plane.
Use the --unpause-after-import flag to change the default behavior and activate the control plane immediately after
importing the archive file.
-
Review and validate the imported configuration/state. When you are ready, activate your managed control plane by running the following command:
kubectl annotate managed --all crossplane.io/paused-At this point, you can delete the source Crossplane control plane.
CLI options
Filtering
The migration tool captures the state of a Control Plane. The only filtering supported is Kubernetes namespace and Kubernetes resource Type filtering.
You can exclude namespaces using the --exclude-namespaces CLI option. This can prevent the CLI from including unwanted resources in the export.
--exclude-namespaces=kube-system,kube-public,kube-node-lease,local-path-storage,...
# A list of specific namespaces to exclude from the export. Defaults to 'kube-system', 'kube-public','kube-node-lease', and 'local-path-storage'.
You can exclude Kubernetes Resource types by using the --exclude-resources CLI option:
--exclude-resources=EXCLUDE-RESOURCES,...
# A list of resource types to exclude from the export in "resource.group" format. No resources are excluded by default.
For example, here's an example for excluding the CRDs installed by Crossplane functions (since they're not needed):
up controlplane migration export \
--exclude-resources=gotemplates.gotemplating.fn.crossplane.io,kclinputs.template.fn.crossplane.io
You must specify resource names in lowercase "resource.group" format (for example, gotemplates.gotemplating.fn.crossplane.io). Using only the resource kind (for example, GoTemplate) isn't supported.
Exclude function input CRDs (inputs.template.fn.crossplane.io, resources.pt.fn.crossplane.io, gotemplates.gotemplating.fn.crossplane.io, kclinputs.template.fn.crossplane.io) from migration exports. Upbound automatically recreates these resources during import. Function input CRDs typically have owner references to function packages and may have restricted RBAC access. Upbound installs these CRDs during the import when function packages are restored.
After export, users can also change the archive file to only include necessary resources.
Export non-Crossplane resources
Use the --include-extra-resources= CLI option to select other CRD types to include in the export.
Set the kubecontext
Currently --context isn't supported in the migration CLI. You should be able to use the --kubeconfig CLI option to use a file that's set to the correct context. example:
up controlplane migration export --kubeconfig
Use this in tandem with up ctx to export a control plane's kubeconfig:
up ctx --kubeconfig ~/.kube/config
# To list the current contet
up ctx . --kubeconfig ~/.kube/config
Export archive
The migration CLI exports an archive upon successful completion. Below is an example export of a control plane that excludes several CRD types and skips the confirmation prompt. A file gets written to the working directory, unless you select another output file:
View the example export
$ up controlplane migration export --exclude-resources=gotemplates.gotemplating.fn.crossplane.io,kclinputs.template.fn.crossplane.io --yes
Exporting control plane state...
✓ Scanning control plane for types to export... 121 types found! 👀
✓ Exporting 121 Crossplane resources...60 resources exported! 📤
✓ Exporting 3 native resources...8 resources exported! 📤
✓ Archiving exported state... archived to "xp-state.tar.gz"! 📦
When an export occurs, a file named xp-state.tar.gz by default gets created in the working directory. You can unzip the file and all the contents of the export are all text YAML files.
- Each CRD (for example
vpcs.ec2.aws.upbound.io) gets its own directory which contains:- A
metadata.yamlfile that contains Kubernetes Object Metadata - A list of Kubernetes Categories the resource belongs to
- A
- A
clusterdirectory that contains YAML manifests for all resources provisioned using the CRD.
Sample contents for a Cluster with a single XNetwork Composite from
configuration-aws-network is show below:
View the example cluster content
├── compositionrevisions.apiextensions.crossplane.io
│ ├── cluster
│ │ ├── kcl.xnetworks.aws.platform.upbound.io-4ca6a8a.yaml
│ │ └── xnetworks.aws.platform.upbound.io-9859a34.yaml
│ └── metadata.yaml
├── configurations.pkg.crossplane.io
│ ├── cluster
│ │ └── configuration-aws-network.yaml
│ └── metadata.yaml
├── deploymentruntimeconfigs.pkg.crossplane.io
│ ├── cluster
│ │ └── default.yaml
│ └── metadata.yaml
├── export.yaml
├── functions.pkg.crossplane.io
│ ├── cluster
│ │ ├── crossplane-contrib-function-auto-ready.yaml
│ │ ├── crossplane-contrib-function-go-templating.yaml
│ │ └── crossplane-contrib-function-kcl.yaml
│ └── metadata.yaml
├── internetgateways.ec2.aws.upbound.io
│ ├── cluster
│ │ └── borrelli-backup-test-xgl4q.yaml
│ └── metadata.yaml
├── mainroutetableassociations.ec2.aws.upbound.io
│ ├── cluster
│ │ └── borrelli-backup-test-t2qh7.yaml
│ └── metadata.yaml
├── namespaces
│ └── cluster
│ ├── crossplane-system.yaml
│ ├── default.yaml
│ └── upbound-system.yaml
├── providerconfigs.aws.upbound.io
│ ├── cluster
│ │ └── default.yaml
│ └── metadata.yaml
├── providerconfigusages.aws.upbound.io
│ ├── cluster
│ │ ├── 0a2a3ec6-ef13-45f9-9cf0-63af7f4a6b6b.yaml
...redacted
│ │ └── f7092b0f-3a78-4bfe-82c8-57e5085a9b11.yaml
│ └── metadata.yaml
├── providers.pkg.crossplane.io
│ ├── cluster
│ │ ├── upbound-provider-aws-ec2.yaml
│ │ └── upbound-provider-family-aws.yaml
│ └── metadata.yaml
├── routes.ec2.aws.upbound.io
│ ├── cluster
│ │ └── borrelli-backup-test-dt9cj.yaml
│ └── metadata.yaml
├── routetableassociations.ec2.aws.upbound.io
│ ├── cluster
│ │ ├── borrelli-backup-test-mr2sd.yaml
│ │ ├── borrelli-backup-test-ngq5h.yaml
│ │ ├── borrelli-backup-test-nrkgg.yaml
│ │ └── borrelli-backup-test-wq752.yaml
│ └── metadata.yaml
├── routetables.ec2.aws.upbound.io
│ ├── cluster
│ │ └── borrelli-backup-test-dv4mb.yaml
│ └── metadata.yaml
├── secrets
│ └── namespaces
│ ├── crossplane-system
│ │ ├── cert-token-signing-gateway-pub.yaml
│ │ ├── mxp-hostcluster-certs.yaml
│ │ ├── package-pull-secret.yaml
│ │ └── xgql-tls.yaml
│ └── upbound-system
│ └── aws-creds.yaml
├── securitygrouprules.ec2.aws.upbound.io
│ ├── cluster
│ │ ├── borrelli-backup-test-472f4.yaml
│ │ └── borrelli-backup-test-qftmw.yaml
│ └── metadata.yaml
├── securitygroups.ec2.aws.upbound.io
│ ├── cluster
│ │ └── borrelli-backup-test-w5jch.yaml
│ └── metadata.yaml
├── storeconfigs.secrets.crossplane.io
│ ├── cluster