|
| 1 | +--- |
| 2 | +title: Change Provider Registries |
| 3 | +weight: 415 |
| 4 | +description: "Safely change from one provider to a compatible provider in a different registry" |
| 5 | +--- |
| 6 | + |
| 7 | +When changing a provider's OCI reference to a different registry, the provider |
| 8 | +itself updates normally with a new revision. However, any **dependencies that |
| 9 | +Crossplane automatically installs** (like family providers) are treated as |
| 10 | +entirely separate packages, requiring careful coordination. |
| 11 | + |
| 12 | +This problem affects: |
| 13 | + |
| 14 | +* **Providers with family dependencies**: Most cloud providers depend on a |
| 15 | + family provider (like `provider-gcp-compute` depending on `provider-family-gcp`) |
| 16 | +* **Providers installed as Configuration dependencies**: When a Configuration |
| 17 | + package lists providers as dependencies |
| 18 | + |
| 19 | +**Single providers without dependencies change automatically** - no manual |
| 20 | +intervention needed. |
| 21 | + |
| 22 | +The most common conflict occurs with **family provider dependencies**. For |
| 23 | +example, when changing `provider-gcp-compute` from Upbound to Crossplane |
| 24 | +Contrib, both versions depend on different family providers: |
| 25 | + |
| 26 | +* Old: `xpkg.upbound.io/upbound/provider-gcp-compute` → depends on `upbound/provider-family-gcp` |
| 27 | +* New: `xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute` → depends on `crossplane-contrib/provider-family-gcp` |
| 28 | + |
| 29 | +This creates two active family providers competing for the same resources, |
| 30 | +causing errors like: |
| 31 | + |
| 32 | +```console |
| 33 | +cannot establish control of object: providerconfigusages.gcp.upbound.io is already controlled by ProviderRevision upbound-provider-family-gcp-f0aa3640a6a9 |
| 34 | +``` |
| 35 | + |
| 36 | +## Prerequisites |
| 37 | + |
| 38 | +Before changing providers, ensure: |
| 39 | + |
| 40 | +* Crossplane v2.0 or later |
| 41 | +* `kubectl` access to your cluster |
| 42 | +* Understanding of your current provider setup |
| 43 | +* Time for testing and validation |
| 44 | +* Backup of critical resources |
| 45 | + |
| 46 | +{{<hint "tip">}} |
| 47 | +Test this change in a staging environment first. The process is safe but |
| 48 | +requires careful verification at each step. |
| 49 | +{{</hint>}} |
| 50 | + |
| 51 | +## Why manual coordination is recommended |
| 52 | + |
| 53 | +Crossplane names package dependencies using OCI repository paths. It uses the |
| 54 | +pattern `<org>-<repo>`. When you change from `upbound/provider-gcp-compute` to |
| 55 | +`crossplane-contrib/provider-gcp-compute`, Crossplane sees these as completely |
| 56 | +different providers and creates both: |
| 57 | + |
| 58 | +* `upbound-provider-family-gcp` (old, still active) |
| 59 | +* `crossplane-contrib-provider-family-gcp` (new, requires ownership coordination) |
| 60 | + |
| 61 | +Both family providers manage the same CRDs and MRDs, requiring careful |
| 62 | +coordination of ownership transfer. |
| 63 | + |
| 64 | +Crossplane takes this conservative approach because determining package |
| 65 | +equivalence is complex. For example, an older Upbound provider version might |
| 66 | +differ significantly from a newer Crossplane Contrib version - with additional |
| 67 | +CRDs, different controller behavior, or updated APIs. Automatically replacing |
| 68 | +dependencies could break existing resources or introduce unexpected behavior. |
| 69 | + |
| 70 | +Manual coordination gives you explicit control to safely transition ownership |
| 71 | +from old to new providers with full visibility into each step. |
| 72 | + |
| 73 | +## Process overview |
| 74 | + |
| 75 | +The manual process follows this safe sequence: |
| 76 | + |
| 77 | +1. **Update provider package** - Change the provider's OCI reference |
| 78 | +2. **Identify conflicts** - Find which family provider is conflicted |
| 79 | +3. **Set manual activation** - Prevent the old family provider from staying active |
| 80 | +4. **Deactivate old revision** - Stop the old family provider from managing resources |
| 81 | +5. **Verify transition** - Ensure the new family provider manages all resources |
| 82 | +6. **Clean up** - Remove the old family provider |
| 83 | + |
| 84 | +This deliberate approach gives you full control over the timing and |
| 85 | +validation, ensures no resources are orphaned, and provides clear rollback |
| 86 | +points. |
| 87 | + |
| 88 | +## Step-by-step process |
| 89 | + |
| 90 | +This example changes from Upbound's GCP Compute provider to the Crossplane |
| 91 | +community version, which demonstrates the family provider dependency issue: |
| 92 | + |
| 93 | +* **From**: `xpkg.upbound.io/upbound/provider-gcp-compute:v1.14.1` |
| 94 | +* **To**: `xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute:v2.0.0` |
| 95 | + |
| 96 | +This change requires coordinating multiple package dependencies because each |
| 97 | +version depends on a different family provider. |
| 98 | + |
| 99 | +### Step 1: Inventory current providers |
| 100 | + |
| 101 | +Check your current provider setup: |
| 102 | + |
| 103 | +```shell |
| 104 | +kubectl get providers |
| 105 | +``` |
| 106 | + |
| 107 | +```console |
| 108 | +NAME INSTALLED HEALTHY PACKAGE AGE |
| 109 | +upbound-provider-family-gcp True True xpkg.upbound.io/upbound/provider-family-gcp:v1.14.1 30d |
| 110 | +provider-gcp-compute True True xpkg.upbound.io/upbound/provider-gcp-compute:v1.14.1 30d |
| 111 | +``` |
| 112 | + |
| 113 | +List managed resources to understand what the provider manages: |
| 114 | + |
| 115 | +```shell |
| 116 | +kubectl get managed |
| 117 | +``` |
| 118 | + |
| 119 | +```console |
| 120 | +NAME READY SYNCED EXTERNAL-NAME AGE |
| 121 | +address.compute.gcp.upbound.io/my-address True True my-address-abc123 5d |
| 122 | +``` |
| 123 | + |
| 124 | +### Step 2: Update the provider package |
| 125 | + |
| 126 | +Edit the existing provider to change its package reference: |
| 127 | + |
| 128 | +```shell |
| 129 | +kubectl patch provider provider-gcp-compute --type=merge \ |
| 130 | + -p='{"spec":{"package":"xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute:v2.0.0"}}' |
| 131 | +``` |
| 132 | + |
| 133 | +This creates a new family provider dependency. Check what providers exist: |
| 134 | + |
| 135 | +```shell |
| 136 | +kubectl get providers |
| 137 | +``` |
| 138 | + |
| 139 | +```console |
| 140 | +NAME INSTALLED HEALTHY PACKAGE AGE |
| 141 | +crossplane-contrib-provider-family-gcp True False xpkg.crossplane.io/crossplane-contrib/provider-family-gcp:v2.0.0 2m |
| 142 | +upbound-provider-family-gcp True True xpkg.upbound.io/upbound/provider-family-gcp:v1.14.1 30d |
| 143 | +provider-gcp-compute True True xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute:v2.0.0 2m |
| 144 | +``` |
| 145 | + |
| 146 | +Notice the new family provider is `HEALTHY=False` due to the ownership conflict. |
| 147 | + |
| 148 | +### Step 3: Set old family provider to manual activation |
| 149 | + |
| 150 | +Prevent the old family provider from automatically activating its revisions: |
| 151 | + |
| 152 | +```shell |
| 153 | +kubectl patch provider upbound-provider-family-gcp --type=merge \ |
| 154 | + -p='{"spec":{"revisionActivationPolicy":"Manual"}}' |
| 155 | +``` |
| 156 | + |
| 157 | +Verify the change: |
| 158 | + |
| 159 | +```shell |
| 160 | +kubectl get provider upbound-provider-family-gcp -o yaml | grep revisionActivationPolicy |
| 161 | +``` |
| 162 | + |
| 163 | +```console |
| 164 | + revisionActivationPolicy: Manual |
| 165 | +``` |
| 166 | + |
| 167 | +### Step 4: Deactivate old family provider revision |
| 168 | + |
| 169 | +Find the current revision of the old family provider: |
| 170 | + |
| 171 | +```shell |
| 172 | +kubectl get providerrevisions | grep upbound-provider-family-gcp |
| 173 | +``` |
| 174 | + |
| 175 | +```console |
| 176 | +NAME HEALTHY REVISION IMAGE STATE DEP-FOUND DEP-INSTALLED AGE |
| 177 | +upbound-provider-family-gcp-f0aa3640a6a9 True 1 xpkg.upbound.io/upbound/provider-family-gcp:v1.14.1 Active 0 0 30d |
| 178 | +``` |
| 179 | + |
| 180 | +Set the old family provider revision to inactive: |
| 181 | + |
| 182 | +```shell |
| 183 | +kubectl patch providerrevision upbound-provider-family-gcp-f0aa3640a6a9 --type=merge \ |
| 184 | + -p='{"spec":{"desiredState":"Inactive"}}' |
| 185 | +``` |
| 186 | + |
| 187 | +### Step 5: Verify the new family provider becomes healthy |
| 188 | + |
| 189 | +Check that the new family provider can now establish control: |
| 190 | + |
| 191 | +```shell |
| 192 | +kubectl get providers |
| 193 | +``` |
| 194 | + |
| 195 | +```console |
| 196 | +NAME INSTALLED HEALTHY PACKAGE AGE |
| 197 | +crossplane-contrib-provider-family-gcp True True xpkg.crossplane.io/crossplane-contrib/provider-family-gcp:v2.0.0 5m |
| 198 | +upbound-provider-family-gcp True True xpkg.upbound.io/upbound/provider-family-gcp:v1.14.1 30d |
| 199 | +provider-gcp-compute True True xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute:v2.0.0 5m |
| 200 | +``` |
| 201 | + |
| 202 | +Verify the old family provider revision is inactive: |
| 203 | + |
| 204 | +```shell |
| 205 | +kubectl get providerrevisions | grep upbound-provider-family-gcp |
| 206 | +``` |
| 207 | + |
| 208 | +```console |
| 209 | +NAME HEALTHY REVISION IMAGE STATE DEP-FOUND DEP-INSTALLED AGE |
| 210 | +upbound-provider-family-gcp-f0aa3640a6a9 True 1 xpkg.upbound.io/upbound/provider-family-gcp:v1.14.1 Inactive 0 0 30d |
| 211 | +``` |
| 212 | + |
| 213 | +Check that managed resources are still healthy: |
| 214 | + |
| 215 | +```shell |
| 216 | +kubectl get managed |
| 217 | +``` |
| 218 | + |
| 219 | +```console |
| 220 | +NAME READY SYNCED EXTERNAL-NAME AGE |
| 221 | +address.compute.gcp.upbound.io/my-address True True my-address-abc123 5d |
| 222 | +``` |
| 223 | + |
| 224 | +### Step 6: Delete the old family provider |
| 225 | + |
| 226 | +After verifying everything works correctly, remove the old family provider: |
| 227 | + |
| 228 | +```shell |
| 229 | +kubectl delete provider upbound-provider-family-gcp |
| 230 | +``` |
| 231 | + |
| 232 | +### Step 7: Final verification |
| 233 | + |
| 234 | +Confirm only the new providers remain: |
| 235 | + |
| 236 | +```shell |
| 237 | +kubectl get providers |
| 238 | +``` |
| 239 | + |
| 240 | +```console |
| 241 | +NAME INSTALLED HEALTHY PACKAGE AGE |
| 242 | +crossplane-contrib-provider-family-gcp True True xpkg.crossplane.io/crossplane-contrib/provider-family-gcp:v2.0.0 10m |
| 243 | +provider-gcp-compute True True xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute:v2.0.0 10m |
| 244 | +``` |
| 245 | + |
| 246 | +Verify managed resources are still healthy: |
| 247 | + |
| 248 | +```shell |
| 249 | +kubectl get managed |
| 250 | +``` |
| 251 | + |
| 252 | +```console |
| 253 | +NAME READY SYNCED EXTERNAL-NAME AGE |
| 254 | +address.compute.gcp.upbound.io/my-address True True my-address-abc123 5d |
| 255 | +``` |
| 256 | + |
| 257 | +## Other common scenarios |
| 258 | + |
| 259 | +### Providers without dependencies |
| 260 | + |
| 261 | +For providers that don't depend on other packages (like `provider-helm`, |
| 262 | +`provider-kubernetes`, or standalone providers), the change happens automatically: |
| 263 | + |
| 264 | +1. Update the provider's `spec.package` |
| 265 | +2. Crossplane creates a new revision with the new package |
| 266 | +3. The old revision automatically becomes inactive |
| 267 | +4. No conflicts occur because there are no dependencies |
| 268 | + |
| 269 | +Examples of providers that typically change automatically: |
| 270 | +* `provider-helm` |
| 271 | +* `provider-kubernetes` |
| 272 | +* `provider-sql` |
| 273 | +* Single-resource providers without family dependencies |
| 274 | + |
| 275 | +{{<hint "tip">}} |
| 276 | +You can check which providers have dependencies by inspecting the package lock: |
| 277 | + |
| 278 | +```shell |
| 279 | +kubectl get lock lock -o yaml |
| 280 | +``` |
| 281 | + |
| 282 | +Look for providers with non-empty `dependencies` arrays. For example: |
| 283 | +```yaml |
| 284 | +- name: provider-gcp-compute-a41e4ba551fc |
| 285 | + dependencies: |
| 286 | + - constraints: '>= 0.0.0' |
| 287 | + package: xpkg.crossplane.io/crossplane-contrib/provider-family-gcp |
| 288 | + type: Provider |
| 289 | +``` |
| 290 | +
|
| 291 | +Providers with empty `dependencies: []` change automatically. |
| 292 | +{{</hint>}} |
| 293 | + |
| 294 | +### Configuration package dependencies |
| 295 | + |
| 296 | +When changing providers that are dependencies of Configuration packages, the |
| 297 | +same conflicts can occur. The Configuration creates provider dependencies based |
| 298 | +on OCI references, so changing registries creates duplicate providers. |
| 299 | + |
| 300 | +To change providers in this scenario: |
| 301 | +1. Update the Configuration's package OCI reference |
| 302 | +2. Follow the same manual coordination steps for any conflicted providers |
| 303 | +3. Verify all providers the Configuration depends on are healthy |
| 304 | + |
| 305 | +### Rollback procedure |
| 306 | + |
| 307 | +If you need to rollback during the process: |
| 308 | + |
| 309 | +1. **Before deleting the old provider (step 6)**: Reactivate the old family |
| 310 | + provider revision: |
| 311 | + ```shell |
| 312 | + kubectl patch providerrevision upbound-provider-family-gcp-f0aa3640a6a9 --type=merge \ |
| 313 | + -p='{"spec":{"desiredState":"Active"}}' |
| 314 | + ``` |
| 315 | + |
| 316 | + Then deactivate the new family provider revision and delete the new provider. |
| 317 | + |
| 318 | +2. **After deleting the old provider**: You must recreate the old provider |
| 319 | + because Crossplane automatically deletes all revisions when you delete a |
| 320 | + provider. Create this manifest: |
| 321 | + |
| 322 | + ```yaml |
| 323 | + apiVersion: pkg.crossplane.io/v1 |
| 324 | + kind: Provider |
| 325 | + metadata: |
| 326 | + name: upbound-provider-family-gcp |
| 327 | + spec: |
| 328 | + package: xpkg.upbound.io/upbound/provider-family-gcp:v1.14.1 |
| 329 | + ``` |
| 330 | + |
| 331 | + Save as `rollback-provider.yaml` and apply: |
| 332 | + ```shell |
| 333 | + kubectl apply -f rollback-provider.yaml |
| 334 | + ``` |
| 335 | + |
| 336 | + Then follow the process in reverse to switch back. |
| 337 | + |
| 338 | +## Troubleshooting |
| 339 | + |
| 340 | +### New family provider stays unhealthy |
| 341 | + |
| 342 | +If the new family provider remains `HEALTHY=False` after deactivating the old one: |
| 343 | + |
| 344 | +1. Check the provider revision status: |
| 345 | + ```shell |
| 346 | + kubectl get providerrevisions | grep crossplane-contrib-provider-family |
| 347 | + ``` |
| 348 | + |
| 349 | +2. Look for ownership conflict errors in the provider logs: |
| 350 | + ```shell |
| 351 | + kubectl logs -n crossplane-system -l pkg.crossplane.io/provider=crossplane-contrib-provider-family-gcp |
| 352 | + ``` |
| 353 | + |
| 354 | +3. Verify the old revision is truly inactive: |
| 355 | + ```shell |
| 356 | + kubectl describe providerrevision upbound-provider-family-gcp-f0aa3640a6a9 |
| 357 | + ``` |
| 358 | + |
| 359 | +### CRD ownership conflicts persist |
| 360 | + |
| 361 | +If you see persistent ownership conflicts: |
| 362 | + |
| 363 | +```console |
| 364 | +cannot establish control of object: providerconfigusages.gcp.upbound.io is already controlled by ProviderRevision upbound-provider-family-gcp-f0aa3640a6a9 |
| 365 | +``` |
| 366 | + |
| 367 | +This usually means the old revision is still active. Double-check: |
| 368 | + |
| 369 | +1. The old provider has `revisionActivationPolicy: Manual` |
| 370 | +2. The old revision has `desiredState: Inactive` |
| 371 | +3. Wait a few minutes for the change to propagate |
| 372 | + |
| 373 | +### Provider won't deactivate |
| 374 | + |
| 375 | +If the old provider revision won't become inactive: |
| 376 | + |
| 377 | +1. Check for active managed resources preventing deactivation |
| 378 | +2. Verify the patch command succeeded |
| 379 | +3. Check provider logs for errors: |
| 380 | + ```shell |
| 381 | + kubectl logs -n crossplane-system -l pkg.crossplane.io/provider=upbound-provider-family-gcp |
| 382 | + ``` |
| 383 | + |
| 384 | +## Next steps |
| 385 | + |
| 386 | +After successfully changing providers: |
| 387 | + |
| 388 | +* Update any documentation referencing the old provider |
| 389 | +* Consider changing to v2 namespaced resources if using Crossplane v2 |
| 390 | +* Review other providers for potential registry changes |
| 391 | +* Share your experience with the Crossplane community |
| 392 | + |
| 393 | +For more information: |
| 394 | +* [Provider documentation]({{<ref "../packages/providers">}}) |
| 395 | +* [Troubleshooting guide]({{<ref "troubleshoot-crossplane">}}) |
| 396 | +* [Crossplane community](https://crossplane.io/community/) |
0 commit comments