ankra migrate up takes a directory holding a Docker Compose file and moves the whole deployment into a cluster Ankra runs: it converts the services into a stack, applies the stack, and then moves the data out of the deployment’s PostgreSQL, MySQL and MariaDB databases into the databases it just deployed. A bare Dockerfile and the running Docker daemon work as sources too.--stop-source to cut over.
Prerequisites
- A logged-in session:
ankra login, orANKRA_API_TOKENin the environment. - A target cluster in the organisation running an Ankra agent new enough to run data restores. An older agent makes the platform refuse the restore with
409:The cluster's agent does not support data restores yet; upgrade the agent first. - The backups feature enabled for the organisation, and a backup vault in the
readystate. The dumps travel through the vault’s bucket.ankra backup vaults listshows what you have,ankra backup vaults provisioncreates one. With exactly one ready vault the CLI picks it; with several, name one with--vault. - Docker reachable from wherever the command runs. Locally that is the daemon on your machine; for a deployment on another host, point at it with
--option docker-host=ssh://root@host.
Plan first
--plan prints what the run would do and changes nothing:
- The module detected in the source directory, the target cluster, the stack (new, or an existing one that will be updated) and the namespace. The stack defaults to the source directory’s name and the namespace to the stack’s name.
ankra migrate detect ./appreports which modules recognise a directory, andankra migrate moduleslists the ones available. - The output directory (
--out, defaultankra-migration): the conversion is written to<out>/stackand the dumps to<out>/data. A directory holding nothing but an earlier run’sstack/anddata/is reused, so running the same command again needs no extra flag. - Every database server it found, with its engine, version and user, and each database on it with the size read from the running container (
pg_database_sizeon PostgreSQL,information_schemaon MySQL and MariaDB). - The estimated dump size against the free disk where the dumps will be written. The run refuses rather than filling the disk.
- Warnings, such as a database above 625 GiB (more than a single upload can carry), or the
postgresmaintenance database being skipped. Ifpostgresreally is your application database, say so with--option databases.<workload>=postgres. - A not carried list: files in the volumes of non-database workloads, and data in engines the export does not dump.
--plan the same summary is printed and the run waits for a confirmation. --yes skips the prompt.
Run it
1
Convert
The source is converted into a stack, exactly as
ankra migrate convert would, and written to <out>/stack.2
Deploy
The stack is applied to the cluster under its name, the same write
ankra cluster apply performs, and the command waits for the platform to accept it.3
Wait for the databases
Each database workload has to have a running, ready pod before anything is restored into it.
4
Export
The dumps are taken from the source, as
ankra migrate export would, into <out>/data.5
Restore
The dumps are uploaded through the vault, verified, restored in-cluster, and the command waits for the restore to finish.
--option ingress.<workload>=<host>, what is still running on the source, and whether the run was a rehearsal.
To publish a workload and get TLS for it, pass the host and the issuer:
Flags
Rehearse, then cut over
Nothing about the run requires the source to be stopped, so rehearse with it live, look at what landed in the cluster, and repeat until you are happy. When you are, cut over:Running again over the same output directory needs no extra flag: a directory holding nothing but an earlier run’s
stack/ and data/ is reused. --force is only for an output directory that holds something else, and the refusal names the file that is in the way: <out> holds notes.txt, which no earlier run of this command wrote; pass --force to overwrite it or --out for another directory.--stop-source stops the source’s non-database services before the final dump is taken, so nothing writes to the source databases while they are being read. The databases themselves stay up for the dump. The summary prints the docker start ... command that brings the source back if you need to roll back. Once you are satisfied, move DNS to the cluster.
Running the steps separately
The same work is available as individual commands when you want to inspect what each one produced:ankra migrate data ./app --cluster production --wait runs steps 3 and 4 together. A restore that was started without --wait can be followed with ankra migrate restore-status <import-id> --wait.
Options
--option is repeatable, and ankra migrate up accepts both sets. The conversion takes:
The export takes:
How the data travels
The dump runs inside each database container, through the container’s own shell. The password is read from the container’s environment,*_FILE secrets are honoured, and no credential is ever put on the host’s command line.
- PostgreSQL:
pg_dump -Fcper database, pluspg_dumpall --globals-only --no-role-passwordsfor the roles. - MySQL and MariaDB:
mysqldump --single-transaction --routines --triggers --events --databases, as root where a root password exists and otherwise as the application user.
postgres, postgis, pgvector or timescaledb, and mysql, mariadb or percona. Sidecars are left alone: an image whose name contains exporter, proxy, bouncer, backup, operator, client or admin is never dumped from.
Dumps are written 0600 alongside a manifest.json and a SHA256SUMS.
On the way in, the CLI uploads straight to the vault’s own bucket using presigned URLs the platform mints under imports/<import-id>/. A dump above 1 GiB goes up in parts of 64 MiB, each retried on its own, so one stalled part costs a part rather than the whole upload. The platform starts the multipart upload and the CLI completes it, aborting it if it cannot finish, so the vault is never left holding half an artifact. The progress line names the size and the part count:
HEAD, and then the cluster’s agent runs a Kubernetes Job in the target namespace: an init container downloads the artifacts and checks them against their SHA-256 sums, and the engine client (postgres:<major>-alpine, or mysql/mariadb:<version>) waits for the database to accept connections and restores into it. Roles and globals go first, then each database, with pg_restore --clean --if-exists --no-owner or mysql < file. The Job connects using the Service and Secret the conversion generated.
Ankra never holds your data: it goes from your source to your vault’s bucket to your cluster. No vault credential is handed to the cluster, and nothing on the machine running the command needs
kubectl or a database client.The dumps a restore leaves in the vault
Every restore keeps its upload underimports/<import-id>/ in the vault, so the same import can be restored again without dumping the source a second time. The dumps stay there until you remove them.
list gives each import’s id, stack, status, databases, size and when it was created. delete removes the dumps from the vault and forgets the import, and refuses one whose restore is still running; --yes skips its confirmation. A restore that completes prints the delete command for the import it just finished, so the cleanup is there when you want it.
Deleting the vault itself also removes the dumps of every import it held, on a bucket you own.
What is not carried
- Files in the volumes of non-database workloads. Uploads, caches and other on-disk state have to be copied into the PVC yourself.
- Data in engines the export does not dump: Redis, Valkey, MongoDB, Elasticsearch and OpenSearch, RabbitMQ, MinIO, ClickHouse, InfluxDB, Neo4j, Cassandra and CouchDB. Their workloads are converted and deployed; they simply come up empty. The plan names each one it found.
- A single artifact above 625 GiB, which is the 10,000 parts of 64 MiB one upload can carry.
ankra migrate restorerefuses a larger one before it registers the import, sayingan upload carries at most 625.0 GiB. - PostgreSQL role passwords. Roles are restored without them. The application user keeps the password from the cluster Secret, so the application works; any other login role needs an
ALTER ROLE ... PASSWORDafterwards.
pg_restore that finishes with “errors ignored” (exit code 1) is reported as a warning and the restore is treated as successful, which is the normal outcome when the target database already holds some of the objects.
Troubleshooting
A failed restore keeps its Job in the namespace for an hour. The agent already tails the Job’s log into the failed step, so the reason usually travels with the operation, and the CLI reports
the restore of import <import-id> failed: .... To read the Job yourself while it is still there, through Ankra (with the
cluster selected via ankra cluster select <cluster>):
Next steps
Backup vaults
Provision the vault the dumps travel through.
Stacks
Understand the stack the conversion produced.
Ankra CLI
Install the CLI and browse the rest of its commands.
Import a cluster
Connect the cluster you are migrating into.