Skip to content

Commit 3b8bad4

Browse files
authored
Merge pull request #976 from negz/guidance
Guide for updating v1 -> v2
2 parents b2fa381 + 5e5a548 commit 3b8bad4

File tree

4 files changed

+784
-14
lines changed

4 files changed

+784
-14
lines changed
Lines changed: 387 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,387 @@
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

Comments
 (0)