Migrate your Mission Control installation from Replicated to ICR

Replicated is no longer supported as an installation method for Mission Control. If you have an existing Replicated installation, you must migrate it to IBM Container Registry (ICR). You can do this by switching the image pull source from Replicated to ICR without reinstalling Mission Control.

Restarting cass-operator causes it to reconcile all managed database clusters and restart the database pods to pull new images from cp.icr.io. Database availability during this restart depends on your replication factor:

  • Clusters with a replication factor of 3 or more can tolerate the rolling pod restarts without data becoming unavailable.

  • Clusters with a lower replication factor will experience downtime.

Additionally, Mission Control control plane pods restart in a rolling fashion during the Helm upgrade and are briefly unavailable regardless of replication factor.

DataStax recommends that you schedule a maintenance window before you proceed.

Migrate a Helm-based Replicated installation

Use this option if you installed Mission Control directly with helm install from the Replicated proxy registry without the KOTS admin console. Otherwise, see KOTS-based installation.

Set environment variables

  1. Make sure you have the following:

    • The Helm release name used during the original Replicated installation.

    • The namespace where Mission Control is installed.

    • All namespaces that host database clusters managed by this Mission Control instance.

    • An IBM entitlement key from the IBM Container Library. This is required to pull the following images from cp.icr.io: cql-router, cqlsh (cqlsh-pod), hcd, and dse (dse-mgmtapi). Public Mission Control images (mission-control, mission-control-ui, mission-control-dex, k8ssandra-client) are served from the non-entitled icr.io registry, and they do not require the entitlement key.

    • The Mission Control version currently installed. You must migrate to the same version.

    • The original values.yaml files used for the original Helm install.

    • The pull secret name used during the original Replicated installation, typically ${RELEASE_NAME}-registry. For example, if your release name is mission-control, use mission-control-registry.

  2. Set the following environment variables in your terminal using the information you collected in the previous step:

    export RELEASE_NAME=RELEASE_NAME
    export MC_NAMESPACE=NAMESPACE
    export CLUSTER_NAMESPACES="NAMESPACE1 NAMESPACE2 NAMESPACE3"
    export IBM_ENTITLEMENT_KEY=ENTITLEMENT_KEY
    export TARGET_VERSION=VERSION
    export ORIGINAL_VALUES_FILE=VALUES_FILE
    export PULL_SECRET_NAME=PULL_SECRET

Upgrade the pull secret

Update the registry pull secret in the Mission Control namespace only. The Mission Control operator automatically replicates it to all cluster namespaces.

Replicated creates the pull secret during installation using the naming convention RELEASE_NAME-registry. For a release named mission-control, the secret is mission-control-registry. This existing secret is updated in place. It is already referenced in helm-overrides.yaml under global.imageConfig.defaults.pullSecrets.

kubectl create secret docker-registry ${RELEASE_NAME}-registry \
  --docker-server=cp.icr.io \
  --docker-username=cp \
  --docker-password=${IBM_ENTITLEMENT_KEY} \
  --namespace=${MC_NAMESPACE} \
  --dry-run=client -o yaml | kubectl apply -f -

The --dry-run=client -o yaml | kubectl apply pattern generates the secret manifest locally and pipes it to kubectl apply, performing a create-or-update. It is idempotent and safe to re-run against the existing Replicated-created secret.

Run helm upgrade with ICR overrides

Run helm upgrade with your original values files and helm-overrides.yaml. The overrides file is applied last so its values take precedence, redirecting all image references from the Replicated proxy to icr.io and cp.icr.io.

The version must match the currently installed release. Set TARGET_VERSION in your environment variables to the exact version that was installed from Replicated.

Don’t use this migration process as an upgrade shortcut. If you want to upgrade the version, you must do so after migrating your installation.

  1. Create an ICR overrides file named overrides.yaml with the following content, and replacing PULL_SECRET_NAME with your pull secret name:

    # Disable replicated
    replicated:
      enabled: false
    disablePullSecretsGeneration: true
    
    # MC operator
    image:
      registry: icr.io
      repository: datastax-mission-control/mission-control
    
    # MC UI
    ui:
      image:
        registry: icr.io
        repository: datastax-mission-control/mission-control-ui
    
    # CRD patcher
    client:
      image:
        registry: icr.io
        repository: datastax-mission-control/k8ssandra-client
    
    global:
      # Image pull secret for entitled images
      imageConfig:
        defaults:
          pullSecrets:
            - **PULL_SECRET_NAME**   # <RELEASE_NAME>-registry
        images:
          k8ssandra-client:
            registry: icr.io
            repository: datastax-mission-control
            name: k8ssandra-client
          cql-router:                    # entitled — requires cp.icr.io pull secret
            registry: cp.icr.io
            repository: cp/ibm-ds-mission-control
          cqlsh:                         # entitled — requires cp.icr.io pull secret
            registry: cp.icr.io
            repository: cp/ibm-ds-mission-control
        types:
          hcd:                           # entitled — requires cp.icr.io pull secret
            registry: cp.icr.io
            repository: cp/ibm-ds-mission-control
            name: hcd
          dse:                           # entitled — requires cp.icr.io pull secret
            registry: cp.icr.io
            repository: cp/ibm-ds-mission-control
            name: dse-mgmtapi
    
    # MC Dex
    dex:
      image:
        repository: icr.io/datastax-mission-control/mission-control-dex
  2. Run the upgrade.

    If you used more than one -f flag during the original installation, supply them all in the same order, then append -f helm-overrides.yaml as the final entry. Files are read in order and later files take precedence.

    helm upgrade ${RELEASE_NAME} oci://icr.io/mission-control-helm/mission-control \
      --version ${TARGET_VERSION} \
      -n ${MC_NAMESPACE} \
      -f ${ORIGINAL_VALUES_FILE} \
      -f helm-overrides.yaml \
      --server-side true
  3. Monitor the rollout until all Mission Control pods are Running with images pulled from icr.io or cp.icr.io:

    1. Monitor the deployment rollout:

      kubectl rollout status deployment -n ${MC_NAMESPACE} --timeout=10m
    2. Confirm image sources:

      kubectl get pods -n ${MC_NAMESPACE} \
        -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{range .spec.containers[*]}{.image}{"\n"}{end}{end}'

      All images should reference icr.io/datastax-mission-control/… or cp.icr.io/cp/ibm-ds-mission-control/…. If any pod is in ImagePullBackOff, verify that the pull secret contains a valid cp.icr.io entry.

Restart cass-operator

Restarting cass-operator causes it to reconcile all CassandraDatacenter resources. Each database pod restarts to pull the new image from cp.icr.io. Multi-node clusters undergo a rolling restart. Single-node clusters briefly experience a full outage.

After the Helm upgrade, the CassandraDatacenter resources carry updated image configuration pointing to cp.icr.io. Restarting cass-operator causes it to pick up the new configuration and reconcile the database StatefulSets.

  1. Identify the cass-operator deployment:

    kubectl get deployments -n ${MC_NAMESPACE} | grep cass-operator
  2. Restart cass-operator:

    kubectl rollout restart deployment/cass-operator -n ${MC_NAMESPACE}
  3. Wait for the operator to be ready:

    kubectl rollout status deployment/cass-operator -n ${MC_NAMESPACE} --timeout=3m
  4. Watch database pod restarts, repeating for each namespace that contains database pods:

    kubectl get pods -n CLUSTER_NAMESPACE -w

    Replace CLUSTER_NAMESPACE with each cluster namespace.

  5. Confirm image sources, repeating for each cluster namespace:

    kubectl get pods -n CLUSTER_NAMESPACE \
      -o jsonpath='{range .items[]}{.metadata.name}{"\t"}{range .spec.containers[]}{.image}{"\n"}{end}{end}'

    All HCD and DSE containers should reference cp.icr.io/cp/ibm-ds-mission-control/hcd:… or cp.icr.io/cp/ibm-ds-mission-control/dse-mgmtapi:…​.

  6. Confirm the CassandraDatacenter resources report a healthy status (READY = true, PROGRESS = false)

    kubectl get cassandradatacenter -A

KOTS-based installation

Use this option if you installed Mission Control with the KOTS admin console using kubectl kots install or through the Replicated vendor portal. Otherwise, see Migrate a Helm-based Replicated installation.

When Mission Control is installed through KOTS, the admin console owns the Helm release. It renders all repl{{ }} template expressions from the admin-console configuration screen into concrete Helm values before each deploy.

The migration involves three logical phases:

  1. Extract: Capture the effective Helm values that KOTS currently has deployed.

  2. Hand off: Stop KOTS from reconciling the release so that plain helm commands take over.

  3. Upgrade: Perform an ICR-redirect upgrade.

Set environment variables

  1. Make sure you have the following:

    • The Helm release name, typically mission-control.

    • The namespace where Mission Control is installed, typically mission-control.

    • All namespaces that host database clusters managed by this Mission Control instance.

    • An IBM entitlement key from the IBM Container Library. This is required to pull the following images from cp.icr.io: cql-router, cqlsh (cqlsh-pod), hcd, and dse (dse-mgmtapi). Public Mission Control images (mission-control, mission-control-ui, mission-control-dex, k8ssandra-client) are served from the non-entitled icr.io registry, and they do not require the entitlement key.

    • The Mission Control version currently deployed by KOTS. You must migrate to the same version. You can verify the version with helm list -n ${MC_NAMESPACE}.

    • The namespace where the KOTS admin console is running, typically mission-control or a dedicated kotsadm namespace.

    • The pull secret name, typically ${RELEASE_NAME}-registry. For example, if your release name is mission-control, use mission-control-registry. The pull secret is required for the entitled images: cql-router, cqlsh (cqlsh-pod), hcd, and dse (dse-mgmtapi).

  2. Set the following environment variables in your terminal using the information you collected in the previous step:

    export RELEASE_NAME=RELEASE_NAME
    export MC_NAMESPACE=NAMESPACE
    export CLUSTER_NAMESPACES="NAMESPACE1 NAMESPACE2 NAMESPACE3"
    export IBM_ENTITLEMENT_KEY=ENTITLEMENT_KEY
    export TARGET_VERSION=VERSION
    export KOTSADM_NAMESPACE=KOTSADM_NAMESPACE
    export PULL_SECRET_NAME=PULL_SECRET

Construct the Helm values file from exported KOTS values

KOTS renders your admin-console configuration (Deployment Mode, TLS, observability storage, Dex, ingress, and other settings) into Helm values at deploy time. Before you disable KOTS, capture the full set of values that are currently deployed.

The exported values file forms the base of your new Helm-managed installation, and it must be preserved.

  1. Export the values:

    helm get values ${RELEASE_NAME} -n ${MC_NAMESPACE} -o yaml > kots-current-values.yaml
  2. Review the exported values to verify that it contains all values KOTS passed to Helm, including:

    • Deployment mode (controlPlane, controlPlaneRemote)

    • TLS settings (tls.generateCerts, tls.certDuration, tls.certRenewBefore)

    • Dex configuration (issuer URL, LDAP/OIDC connectors, static passwords, TLS volumes)

    • Observability stack (Loki, Mimir, Minio - storage backends, bucket names, PVC sizes, replicas)

    • Ingress configuration

    • Security contexts

  3. Create the base Helm values file:

    cp kots-current-values.yaml my-values.yaml
  4. Add the following ICR overrides to your Helm values file, replacing PULL_SECRET_NAME with your pull secret name,

    These fields disable the Replicated SDK and KOTS-managed pull secret generation, and then redirect all image references to ICR.

    # Disable replicated SDK and KOTS pull secret generation
    replicated:
      enabled: false
    disablePullSecretsGeneration: true
    
    # MC operator
    image:
      registry: icr.io
      repository: datastax-mission-control/mission-control
    
    # MC UI
    ui:
      image:
        registry: icr.io
        repository: datastax-mission-control/mission-control-ui
    
    # CRD patcher
    client:
      image:
        registry: icr.io
        repository: datastax-mission-control/k8ssandra-client
    
    global:
      # Image pull secret for entitled images
      imageConfig:
        defaults:
          pullSecrets:
            - **PULL_SECRET_NAME**   # <RELEASE_NAME>-registry
        images:
          k8ssandra-client:
            registry: icr.io
            repository: datastax-mission-control
            name: k8ssandra-client
          cql-router:                    # entitled — requires cp.icr.io pull secret
            registry: cp.icr.io
            repository: cp/ibm-ds-mission-control
          cqlsh:                         # entitled — requires cp.icr.io pull secret
            registry: cp.icr.io
            repository: cp/ibm-ds-mission-control
        types:
          hcd:                           # entitled — requires cp.icr.io pull secret
            registry: cp.icr.io
            repository: cp/ibm-ds-mission-control
            name: hcd
          dse:                           # entitled — requires cp.icr.io pull secret
            registry: cp.icr.io
            repository: cp/ibm-ds-mission-control
            name: dse-mgmtapi
    
    # MC Dex
    dex:
      image:
        repository: icr.io/datastax-mission-control/mission-control-dex

Update the registry pull secret

KOTS creates the pull secret during installation.

Update the pull secret in the Mission Control namespace only. The Mission Control operator automatically replicates it to all cluster namespaces.

kubectl create secret docker-registry ${RELEASE_NAME}-registry \
  --docker-server=cp.icr.io \
  --docker-username=cp \
  --docker-password=${IBM_ENTITLEMENT_KEY} \
  --namespace=${MC_NAMESPACE} \
  --dry-run=client -o yaml | kubectl apply -f -

The --dry-run=client -o yaml | kubectl apply pattern generates the secret manifest locally and pipes it to kubectl apply, performing a create-or-update. It is idempotent and safe to re-run against the existing Replicated-created secret.

Disable KOTS reconciliation

KOTS continuously watches for configuration changes and redeploys the Helm release when it detects drift. Scaling KOTS components to zero stops KOTS from redeploying over your upcoming helm upgrade.

The KOTS admin console UI is unavailable while scaled to zero, but Mission Control itself continues running.

  1. Scale down all KOTS components to stop automated reconciliation before you run the Helm upgrade:

    kubectl scale deployment kotsadm kotsadm-operator -n ${KOTSADM_NAMESPACE} --replicas=0
    kubectl scale statefulset kotsadm-minio kotsadm-rqlite -n ${KOTSADM_NAMESPACE} --replicas=0
  2. Verify all KOTS pods have terminated:

    kubectl get pods -n ${KOTSADM_NAMESPACE} | grep kotsadm

    All KOTS pods must not be in a Running state before proceeding.

Run helm upgrade with ICR overrides

With KOTS inactive, you must run helm upgrade directly.

Your current and target versions must match exactly. Set TARGET_VERSION in your environment variables to the exact version that was deployed by KOTS.

Don’t use this migration process as an upgrade shortcut. If you want to upgrade the version, you must do so after migrating your installation.

  1. Run helm upgrade with your Helm ICR overrides values.yaml file that you created earlier, which already contains all the KOTS-managed settings:

    helm upgrade ${RELEASE_NAME} oci://icr.io/mission-control-helm/mission-control \
      --version ${TARGET_VERSION} \
      -n ${MC_NAMESPACE} \
      -f my-values.yaml \
      --server-side true
  2. Monitor the deployment rollout:

    kubectl rollout status deployment -n ${MC_NAMESPACE} --timeout=10m
  3. Confirm image sources:

    kubectl get pods -n ${MC_NAMESPACE} \
      -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{range .spec.containers[*]}{.image}{"\n"}{end}{end}'

    All images should reference icr.io/datastax-mission-control/… or cp.icr.io/cp/ibm-ds-mission-control/….

    If any pod is in ImagePullBackOff, verify that the pull secret contains a valid cp.icr.io entry.

Restart cass-operator

After the Helm upgrade, the CassandraDatacenter resources carry updated image configuration pointing to cp.icr.io. Restarting cass-operator causes it to pick up the new configuration and reconcile the database StatefulSets.

  1. Identify the cass-operator deployment:

    kubectl get deployments -n ${MC_NAMESPACE} | grep cass-operator
  2. Restart cass-operator:

    kubectl rollout restart deployment/cass-operator -n ${MC_NAMESPACE}
  3. Wait for the operator to be ready:

    kubectl rollout status deployment/cass-operator -n ${MC_NAMESPACE} --timeout=3m
  4. Watch database pod restarts, repeating for each namespace that contains database pods:

    kubectl get pods -n CLUSTER_NAMESPACE -w

    Replace CLUSTER_NAMESPACE with each cluster namespace.

  5. Confirm image sources, repeating for each cluster namespace:

    kubectl get pods -n CLUSTER_NAMESPACE \
      -o jsonpath='{range .items[]}{.metadata.name}{"\t"}{range .spec.containers[]}{.image}{"\n"}{end}{end}'

    All HCD and DSE containers should reference cp.icr.io/cp/ibm-ds-mission-control/hcd:… or cp.icr.io/cp/ibm-ds-mission-control/dse-mgmtapi:….

  6. Confirm the CassandraDatacenter resources report a healthy status (READY = true, PROGRESS = false):

    kubectl get cassandradatacenter -A

Remove KOTS

Once the Helm-managed installation is verified and stable, remove KOTS entirely. This step is irreversible. The KOTS admin console and all its associated resources are deleted. Mission Control itself is not affected and continues to run. You can manage it with plain helm upgrade commands.

Delete the resources directly with kubectl. Do not use kubectl kots remove.

Because you scaled kotsadm to zero earlier, the kots CLI cannot port-forward to the admin console pod and kubectl kots remove fails with timeout waiting for kotsadm pod.

  1. Delete KOTS deployments and StatefulSets:

    kubectl delete deployment kotsadm kotsadm-operator -n ${KOTSADM_NAMESPACE} --ignore-not-found
    kubectl delete statefulset kotsadm-minio kotsadm-rqlite -n ${KOTSADM_NAMESPACE} --ignore-not-found
  2. Delete KOTS services:

    kubectl delete service kotsadm kotsadm-http -n ${KOTSADM_NAMESPACE} --ignore-not-found
  3. Delete KOTS PersistentVolumeClaims:

    # Verify the exact PVC names first
    kubectl get pvc -n ${KOTSADM_NAMESPACE}
    
    # Delete the PVCs
    kubectl delete pvc -n ${KOTSADM_NAMESPACE} \
      -l app=kotsadm-minio \
      --ignore-not-found
    kubectl delete pvc -n ${KOTSADM_NAMESPACE} \
      -l app=kotsadm-rqlite \
      --ignore-not-found
  4. Delete KOTS-owned secrets and ConfigMaps:

    kubectl delete secret    -n ${KOTSADM_NAMESPACE} -l kots.io/kotsadm=true --ignore-not-found
    kubectl delete configmap -n ${KOTSADM_NAMESPACE} -l kots.io/kotsadm=true --ignore-not-found

Was this helpful?

Give Feedback

How can we improve the documentation?

© Copyright IBM Corporation 2026 | Privacy policy | Terms of use Manage Privacy Choices

Apache, Apache Cassandra, Cassandra, Apache Tomcat, Tomcat, Apache Lucene, Apache Solr, Apache Hadoop, Hadoop, Apache Pulsar, Pulsar, Apache Spark, Spark, Apache TinkerPop, TinkerPop, Apache Kafka and Kafka are either registered trademarks or trademarks of the Apache Software Foundation or its subsidiaries in Canada, the United States and/or other countries. Kubernetes is the registered trademark of the Linux Foundation.

General Inquiries: Contact IBM