The CockroachDB operator is in .
Compatibility
Before starting migration, verify your cluster configuration is supported by the migration controller:Before You Begin
Verify the following before starting migration:- CockroachDB cluster is managed by the Public Operator (v1alpha1 CrdbCluster).
- All StatefulSet pods are Running and Ready with no pending rolling updates or scale operations.
kubectlandhelmare installed and configured with access to the target cluster.- For multi-region clusters: cloud region and provider labels are applied to K8s nodes.
- You have the
regionCodeandcloudProvidervalues for your cluster. - You have reviewed the Compatibility table and confirmed your configuration is supported, or otherwise are prepared to manually recreate unsupported feature configurations.
- The public operator is accessible and running (required for rollback capability).
- If you plan to create new v1beta1 clusters while the public operator is running: Patch the public operator’s webhooks to use
matchPolicy: Exact. - If using custom
NodeTLSSecret/ClientTLSSecret: Your certificates include join service DNS SANs ({cluster-name}-join,{cluster-name}-join.{namespace},{cluster-name}-join.{namespace}.svc.cluster.local). The migration controller cannot regenerate certificates when custom secrets are provided (the CA private key is not available).
Migration controller overview
The following sections describe how the automated migration controller handles a migration from the Public operator to the CockroachDB operator:What the migration controller does automatically
- Detects cert-manager, self-signer, or custom TLS secrets. Self-signer and cert-manager certs are regenerated with join service DNS SANs automatically. When custom
NodeTLSSecret/ClientTLSSecretare set, skips cert regeneration and mounts the user’s secrets directly. - Creates RBAC resources with namespace-qualified names for cluster-scoped resources.
- Migrates ConfigMap key format (
logging.yamltologs.yaml). - Converts v1alpha1 CrdbCluster spec to v1beta1 via conversion webhook.
- Deletes old PDB and creates a new one during finalization (no protection gap because the new PDB is created immediately after old PDB deletion).
- Updates service selectors and restores them on rollback.
- Migrates nodes one at a time, verifying cluster health between each node.
- Preserves Ingress configuration from v1alpha1 CR as annotation on v1beta1 CrdbCluster.
- Removes
crdb.io/skip-reconcilelabel as the last step of rollback so the public operator resumes control cleanly.
Controlling migration (Stop / Resume / Rollback)
The following section describe how to safely manage an in-progress migration.Stop (Pause)
Pauses migration at the current phase. No resources are deleted. CrdbNodes already created remain running and serving traffic.Resume
There is no separate “resume” label value. Usestart again to resume from the paused phase. The controller detects the PhaseStopped state internally and resumes at the correct phase based on how many nodes have already been migrated.
Stop during rollback
If rollback is in progress and you apply the stop label, the controller pauses the rollback. The status message indicates that migration was stopped while inRollbackInProgress.
To resume the rollback:
start resumes forward migration, while rollback resumes rollback.
Gap detection on stop
If stop is requested between scaling down the StatefulSet and creating the replacement CrdbNode, the controller detects the gap and scales the StatefulSet back up before enteringPhaseStopped. This keeps every ordinal represented by either a StatefulSet pod or a CrdbNode pod while migration is paused.
Rollback
Rollback is safe at any phase before Complete. Removing the label triggers automatic rollback. The controller automatically:- Deletes all CrdbNodes and waits for their pods to terminate.
- Restores StatefulSet to original replica count.
- Removes migration labels (
crdb.cockroachlabs.com/cluster,svc) from pods. - Deletes CA ConfigMap (
{name}-ca-crt) and migration-created cert secrets ({name}-node-secret,{name}-client-secret). - Reverses ConfigMap key migration (
logs.yamlback tologging.yaml). - Deletes all PDB variants (
{name},{name}-budget,{name}-pdb). - Restores original service selectors (
app.kubernetes.io/component,app.kubernetes.io/instance). - Deletes namespace-qualified ClusterRole and ClusterRoleBinding (
{namespace}-{name}). - Sets CrdbCluster
Mode=Disabled. - Removes
crdb.io/skip-reconcilelabel last so the public operator resumes control.
For operator migrations, the public operator must still be running (or at least its CRDs and webhook must be available) for rollback to fully succeed. The controller removes
skip-reconcile as the last rollback step, allowing the public operator to resume reconciliation. If the public operator has been completely uninstalled (including CRDs), the StatefulSet is restored but nothing will reconcile it. You would need to reinstall the public operator or manage the cluster manually.Rollback validation
After rollback, the controller enters a validation phase (PhaseRollbackComplete) and verifies the following:
- All CrdbNodes are deleted.
- StatefulSet is restored to original replica count.
- All pods are ready.
- Headless service has no v1beta1 ownerReferences.
skip-reconcile label and clears migration status after all checks are confirmed.
Rollback safety by phase
Label values reference
Rollback after complete
OncePhase=Complete, automated rollback is not possible. The StatefulSet has been deleted.
Manual recovery steps:
- Delete all CrdbNodes
- Manually recreate the StatefulSet with original spec
- Scale up and verify cluster health
- Remove the migration label
Certificate Detection
The controller automatically detects your certificate method. No manual configuration is needed.- cert-manager: If cert-manager Certificate CRs exist for the cluster (
{name}-node), the controller updates the Certificate CR with join service DNS SANs and preserves the issuer references. cert-manager then regenerates the secrets automatically. CrdbNode pods mount from the cert-manager-managed secret (the name fromspec.secretNamein the Certificate CR), not{name}-node-secret. This keeps cert-manager’s automatic rotation working after migration. - Self-signer (operator built-in): The controller loads the existing CA from cluster secrets, regenerates node and client certificates with join service DNS SANs, and writes them to the destination secrets (
{name}-node-secret,{name}-client-secret). CrdbNode pods mount from{name}-node-secret. The regenerated certificates have a 1-year TTL and are stored asExternalCertificatesin the v1beta1 spec. The operator does not auto-rotateExternalCertificates, so after migration you should switch tocockroachdb.tls.selfSigner.enabled: truevia Helm adoption to enable automatic rotation. If you delay this step, the certs will expire silently after one year. - External certs: If neither cert-manager CRs nor self-signer secrets are found, the controller preserves existing secret references as ExternalCertificates in the v1beta1 spec.
- Custom secret names: If the v1alpha1 spec has
NodeTLSSecretorClientTLSSecretset, the controller skips cert regeneration entirely because the CA private key is not available. CrdbNode pods mount the user’s existing secrets directly. The user must update their certificates to include join service DNS SANs before starting the migration (see prerequisites). - Insecure clusters: Detected from the
--insecurestart flag. The entire cert migration phase is skipped. AnInsecureClusterMigrationwarning event is emitted.
Regardless of the original cert type, after migration all certificate secret names are stored as
ExternalCertificates on the CrdbNode spec. This is the internal representation used by the operator to mount the correct secrets into pods.Co-operating public and CockroachDB operators
The CockroachDB operator and the public operator can run side by side during migration. Installing the CockroachDB operator withmigration.enabled=true replaces the CRD with a dual-version CRD (v1alpha1 + v1beta1) and registers a conversion webhook. Existing clusters continue to work normally.
Supported scenarios
Unsupported scenarios
How webhook isolation works
Both operators’ webhooks must usematchPolicy: Exact to prevent cross-version interception. The CockroachDB operator’s webhooks ship with this setting. The public operator’s webhooks use the Kubernetes default (Equivalent), which causes them to intercept v1beta1 requests after Kubernetes converts them to v1alpha1. To create v1beta1 clusters while the public operator is present, update the public operator’s webhooks to use matchPolicy: Exact.
Option 1: Edit the public operator manifest before installing. Download the manifest, add matchPolicy: Exact to both webhook entries, then apply:
matchPolicy: Exact, a v1alpha1 request triggers only the public operator’s webhooks, and a v1beta1 request triggers only the CockroachDB operator’s webhooks.
This patching is only needed if you plan to create new v1beta1 clusters while the public operator is still running. Migration of existing v1alpha1 clusters does not require patching because the migration controller works with the v1alpha1 API directly.
How conversion works
v1alpha1 clusters withoutskip-reconcile are converted to v1beta1 with Mode=Disabled for storage. The CockroachDB operator ignores clusters in this mode.
v1beta1 cluster protection: The CockroachDB operator’s mutating webhook injects crdb.io/skip-reconcile=true on every v1beta1 CrdbCluster. This label is stored on the object and carried through to the v1alpha1 view via ObjectMeta, so the public operator sees it and skips reconciliation.
In summary, you can:
- Keep existing v1alpha1 clusters running with the public operator
- Create new v1alpha1 clusters while the CockroachDB Operator is installed
- Create new v1beta1 clusters while the public operator is still running
- Migrate clusters one by one at your own pace
Multi-cluster migration strategy
When you have multiple clusters across different namespaces, you can migrate them one at a time while the public operator continues managing the remaining v1alpha1 clusters.Deployment pattern
Deploy one namespace-scoped CockroachDB Operator per namespace usingwatchNamespaces. This provides clean isolation where each operator manages only the clusters in its namespace. A single operator watching multiple namespaces can also work, but has less isolation.
The migration flag rule
At least one CockroachDB operator must havemigration.enabled=true as long as any v1alpha1 cluster exists anywhere in the Kubernetes cluster. The CRD conversion webhook is a cluster-wide resource. The public operator reads and writes v1alpha1 CrdbClusters, and since the storage version is v1beta1, every v1alpha1 interaction goes through the webhook. Only operators started with migration.enabled=true register the /convert endpoint.
It does not matter which operator has the flag. The conversion endpoint is stateless and handles requests for any namespace. But at least one must be running and reachable.
Operators that only manage fresh v1beta1 clusters do not need the migration flag. When an operator starts without migration enabled, it checks the CRD’s storedVersions field. If v1alpha1 is present and an existing conversion webhook is already configured (by another operator), it preserves the webhook and starts normally.
Creating new v1beta1 clusters during migration
You can create new v1beta1 clusters at any point during migration. Install a namespace-scoped CockroachDB operator in a separate namespace and create v1beta1 CrdbCluster resources directly. The mutating webhook automatically injectscrdb.io/skip-reconcile=true so the public operator ignores these clusters.
The new operator does not need migration.enabled=true as long as another operator already has it enabled.
Migrated clusters and the public operator
After a cluster is migrated, the public operator can remain running while it manages other v1alpha1 clusters. Migrated clusters can be updated by the CockroachDB Operator or CockroachDB Helm chart independently of the public operator. Keepcrdb.io/skip-reconcile=true on migrated clusters while the public operator is still running. Removing it allows the public operator to reconcile the migrated cluster and can recreate StatefulSet resources that conflict with CrdbNodes.
Gradual migration across namespaces
Phase 1 - Migrate the first namespace:- Install a CockroachDB Operator in ns-1 with
migration.enabled=true,appLabel=cockroachdb-operator, andwatchNamespaces=ns-1. - Apply
skip-reconcileand cloud annotations on the cluster in ns-1. - Label the cluster with
crdb.io/migrate=start. - Monitor migration, delete StatefulSet when in Finalization.
- The cluster in ns-2 continues running under the public operator, unaffected.
- Install a CockroachDB Operator in ns-3 with
migration.enabled=false,appLabel=cockroachdb-operator, andwatchNamespaces=ns-3. This works because the ns-1 operator already has the conversion webhook configured. - Create v1beta1 clusters directly using the CockroachDB Helm chart.
- Either expand ns-1’s
watchNamespacesto include ns-2, or install a new CockroachDB operator in ns-2 withmigration.enabled=true,appLabel=cockroachdb-operator. - Apply
skip-reconcileand cloud annotations on the cluster in ns-2. - Migrate the cluster.
- Remove the public operator (no v1alpha1 clusters remain).
- Patch
storedVersionsto remove v1alpha1 (see Step 13). - The migration flag can optionally be removed (see Step 14).
What happens if things go wrong
Step 1: Export environment variables
Export the following environment variables based on your existing deployment:Step 2: Apply cloud region and provider labels (multi-region only)
CockroachDB uses K8s node labels for locality-based pod placement. These labels must exist before the operator starts scheduling pods.Step 3: Pause the Public Operator
The public operator must stop reconciling the cluster before installing the CockroachDB Operator. Without this, both controllers will fight over RBAC, PDB, and service selectors.skip-reconcile label is not applied, migration will fail with: missing required label: crdb.io/skip-reconcile=true
The
crdb.io/skip-reconcile=true label must remain on the v1alpha1 CrdbCluster for as long as the public operator is running. The public operator reconciles any CrdbCluster without this label and will recreate the StatefulSet and associated resources if it regains control. Do not remove this label until after the public operator has been fully uninstalled. Removing it while the public operator is still running will cause it to recreate the StatefulSet, potentially conflicting with the migrated CrdbNodes.Step 4: Annotate CrdbCluster with Region and Cloud Provider
Annotate the CR with region and cloud provider so they are preserved during the v1alpha1 to v1beta1 conversion:regionsannotation (for multi-region).regionCodeandcloudProviderannotations.- Operator environment configuration.
- Default
us-east1. For single-region clusters, the default may be acceptable.
Step 5: Install CockroachDB Operator with Migration Enabled
Install the operator with migration enabled. The migration controller only acts on resources that have thecrdb.io/migrate label, and the cluster controller skips clusters with Mode=Disabled (which the conversion webhook sets for all v1alpha1 clusters). The CockroachDB operator will not interfere with clusters that have not been explicitly marked for migration.
The CockroachDB operator and the public operator can run side-by-side during migration. See co-operating public and CockroachDB operators for details.
watchNamespaces is optional. This setting restricts the CockroachDB operator to a subset of namespaces, which can be useful for reducing blast radius in large environments.
migration.enabled=true on the operator chart enables the migration controller and registers the conversion webhook (translates between v1alpha1 and v1beta1).
Verify the operator is running and the conversion webhook is active:
appLabel=cockroachdb-operator so the CockroachDB operator’s Deployment selector and Service selector do not collide with the public operator’s app=cockroach-operator labels when both operators run in the same namespace. The operator chart default remains appLabel=cockroach-operator for normal upgrades and preview users to avoid changing the existing immutable Deployment selector. Use the distinct appLabel only for new migration/coexistence installs.
When migrating clusters across multiple namespaces, migrate one namespace at a time. Update watchNamespaces (or use a comma-separated list) to include additional namespaces only after the previous migration is complete.
Step 6: Start Migration
Initiate the migration by labeling the v1alpha1 CrdbCluster.Step 7: Monitor Migration
The following sections describe how to monitor the ongoing migration.Phase-Specific Checks
The following table describes the high-level events to monitor for progress during each migration phase:DB Console
The DB Console is accessible via the public service throughout migration.- Node List: Watch for nodes joining and leaving as migration progresses. Total node count stays constant (new CrdbNode created before old STS pod is removed).
- Replication Status: Under-replicated and unavailable ranges should stay at zero. The migration controller waits for under-replicated ranges to clear before proceeding to the next node.
- Ranges Dashboard: Under-replicated ranges counter should not increase during migration.
Prometheus Metrics
CockroachDB health checks
The controller performs these checks automatically between each node migration, but you can verify manually:Check migration phase
The migration status is recorded on the v1beta1 CrdbCluster (created via conversion webhook).Monitor Kubernetes events
Watch CrdbNode creation during the PodMigration phase
Troubleshooting pauses during PodMigration
During PodMigration, if a newly created CrdbNode does not pass health checks within 10 minutes, the controller automatically pauses migration by setting the phase toPhaseStopped. Health checks run every 10 seconds and verify:
- CrdbNode has
PodReady=Truecondition - Pod is in
Runningphase withReady=Truecondition - SQL health check passes (zero under-replicated ranges and correct live node count)
- Pod is registered in the headless service endpoints
kubectl label sts $CRDBCLUSTER crdb.io/migrate=start --overwrite.
PDB Behavior During Migration
- Init through PodMigration: The original public operator PDB remains active. Pod disruption protection is maintained throughout.
- Finalization: The controller deletes the old PDB (
{name}or{name}-budget) and immediately creates the new PDB ({name}-pdb). There is no gap in protection. - Rollback: All PDB variants are deleted (
{name},{name}-budget,{name}-pdb). The original PDB is recreated by the public operator onceskip-reconcileis removed.
Step 8: Delete StatefulSet
After the finalization phase is complete, the controller stops processing and waits for the user to manually delete the StatefulSet. The StatefulSet is intentionally left intact. Once deleted, the controller setsspec.mode=MutableOnly and records Phase=Complete.
replicas=0 by the time Finalization runs (scaled down one by one during PodMigration). Deleting the StatefulSet object does not evict any running pods.
Step 9: Verify cluster health post-migration
Run the followingkubectl commands to validate that the new cluster is online and healthy:
Verify preserved configurations
Verify v1alpha1 → v1beta1 field conversion
Key fields converted during migration:Step 10: Configure LocalityMappings
The migration controller preserves the--locality flag tier keys (e.g. region, zone) as localityLabels on the CrdbNodeSpec. localityLabels is deprecated in favor of localityMappings, which maps K8s node labels to CockroachDB locality tiers. The default mapping covers standard K8s topology labels (topology.kubernetes.io/region → region, topology.kubernetes.io/zone → zone).
If your cluster uses custom K8s node labels for locality, update localityMappings to match. Each entry maps a K8s node label key to a CockroachDB locality tier name.
topology.kubernetes.io/* labels, the kubebuilder defaults are correct and no action is needed.
Step 11: Cleanup Public Operator Resources
After verifying the migrated cluster is healthy, clean up old public operator resources.Migration-created RBAC (stale)
Public operator RBAC
Public operator deployment
Only do this after all clusters managed by the public operator have been migrated.Do not delete
crdbclusters.crdb.cockroachlabs.com, crdbnodes.crdb.cockroachlabs.com, or crdbtenants.crdb.cockroachlabs.com. Those CRDs are shared by the migrated CockroachDB Operator resources. A later step removes v1alpha1 from storedVersions after every v1alpha1 cluster has been migrated.Public operator webhook configurations
Public operator ServiceAccount and RBAC in its namespace
Step 12: Adopt into CockroachDB Helm Chart (Optional)
Before adopting, verify the operator has fully reconciled the migrated cluster. Do not proceed untilgeneration and observedGeneration match and all pods are running.
helm upgrade to manage the migrated CrdbCluster going forward, you need to annotate existing resources for Helm ownership and provide a values.yaml that matches the migrated spec.
Prepare values.yaml
Inspect the migrated CrdbCluster and map its spec to Helm values.values.yaml file automatically with a migration helper, and/or build the file manually by mapping existing values.
Option A: Generate values.yaml automatically
Build and run the migration helper binary in the root of the cockroachdb/helm-charts repository:cockroachdb.crdbCluster.rbac.serviceAccount.name, keep that value as-is. This field preserves the service account used by the migrated cluster.
Option B: Build values.yaml manually
Key values to set:
The v1alpha1 CrdbCluster fields (cache, max-sql-memory, additionalArgs) were converted to
spec.template.spec.startFlags.upsert during migration. Map these to the appropriate Helm values or pass them via cockroachdb.crdbCluster.startFlags.
Field Mapping Reference
Annotate resources for Helm ownership
service/${CRDBCLUSTER}). The headless service is operator-managed and not templated by the CockroachDB Helm chart.
Do not annotate the migration-created ClusterRole/ClusterRoleBinding. The CockroachDB Helm chart creates its own cluster-scoped RBAC with different names ({fullname}-{namespace}-node-reader). Delete the stale migration-created role and binding after Helm adoption:
Transfer field ownership to Helm
The public operator and migration controller write some fields on the Role and public Service using thecockroach-operator field manager. Helm uses the Helm field manager during server-side apply. Transfer ownership of those existing fields before Helm adoption to avoid conflict errors.
This is metadata-only. This script does not delete or recreate resources and does not affect running pods.
Run Helm install
There is no existing Helm release for the migrated cluster, so use--install to create one.
helm upgrade with an updated timestamp:
Update Certificate Mode After Adoption
After migration, all certificate references are stored asexternalCertificates on the CrdbCluster spec, regardless of the original cert type. The export-values tool outputs these as cockroachdb.tls.externalCertificates. After Helm adoption, update your values.yaml to use the cert mode that matches your intended ongoing management:
- Self-signer: Switch to
cockroachdb.tls.selfSigner.enabled: trueand remove theexternalCertificatesblock. The operator’s self-signer will manage cert rotation going forward. The migration-created{name}-node-secretand{name}-client-secretsecrets become stale once the self-signer creates its own. Delete them after verifying the new certs are working. - cert-manager: Switch to
cockroachdb.tls.certManager.enabled: truewith the appropriate issuer reference. The migration preserved the Certificate CR and itsspec.secretName, so cert-manager continues to manage rotation. Remove theexternalCertificatesblock from values. - User-provided / External: Keep
cockroachdb.tls.externalCertificatesas exported. You are responsible for cert rotation.
helm upgrade again and verify pods are healthy. Clean up any stale secrets that are no longer referenced:
Step 13: Patch storedVersions
After all v1alpha1 clusters across the entire Kubernetes cluster have been migrated and the public operator has been removed, patch the CRD’sstoredVersions to remove v1alpha1.
Do not do this until every v1alpha1 cluster has completed migration and the public operator is stopped.
Step 14: Disable Migration Mode (Optional)
AfterstoredVersions is patched, disabling migration mode is optional. When the operator restarts without the flag, it sees that storedVersions no longer contains v1alpha1 and sets v1alpha1 served=false on the CRD. The conversion webhook is removed.
If you leave migration.enabled=true after patching storedVersions, the operator continues to register the conversion webhook and migration controller, but they have no effect.
- v1alpha1 is no longer served by the API server.
- The conversion webhook is removed from the CRD.
- All existing v1beta1 clusters continue working normally.
Do not disable migration mode while the public operator is still running or before
storedVersions is patched. Disabling it removes the conversion webhook, which causes the API server to drop v1beta1-only fields (certificates, regions, podTemplate) from the stored CrdbCluster spec during v1alpha1 round-trips.Removing the CockroachDB Operator
If you uninstall the CockroachDB operator without completing steps 13-14 first, the CRD still has the conversion webhook pointing at a dead endpoint. Any v1alpha1 API calls (includingkubectl get crdbclusters if the API server chooses v1alpha1 as the storage version) will fail with webhook connection errors. To recover:
- Patch
storedVersionsto remove v1alpha1 (Step 13). - Remove the conversion webhook from the CRD manually:
- Optionally remove v1alpha1 from the CRD’s
spec.versionsif no v1alpha1 clusters remain.
Conversion annotations
The conversion webhook writes annotations on v1alpha1 objects to preserve v1beta1 state across round-trips.ConvertFrom always refreshes the hub spec annotation from the current v1beta1 spec, so the annotation is always up to date when ConvertTo reads it. This ensures v1beta1-only fields like ServiceAccountName and StartFlags survive any v1alpha1 write-back. The migration controller strips these annotations on Phase=Complete as cleanup, but they are harmless and will be re-created if a v1alpha1 read occurs while the conversion webhook is still active. Disabling migration mode prevents any further round-trips.
Troubleshooting
Follow these troubleshooting steps if there are issues with the migration:Migration fails with “missing required label: crdb.io/skip-reconcile=true”
Theskip-reconcile label was not applied before starting migration. Apply it and retry:
Migration stuck at PodMigration phase
If a node fails health checks for more than 10 minutes, migration auto-pauses toPhaseStopped.
CrdbCluster not found
For operator migrations, the v1beta1 CrdbCluster is created via the conversion webhook. The conversion webhook is only registered when the operator is started with--enable-migration (or migration.enabled=true in Helm). If the v1beta1 CrdbCluster is missing, ensure:
- The CockroachDB operator was installed with
migration.enabled=true. - The webhook service is running and reachable.
- The v1alpha1 CrdbCluster has not been deleted.
Under-replicated Ranges
The controller retries health checks every 10 seconds. If under-replicated ranges persist for more than 10 minutes, migration auto-pauses.RBAC conflicts between public and CockroachDB operator
If both operators are fighting over RBAC, check the following:- Verify
skip-reconcileis set on the v1alpha1 CrdbCluster. - Verify the CockroachDB Operator uses
watchNamespacesto limit its scope. - Check that ClusterRole names do not collide (CockroachDB Operator uses
{namespace}-{name}).
ConfigMap key format
The public operator useslogging.yaml as the key in log-config ConfigMaps. The CockroachDB operator uses logs.yaml. The migration controller renames this key automatically. On rollback, the key is renamed back. Verify:
Operator Fails with “storedVersions: must appear in spec.versions”
You may see an error like:spec.versions, but status.storedVersions still lists it. Kubernetes requires every stored version to remain in spec.versions. A common cause is removing migration.enabled=true before patching storedVersions in Step 13.
Fix it by either re-enabling migration temporarily or patching storedVersions if all clusters are already migrated:
Verifying v1alpha1 Storage State
Runningkubectl get crdbclusters.v1alpha1.crdb.cockroachlabs.com does not prove that objects are still stored as v1alpha1. The conversion webhook can convert v1beta1 objects back to v1alpha1 on read.
The reliable indicator is the CRD’s status.storedVersions field, but this is a high-water mark. Kubernetes adds versions when objects have been stored in that version, but does not remove them automatically. A version listed in storedVersions means objects were stored in that version at some point, not necessarily that they still are.
Before patching storedVersions:
- Ensure the CockroachDB Operator has reconciled every CrdbCluster at least once.
- Verify no public operator remains running.
- Patch
storedVersionsas described in Step 13.

