Skip to main content

Migrating from db-manager Databases

KdcDatabase (db.kube-dc.com/v1alpha1), operated by db-manager, was Kube-DC's first database product. It is deprecated. Managed Services is the database offer for every engine, and this page is for teams that still run a KdcDatabase.

What deprecated means for you

  • No new KdcDatabase can be created from the console, and the agent skills and documentation describe managed services only.
  • Your existing databases keep running. db-manager keeps reconciling them, their scheduled backups keep running, DatabaseCredentialPolicy keeps rotating passwords, and kube-dc db credentials keeps working.
  • The Databases area of the console is shown only for the organizations and Projects your provider has listed as still running these databases, with a deprecation notice. Everyone else sees Managed services alone; a bookmarked link to Databases explains where to go.
  • Your provider will retire db-manager once the last KdcDatabase on the installation is gone. Ask them for the date. Until then, this page is the reference for the resources you still have.

Kube-DC does not convert a KdcDatabase into a ManagedService, and a ManagedService cannot be restored from a KdcDatabase backup. You create the managed service, copy the data with the engine's own tools from inside your Project, repoint the application, and delete the old database.

Migration procedure

  1. Create the managed service with the same engine, a plan whose capacity covers the old database, and the same database name. PostgreSQL: Create a PostgreSQL Service; MariaDB: MySQL and MariaDB. Wait for Ready.
  2. Bind a credential for the migration: an owner binding whose Secret the copy Job reads. See Connect Applications.
  3. Freeze writes to the old database (stop the application or put it in read-only mode) and copy the data with one of the Jobs below. The Job runs in your Project, reads the old engine Secret and the new binding Secret, and never prints a password.
  4. Repoint the application at the new binding Secret, using the key names in the mapping. Start it, check it, and keep the old database untouched until you have verified the copy.
  5. Delete the old database with kubectl delete kdcdatabase <name> and any DatabaseCredentialPolicy that referred to it. Its Secrets go with it.

Check that the old database's last backup is recent before step 3, in case the migration has to be repeated.

PostgreSQL copy Job

The KdcDatabase engine Secret is <db>-app (keys username, password, and the service <db>-rw.<namespace>.svc:5432). Replace legacy-db, orders-db, orders-api-db (the binding Secret) and my-project:

apiVersion: batch/v1
kind: Job
metadata:
name: migrate-orders
namespace: my-project
spec:
backoffLimit: 0
template:
spec:
restartPolicy: Never
containers:
- name: copy
image: ghcr.io/cloudnative-pg/postgresql:17.11
command: ["/bin/sh", "-ec"]
args:
- |
export PGSSLROOTCERT=/etc/target/ca.crt
pg_dump --no-owner --no-privileges \
"postgresql://$SRC_USER:$SRC_PASSWORD@legacy-db-rw.my-project.svc:5432/orders?sslmode=require" \
| psql --set ON_ERROR_STOP=1 \
"postgresql://$DST_USER:$DST_PASSWORD@$DST_HOST:$DST_PORT/$DST_DB?sslmode=verify-full"
env:
- { name: SRC_USER, valueFrom: { secretKeyRef: { name: legacy-db-app, key: username } } }
- { name: SRC_PASSWORD, valueFrom: { secretKeyRef: { name: legacy-db-app, key: password } } }
- { name: DST_HOST, valueFrom: { secretKeyRef: { name: orders-api-db, key: host } } }
- { name: DST_PORT, valueFrom: { secretKeyRef: { name: orders-api-db, key: port } } }
- { name: DST_DB, valueFrom: { secretKeyRef: { name: orders-api-db, key: dbname } } }
- { name: DST_USER, valueFrom: { secretKeyRef: { name: orders-api-db, key: username } } }
- { name: DST_PASSWORD, valueFrom: { secretKeyRef: { name: orders-api-db, key: password } } }
volumeMounts:
- { name: target, mountPath: /etc/target, readOnly: true }
volumes:
- name: target
secret:
secretName: orders-api-db
items: [{ key: ca.crt, path: ca.crt }]
kubectl apply -f migrate-orders.yaml
kubectl wait --for=condition=Complete --timeout=1h job/migrate-orders -n my-project
kubectl logs job/migrate-orders -n my-project

--no-owner --no-privileges drops the old login's ownership so the objects belong to the new owner role. Extensions the old database used must be available in the new service; check the dump's CREATE EXTENSION lines first.

MariaDB copy Job

The KdcDatabase engine Secret is <db>-password (key password, user app), reachable at <db>.<namespace>.svc:3306 for one replica or <db>-primary.<namespace>.svc:3306 for several:

apiVersion: batch/v1
kind: Job
metadata:
name: migrate-shop
namespace: my-project
spec:
backoffLimit: 0
template:
spec:
restartPolicy: Never
containers:
- name: copy
image: docker.io/library/mariadb:11.8
command: ["/bin/sh", "-ec"]
args:
- |
mariadb-dump --host legacy-shop.my-project.svc --port 3306 \
--user app --password="$SRC_PASSWORD" --single-transaction --routines --triggers shop \
| mariadb --host "$DST_HOST" --port "$DST_PORT" --user "$DST_USER" --password="$DST_PASSWORD" \
--ssl-ca /etc/target/ca.crt --ssl-verify-server-cert "$DST_DB"
env:
- { name: SRC_PASSWORD, valueFrom: { secretKeyRef: { name: legacy-shop-password, key: password } } }
- { name: DST_HOST, valueFrom: { secretKeyRef: { name: shop-api-db, key: host } } }
- { name: DST_PORT, valueFrom: { secretKeyRef: { name: shop-api-db, key: port } } }
- { name: DST_DB, valueFrom: { secretKeyRef: { name: shop-api-db, key: database } } }
- { name: DST_USER, valueFrom: { secretKeyRef: { name: shop-api-db, key: username } } }
- { name: DST_PASSWORD, valueFrom: { secretKeyRef: { name: shop-api-db, key: password } } }
volumeMounts:
- { name: target, mountPath: /etc/target, readOnly: true }
volumes:
- name: target
secret:
secretName: shop-api-db
items: [{ key: ca.crt, path: ca.crt }]

Secret keys

An application that reads the old engine Secret, or the Secret a DatabaseCredentialPolicy projected, changes to the binding Secret:

Old key (DatabaseCredentialPolicy projection)Binding Secret keyChange
username, password, host, portSame namesChange the Secret name only
databasedbname (PostgreSQL), database (MySQL, MariaDB)Key name, for PostgreSQL
dsnuriKey name. The PostgreSQL URI uses sslmode=verify-full, so the client also needs the CA
engineNot deliveredSelect the driver in the application configuration
Noneca.crt, sslmode or tlsMount ca.crt; PostgreSQL clients set PGSSLROOTCERT and PGSSLMODE=verify-full

The old PostgreSQL engine Secret <db>-app and MariaDB Secret <db>-password use password too. The old dsn value used sslmode=require, which does not check the server's name; binding Secrets always verify it.

What replaces what

You usedIn Managed Services
KdcDatabaseManagedService with the class postgresql, mysql or mariadb, a plan and the connectivity class tenant-native
The engine Secret, or the Secret a DatabaseCredentialPolicy projectsA ServiceBinding, which delivers a Secret with connection details, the credential and the CA
DatabaseCredentialPolicyA ServiceCredentialPolicy for scheduled rotation; a ServiceBinding for delivery
Native backup objects you create and listA Backup operation and read-only ServiceBackup records
Field edits, annotations and kube-dc db commands for day-2 actionsOne ServiceOperation per action, or the console's actions
The Databases area of the consoleManaged services

Fields

KdcDatabase fieldManagedService equivalentDifference
spec.enginespec.classRef.nameThe class, plan, placement and connectivity cannot change after creation
spec.versionspec.engineVersion, or omit it to take the plan's versionYou choose a version by choosing a plan. Later versions arrive through MinorUpgrade and MajorUpgrade operations
spec.databaseNamespec.parameters.databaseCreateOnly
spec.usernamespec.parameters.owner (PostgreSQL)CreateOnly; MySQL and MariaDB name their owner login for you. The login is delivered through the owner role
spec.cpu, spec.memoryspec.compute.cpu, spec.compute.memoryWithin the plan's capacity.computeBounds; changed by a Resize operation where the family allows it
spec.storagespec.storage.sizeAt most the plan's capacity.maxStorage; grown by ExpandStorage where the family and the storage class allow it
spec.storageClassNamespec.storage.classCreateOnly; the plan default or one of its allowedStorageClasses
spec.replicasspec.topology.instancesWithin the plan's topology bounds; changed by a Scale operation for PostgreSQL
spec.parametersspec.parameters.postgresql.parameters or parameters.settingsAllow-listed settings with string values
spec.backup.*spec.parameters.backup.* (PostgreSQL) or the plan's scheduleWithin the plan's backup bounds
spec.backup.s3Endpoint, spec.backup.s3CredentialSecretspec.parameters.backup.store (PostgreSQL)Needs the plan's backup.allowedCustomEndpoints; CreateOnly
spec.expose.typespec.parameters.expose.type (PostgreSQL)gateway and loadbalancer need plan entitlements; see External Access
spec.breakGlass.enableSuperuserAccessspec.parameters.breakGlass.enableSuperuserAccess (PostgreSQL)Needs the plan's credentials.allowBreakGlass
spec.restoreFrom.backupName, .targetTimespec.restoreFrom.serviceRef, .serviceUID, .backupRef or .targetTimeThe source is a ManagedService in the same Project and its ServiceBackup record
Nonespec.deletionPolicy, spec.deletionProtectionNew. The default policy is Retain

Day-2 actions

With KdcDatabaseWith Managed Services
Change spec.version for a major upgradeA MajorUpgrade operation (PostgreSQL) with an image from the plan's allowedImages; needs a completed backup
Create a native backup objectA Backup operation, or Back up now in the console
List native backup objectsServiceBackup records, or the Backups tab
Annotate with kube-dc.com/restore-fromA RestoreInPlace operation (PostgreSQL) with engineUID, acknowledgeDataLoss: true and backupID or targetTime, or a restore into a new service for every family
kube-dc db credentials rotateA RotateCredentials operation, or the action in Users & access
kube-dc db credentials get --show-passwordRead the binding Secret, or reveal it in Users & access

Credential policies

DatabaseCredentialPolicy fieldServiceCredentialPolicy equivalentDifference
spec.databaseRef.namespec.serviceRef.name and spec.serviceUIDserviceUID is required
spec.username of the application userspec.role: ownerspec.role: readonly rotates the read-only login
spec.username of another existing loginspec.existingUser.username and .databaseNeeds the plan's credentials.allowExistingUsers; the login must already exist
spec.mode: static-rotatedNoneA policy only rotates passwords. It never creates a login
spec.rotation.interval, such as 30dspec.rotationIntervalSeconds, 60 to 31536000Default 2592000 (30 days)
spec.sync.enabled, spec.sync.targetSecretNameA ServiceBinding with delivery.secretNameA policy never delivers a Secret itself

Deleting a DatabaseCredentialPolicy removes the Secret it projected. Deleting a ServiceCredentialPolicy of a declared role keeps its bindings and their Secrets. See Credentials and Rotation.

While you still run a KdcDatabase

The resource keeps its API: kubectl get kdcdatabase <name> -n <namespace> shows its phase and conditions, spec.backup holds the schedule and retention, and the console's Databases area (where your Project is listed) shows connection details, credential policies, backups and the restore actions. Confirm the BackupReady condition before you rely on a backup, and plan the migration before your provider's retirement date.