Cluster Migration
Skipper can migrate entire projects (apps, services, databases with data, volumes, functions, jobs, and secrets) from one cluster to another. No kubectl, no manual exports.
When to use migration
- Moving from an old server to a new one
- Upgrading hardware (bigger server, different provider)
- Splitting a cluster (move some projects to a separate server)
- Disaster recovery (restore from a running cluster to a new one)
How it works
Migration is a console feature with visual progress. The flow:
- Generate token on the new cluster (target)
- Paste token on the old cluster (source), select projects
- Watch progress as data transfers automatically
- Verify apps on temporary URLs before touching DNS
- Cutover custom domains and update DNS
What gets migrated
| Resource | How |
|---|---|
| Project CRs | Created on target, namespaces auto-provisioned |
| Kubernetes Secrets | Transferred directly (credentials, env vars, registry auth) |
| Service CRs | Created on target, StatefulSets auto-provisioned |
| Database data | Exported via pg_dumpall / mysqldump / mongodump, imported on target |
| Redis data | RDB snapshot transferred |
| RabbitMQ definitions | Exported and imported via rabbitmqctl |
| Volumes | PVC data tarred, transferred, extracted on target |
| Container images | Manifests transferred between Zot registries |
| App CRs | Created on target with temporary routes |
| Function CRs | Created on target |
| Job CRs | Created on target |
| Custom domain routes | Applied after user verifies apps work |
What is NOT migrated
- System components (Traefik, cert-manager, Longhorn, Dex), which already exist on the target from
kip install - TLS certificates, because cert-manager issues new ones on the target
- Build history (only the current image is migrated)
- Pod logs (ephemeral by nature)
Step-by-step guide
1. Prepare the target cluster
Install Skipper on the new server:
kip install --host 203.0.113.20The target cluster should be running with no projects deployed (or projects that don't conflict with what you're migrating).
2. Generate a migration token
On the target cluster's console, go to Migration and click Receive from another cluster. Copy the generated token.
The token is valid for 24 hours and can only be used once.
3. Start the migration
On the source cluster's console, go to Migration and click Migrate to another cluster. Paste the token and select which projects to migrate.
If a project already exists on the target, you'll be asked to confirm the overwrite by typing the project name.
Click Start migration.
4. Monitor progress
The migration view shows:
- Two cluster icons with animated data flow indicators
- A step-by-step list with checkmarks, spinners, and progress counters
- A detail panel showing the current operation
Typical steps:
- Creating project on target
- Waiting for namespaces
- Transferring secrets
- Creating services and waiting for databases to start
- Exporting and importing database data
- Transferring volume data
- Transferring container images
- Creating apps (with temporary URLs)
- Verifying health
5. Verify your apps
After migration completes, apps are live on temporary *.kipper.run subdomains. The verification dashboard shows each app with its temporary URL and status.
Click each URL to verify the app works correctly. Check that pages load, database connections work, and functionality is intact.
6. Apply custom domains
When everything looks good, click Everything looks good, apply custom domains. Skipper applies the original route configuration and shows DNS update instructions.
Update your DNS records to point to the new server's IP address. Skipper checks DNS propagation automatically and shows resolved/pending status for each domain.
Limitations
- Database size: Databases up to ~500MB transfer in a single request. Larger databases may need manual migration.
- OpenSearch and MinIO: Data transfer for these services is not yet automated. Migrate data manually after the project structure is created.
- Build artifacts: Only the latest container image is transferred, not the full build cache.
- Active connections: Apps on the source cluster continue running during migration. There is no automatic traffic cutover. DNS changes propagate gradually.
Troubleshooting
Migration token expired
Tokens are valid for 24 hours. Generate a new one on the target cluster.
Target cluster unreachable
The source cluster connects to the target's console-api over HTTPS. Ensure the target's console URL is accessible from the source server (no firewall blocking outbound HTTPS).
Database import failed
If the database import fails, the Service CR still exists on the target. You can manually export and import the data:
# On source: export
kubectl exec -n <namespace> <pod> -- pg_dumpall -U skipper > dump.sql
# Copy to target server and import
kubectl exec -i -n <namespace> <pod> -- psql -U skipper -d app < dump.sqlApps stuck in pending
After migration, apps need time to pull container images and start. Check the target cluster's console for pod status and logs.
