|
| 1 | +--- |
| 2 | +title: Upgrade to Crossplane v2 |
| 3 | +weight: 410 |
| 4 | +description: "Upgrade from Crossplane v1 to v2" |
| 5 | +--- |
| 6 | + |
| 7 | +Crossplane v2 introduces significant improvements while maintaining backward |
| 8 | +compatibility with most v1 configurations. This guide helps you upgrade from |
| 9 | +Crossplane v1.x to v2. |
| 10 | + |
| 11 | +Learn about [new features in Crossplane v2]({{<ref "../whats-new">}}) including |
| 12 | +namespaced resources, the ability to compose any Kubernetes resource, and new |
| 13 | +operational workflows. |
| 14 | + |
| 15 | +{{<hint "important">}} |
| 16 | +Only upgrade to Crossplane v2 from Crossplane v1.20, the final v1.x release. |
| 17 | +If you're running an earlier version, upgrade to v1.20 first. |
| 18 | +{{</hint>}} |
| 19 | + |
| 20 | +{{<hint "note">}} |
| 21 | +There's no automated tooling yet to migrate existing v1 cluster-scoped XRs and |
| 22 | +MRs to v2 namespaced style. You can upgrade to Crossplane v2 and |
| 23 | +start using the new namespaced features right away - your existing v1 |
| 24 | +resources continue working unchanged. See |
| 25 | +[crossplane/crossplane#6726](https://github.com/crossplane/crossplane/issues/6726) |
| 26 | +for migration tooling progress. |
| 27 | +{{</hint>}} |
| 28 | + |
| 29 | +## Prerequisites |
| 30 | + |
| 31 | +Before upgrading, ensure: |
| 32 | + |
| 33 | +* You're running Crossplane v1.20 |
| 34 | +* You're not using deprecated features (see [removed features](#removed-features)) |
| 35 | +* All packages use fully qualified image names |
| 36 | +* [Helm](https://helm.sh/docs/intro/install/) version v3.2.0 or later |
| 37 | + |
| 38 | +## Removed features |
| 39 | + |
| 40 | +Crossplane v2 removes these deprecated features: |
| 41 | + |
| 42 | +* [Native patch and transform composition](#native-patch-and-transform-composition) |
| 43 | +* [ControllerConfig type](#controllerconfig-type) |
| 44 | +* [External secret stores](#external-secret-stores) |
| 45 | +* [Default registry flag](#default-registry-flag) |
| 46 | + |
| 47 | +### Native patch and transform composition |
| 48 | +**Deprecated in**: v1.17 |
| 49 | +**Replaced by**: [Composition functions]({{<ref "../composition/compositions">}}) |
| 50 | + |
| 51 | +If you're using `spec.mode: Resources` in your Compositions, migrate to |
| 52 | +composition functions before upgrading. |
| 53 | + |
| 54 | +**Migration help**: use the Crossplane v1.20 CLI to automatically convert your |
| 55 | +Compositions: |
| 56 | + |
| 57 | +```shell |
| 58 | +# Convert patch and transform to function pipelines |
| 59 | +crossplane beta convert pipeline-composition old-composition.yaml -o new-composition.yaml |
| 60 | +``` |
| 61 | + |
| 62 | +<!-- vale Google.Headings = NO --> |
| 63 | +### ControllerConfig type |
| 64 | +<!-- vale Google.Headings = YES --> |
| 65 | +**Deprecated in**: v1.11 |
| 66 | +**Replaced by**: [DeploymentRuntimeConfig]({{<ref "../packages/providers#runtime-configuration">}}) |
| 67 | + |
| 68 | +Update any ControllerConfig resources to use DeploymentRuntimeConfig instead. |
| 69 | + |
| 70 | +**Migration help**: use the Crossplane v1.20 CLI to automatically convert your |
| 71 | +ControllerConfigs: |
| 72 | + |
| 73 | +```shell |
| 74 | +# Convert ControllerConfig to DeploymentRuntimeConfig |
| 75 | +crossplane beta convert deployment-runtime controller-config.yaml -o deployment-runtime-config.yaml |
| 76 | +``` |
| 77 | + |
| 78 | +### External secret stores |
| 79 | +**Status**: alpha feature, unmaintained |
| 80 | + |
| 81 | +If you're using external secret stores, migrate to native Kubernetes secrets |
| 82 | +or [External Secrets Operator](https://external-secrets.io/latest/) before upgrading. |
| 83 | + |
| 84 | +### Default registry flag |
| 85 | +**Removed**: `--registry` flag for default package registry |
| 86 | + |
| 87 | +All packages must now use fully qualified names including the registry |
| 88 | +host name. Check your packages with: |
| 89 | + |
| 90 | +```shell |
| 91 | +kubectl get pkg -o wide |
| 92 | +``` |
| 93 | + |
| 94 | +Update any packages without registry host names before upgrading. For example: |
| 95 | +- ❌ `crossplane-contrib/provider-aws-s3:v1.23.0` |
| 96 | +- ✅ `xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v1.23.0` |
| 97 | + |
| 98 | +## Who can upgrade |
| 99 | + |
| 100 | +You can upgrade to Crossplane v2 if you meet these criteria: |
| 101 | + |
| 102 | +* ✅ Running Crossplane v1.20 |
| 103 | +* ✅ Not using native patch and transform composition |
| 104 | +* ✅ Not using ControllerConfig resources |
| 105 | +* ✅ Not using external secret stores |
| 106 | +* ✅ All packages use fully qualified image names |
| 107 | + |
| 108 | +If you're using any removed features, migrate away from them first. |
| 109 | + |
| 110 | +## Upgrade approach |
| 111 | + |
| 112 | +The recommended upgrade approach: |
| 113 | + |
| 114 | +1. [Prepare for upgrade](#1-prepare-for-upgrade) |
| 115 | +2. [Upgrade Crossplane core](#2-upgrade-crossplane-core) |
| 116 | +3. [Configure managed resource activation policies](#3-configure-managed-resource-activation-policies) |
| 117 | +4. [Upgrade providers](#4-upgrade-providers) |
| 118 | +5. [Start using v2 features](#5-start-using-v2-features) |
| 119 | + |
| 120 | +### 1. Prepare for upgrade |
| 121 | + |
| 122 | +Review your cluster for [removed features](#removed-features) and address any |
| 123 | +that you're using. Each removed feature section includes commands to inspect |
| 124 | +your cluster and migration tools to help convert resources. |
| 125 | + |
| 126 | +### 2. Upgrade Crossplane core |
| 127 | + |
| 128 | +Add the Crossplane Helm repository: |
| 129 | + |
| 130 | +```shell |
| 131 | +helm repo add crossplane-stable https://charts.crossplane.io/stable |
| 132 | +helm repo update |
| 133 | +``` |
| 134 | + |
| 135 | +Upgrade to Crossplane v2: |
| 136 | + |
| 137 | +```shell |
| 138 | +helm upgrade crossplane \ |
| 139 | + --namespace crossplane-system \ |
| 140 | + crossplane-stable/crossplane |
| 141 | +``` |
| 142 | + |
| 143 | +Verify the upgrade: |
| 144 | + |
| 145 | +```shell |
| 146 | +kubectl get pods -n crossplane-system |
| 147 | +``` |
| 148 | + |
| 149 | +### 3. Configure managed resource activation policies |
| 150 | + |
| 151 | +Crossplane v2 automatically creates a default [MRAP]({{<ref "../managed-resources/managed-resource-activation-policies">}}) that activates all managed |
| 152 | +resources (`*`). Before installing v2 providers, you can optionally customize |
| 153 | +this for better cluster resource efficiency. |
| 154 | + |
| 155 | +Check what managed resources you use: |
| 156 | + |
| 157 | +```shell |
| 158 | +# See your managed resource types |
| 159 | +kubectl get managed |
| 160 | +``` |
| 161 | + |
| 162 | +Optionally, replace the default MRAP with a targeted one that activates only |
| 163 | +the resources you need: |
| 164 | + |
| 165 | +```shell |
| 166 | +# Delete the default catch-all MRAP |
| 167 | +kubectl delete mrap default |
| 168 | +``` |
| 169 | + |
| 170 | +Create a targeted MRAP: |
| 171 | + |
| 172 | +```yaml |
| 173 | +apiVersion: apiextensions.crossplane.io/v1alpha1 |
| 174 | +kind: ManagedResourceActivationPolicy |
| 175 | +metadata: |
| 176 | + name: my-resources |
| 177 | +spec: |
| 178 | + activate: |
| 179 | + # Legacy cluster-scoped resources (existing v1 resources) |
| 180 | + - buckets.s3.aws.upbound.io |
| 181 | + - instances.ec2.aws.upbound.io |
| 182 | + |
| 183 | + # Modern namespaced resources (new v2 resources) |
| 184 | + - buckets.s3.aws.m.upbound.io |
| 185 | + - instances.ec2.aws.m.upbound.io |
| 186 | +``` |
| 187 | +
|
| 188 | +{{<hint "tip">}} |
| 189 | +Notice the distinction: `s3.aws.upbound.io` (legacy cluster-scoped) vs |
| 190 | +`s3.aws.m.upbound.io` (v2 namespaced). The `.m.` indicates modern |
| 191 | +namespaced managed resources. |
| 192 | +{{</hint>}} |
| 193 | + |
| 194 | +### 4. Upgrade providers |
| 195 | + |
| 196 | +Upgrade your providers to versions that support both namespaced and |
| 197 | +cluster-scoped managed resources: |
| 198 | + |
| 199 | +```shell |
| 200 | +# Check current provider versions |
| 201 | +kubectl get providers |
| 202 | +``` |
| 203 | + |
| 204 | +Update your provider manifests to use v2 versions: |
| 205 | + |
| 206 | +```yaml |
| 207 | +apiVersion: pkg.crossplane.io/v1 |
| 208 | +kind: Provider |
| 209 | +metadata: |
| 210 | + name: crossplane-contrib-provider-aws-s3 |
| 211 | +spec: |
| 212 | + package: xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v2.0.0 |
| 213 | +``` |
| 214 | + |
| 215 | +{{<hint "note">}} |
| 216 | +Provider v2 releases support both legacy cluster-scoped and new namespaced |
| 217 | +managed resources. Your existing cluster-scoped MRs continue working unchanged. |
| 218 | +{{</hint>}} |
| 219 | + |
| 220 | +### 5. Start using v2 features |
| 221 | + |
| 222 | +After upgrading, you can begin using Crossplane v2 features: |
| 223 | + |
| 224 | +- **Namespaced managed resources**: Try the [managed resources getting started guide]({{<ref "../get-started/get-started-with-managed-resources">}}) |
| 225 | +- **Composition functions**: Follow the [composition getting started guide]({{<ref "../get-started/get-started-with-composition">}}) |
| 226 | +- **Operations**: Explore the [operations getting started guide]({{<ref "../get-started/get-started-with-operations">}}) |
| 227 | +- **Managed resource definitions**: See the [MRDs guide]({{<ref "./disabling-unused-managed-resources">}}) |
| 228 | + |
| 229 | +## Updating compositions for v2 |
| 230 | + |
| 231 | +Existing Compositions work with Crossplane v2 with minimal changes. v2 managed |
| 232 | +resources are schematically identical to v1 managed resources - they're just |
| 233 | +namespaced. |
| 234 | + |
| 235 | +To use v2 namespaced managed resources in compositions: |
| 236 | + |
| 237 | +1. **Update the API group** from `.crossplane.io` to `.m.crossplane.io` |
| 238 | +2. **Check the API version** - v2 namespaced providers often reset the API |
| 239 | + version to `v1beta1` |
| 240 | + |
| 241 | +For example `provider-aws-s3:v2.0.0` has two `Bucket` MRs: |
| 242 | + |
| 243 | +* `apiVersion: s3.aws.upbound.io/v1beta2` - Legacy, cluster scoped |
| 244 | +* `apiVersion: s3.aws.m.upbound.io/v1beta1` - Namespaced |
| 245 | + |
| 246 | +The `spec.forProvider` and `status.atProvider` fields are schematically |
| 247 | +identical. |
| 248 | + |
| 249 | +{{<hint "tip">}} |
| 250 | +Use `kubectl get mrds` to see available MR API versions. |
| 251 | +{{</hint>}} |
| 252 | + |
| 253 | +{{<hint "note">}} |
| 254 | +Not all providers use `.crossplane.io` domains. For example, `provider-aws-s3` |
| 255 | +uses `.upbound.io` domains for historical reasons. The general pattern for |
| 256 | +namespaced resources is adding `.m` to the existing domain: `<domain>` becomes |
| 257 | +`m.<domain>` (like `upbound.io` → `m.upbound.io` or `crossplane.io` → |
| 258 | +`m.crossplane.io`). |
| 259 | +{{</hint>}} |
| 260 | + |
| 261 | +**Before (v1 cluster-scoped)**: |
| 262 | +```yaml |
| 263 | +apiVersion: apiextensions.crossplane.io/v1 |
| 264 | +kind: Composition |
| 265 | +metadata: |
| 266 | + name: my-app |
| 267 | +spec: |
| 268 | + compositeTypeRef: |
| 269 | + apiVersion: example.crossplane.io/v1 |
| 270 | + kind: XBucket |
| 271 | + mode: Pipeline |
| 272 | + pipeline: |
| 273 | + - step: create-bucket |
| 274 | + functionRef: |
| 275 | + name: crossplane-contrib-function-go-templating |
| 276 | + input: |
| 277 | + apiVersion: gotemplating.fn.crossplane.io/v1beta1 |
| 278 | + kind: GoTemplate |
| 279 | + source: Inline |
| 280 | + inline: |
| 281 | + template: | |
| 282 | + apiVersion: s3.aws.upbound.io/v1beta2 |
| 283 | + kind: Bucket |
| 284 | + metadata: |
| 285 | + name: {{ .observed.composite.resource.metadata.name }} |
| 286 | + spec: |
| 287 | + forProvider: |
| 288 | + region: us-east-2 |
| 289 | +``` |
| 290 | + |
| 291 | +**After (v2 namespaced)**: |
| 292 | +```yaml |
| 293 | +apiVersion: apiextensions.crossplane.io/v1 |
| 294 | +kind: Composition |
| 295 | +metadata: |
| 296 | + name: my-app |
| 297 | +spec: |
| 298 | + compositeTypeRef: |
| 299 | + apiVersion: example.crossplane.io/v1 |
| 300 | + kind: Bucket |
| 301 | + mode: Pipeline |
| 302 | + pipeline: |
| 303 | + - step: create-bucket |
| 304 | + functionRef: |
| 305 | + name: crossplane-contrib-function-go-templating |
| 306 | + input: |
| 307 | + apiVersion: gotemplating.fn.crossplane.io/v1beta1 |
| 308 | + kind: GoTemplate |
| 309 | + source: Inline |
| 310 | + inline: |
| 311 | + template: | |
| 312 | + apiVersion: s3.aws.m.upbound.io/v1beta1 # Added .m, reset to v1beta1 |
| 313 | + kind: Bucket |
| 314 | + metadata: |
| 315 | + name: {{ .observed.composite.resource.metadata.name }} |
| 316 | + spec: |
| 317 | + forProvider: |
| 318 | + region: us-east-2 |
| 319 | +``` |
| 320 | + |
| 321 | +{{<hint "tip">}} |
| 322 | +**Namespace handling in compositions**: |
| 323 | +- **Namespaced XRs**: Don't specify `metadata.namespace` in templates. |
| 324 | + Crossplane ignores template namespaces and uses the XR's namespace. |
| 325 | +- **Modern cluster-scoped XRs** (`scope: Cluster`): Can compose resources in any |
| 326 | + namespace. Include `metadata.namespace` in templates to specify the target |
| 327 | + namespace. |
| 328 | +- **Legacy cluster-scoped XRs** (`scope: LegacyCluster`): Can't compose |
| 329 | + namespaced resources. |
| 330 | +{{</hint>}} |
| 331 | + |
| 332 | +## Legacy resource behavior |
| 333 | + |
| 334 | +Your existing v1 resources continue working in Crossplane v2: |
| 335 | + |
| 336 | +* **Legacy cluster-scoped XRs**: Continue working with claims support |
| 337 | +* **Legacy cluster-scoped MRs**: Continue working unchanged |
| 338 | +* **Existing Compositions**: Continue working with legacy XRs |
| 339 | + |
| 340 | +These resources use `LegacyCluster` scope internally and maintain full |
| 341 | +backward compatibility. |
| 342 | + |
| 343 | +For example, existing v1-style XRDs continue working with claims: |
| 344 | + |
| 345 | +```yaml |
| 346 | +apiVersion: apiextensions.crossplane.io/v1 |
| 347 | +kind: CompositeResourceDefinition |
| 348 | +metadata: |
| 349 | + name: xdatabases.example.crossplane.io |
| 350 | +spec: |
| 351 | + # v1 XRDs default to LegacyCluster scope (shown explicitly) |
| 352 | + scope: LegacyCluster |
| 353 | + group: example.crossplane.io |
| 354 | + names: |
| 355 | + kind: XDatabase |
| 356 | + plural: xdatabases |
| 357 | + claimNames: |
| 358 | + kind: Database |
| 359 | + plural: databases |
| 360 | + # schema definition... |
| 361 | +``` |
| 362 | + |
| 363 | +Users can create claims that work as before: |
| 364 | + |
| 365 | +```yaml |
| 366 | +apiVersion: example.crossplane.io/v1 |
| 367 | +kind: Database |
| 368 | +metadata: |
| 369 | + name: my-database |
| 370 | + namespace: production |
| 371 | +spec: |
| 372 | + engine: postgres |
| 373 | + size: large |
| 374 | +``` |
| 375 | + |
| 376 | + |
| 377 | +## Next steps |
| 378 | + |
| 379 | +After upgrading: |
| 380 | + |
| 381 | +1. **Explore namespaced resources**: Try creating XRs and MRs in namespaces |
| 382 | +2. **Build app compositions**: Use v2's ability to compose any Kubernetes resource |
| 383 | +3. **Try Operations**: Experiment with operational workflows |
| 384 | +4. **Plan migration**: Consider which existing resources to migrate to v2 patterns |
| 385 | + |
| 386 | +Read more about [what's new in v2]({{<ref "../whats-new">}}) and explore the |
| 387 | +updated [composition documentation]({{<ref "../composition/compositions">}}). |
0 commit comments