# Kubernetes Migration Guides

Source: https://docs.quake.ai/docs/kubernetes/migration
Markdown: https://docs.quake.ai/docs/kubernetes/migration.md

---

# Kubernetes migration guides

Move your Kubernetes workloads to Quake AI from a managed Kubernetes provider or from a self-managed setup on another cloud. The core shift in most migrations is from a provider-operated control plane (EKS, GKE, AKS, DOKS) to one you operate yourself. On Quake AI you provision Kubernetes two ways: through Magnum, which builds a cluster from a curated template, or self-managed on Nova instances that you install and maintain. Coming from a self-managed source such as Kubernetes on Hetzner Cloud, you keep the self-managed model and move the underlying infrastructure to Nova instances. Either way, you gain control over the cluster, no provider lock-in on networking or storage drivers, and Quake AI's bandwidth-inclusive pricing.

## Two paths to Kubernetes on Quake AI

Quake AI provisions Kubernetes two ways. Both are supported; the right choice depends on how much control you need over the cluster's Kubernetes version, CNI, and CRI.

### Magnum

Magnum, the Container Infrastructure Management service, provisions a control plane and worker nodes from a curated cluster template (`openstack coe cluster create`). Platform templates ship pre-wired with Calico CNI, the OpenStack cloud-provider stack (CCM + Cinder CSI), and a load-balanced API endpoint, so a cluster is fast to stand up. You operate the cluster after creation: upgrades, node-pool sizing, and etcd backups. The Kubernetes version comes from the template catalog, so run `openstack coe cluster template list` to see the versions your region offers.


`openstack coe cluster create` requires a password-scoped Keystone session, not application credentials: Magnum uses Keystone trust delegation, which application credentials cannot perform. See the [Kubernetes FAQ](/docs/kubernetes/faq) for the workaround.


### Self-managed on Nova instances

Provision Nova VMs with OpenTofu, install Kubernetes using kubeadm, k3s, or RKE2, and add the OpenStack cloud-provider stack (CCM + Cinder CSI). This path gives you full control over the Kubernetes version, CNI, CRI, and upgrade cadence, which helps when you need to match a source cluster exactly or run a version outside the template catalog.

```text
OpenTofu (openstack provider)
  -> Nova VMs (control plane x3 + worker nodes)
  -> Neutron private network
  -> stable endpoint for the K8s API
  -> kubeadm init / k3s install / rke2 install
  -> openstack-cloud-controller-manager
  -> Cinder CSI driver
  -> CNI (Calico / Cilium)
```

## Choose your source provider

<UseCaseGrid>
<UseCaseCard
  title="Migrate from AWS EKS"
  description="IRSA removal, EBS-to-Cinder data migration, ALB-to-nginx-ingress, VPC CNI replacement, Fargate pod migration, and Karpenter alternatives."
  href="/docs/kubernetes/migration/migrate-from-eks"
  difficulty="advanced"
  services={["Kubernetes"]}
/>
<UseCaseCard
  title="Migrate from DigitalOcean DOKS"
  description="Minimal vendor lock-in. Swap DO CSI and CCM for OpenStack equivalents. Mirror container images from DO Container Registry."
  href="/docs/kubernetes/migration/migrate-from-doks"
  difficulty="advanced"
  services={["Kubernetes"]}
/>
<UseCaseCard
  title="Migrate from Kubernetes on Hetzner Cloud"
  description="Closest operational model. Swap hcloud CCM and CSI for OpenStack equivalents. Familiar self-managed ethos."
  href="/docs/kubernetes/migration/migrate-from-hetzner-k8s"
  difficulty="advanced"
  services={["Kubernetes"]}
/>
<UseCaseCard
  title="Migrate from GCP GKE"
  description="Workload Identity removal, Config Connector CRD cleanup, GKE Ingress replacement, and Autopilot constraint removal."
  href="/docs/kubernetes/migration/migrate-from-gke"
  difficulty="advanced"
  services={["Kubernetes"]}
/>
<UseCaseCard
  title="Migrate from Azure AKS"
  description="Most complex migration. Entra ID pod identity removal, Azure Key Vault secret extraction, Azure CNI replacement, AGIC-to-nginx-ingress."
  href="/docs/kubernetes/migration/migrate-from-aks"
  difficulty="advanced"
  services={["Kubernetes"]}
/>
<UseCaseCard
  title="Migrate from Linode LKE"
  description="Swap the linode-cloud-controller-manager and linode-blockstorage CSI for OpenStack equivalents. Mirror images out of the Linode Container Registry. Self-managed control plane on Nova."
  href="/docs/kubernetes/migration/migrate-from-lke"
  difficulty="advanced"
  services={["Kubernetes"]}
/>
<UseCaseCard
  title="Migrate from Vultr VKE"
  description="Swap the vultr-cloud-controller-manager and vultr-csi block storage driver for OpenStack equivalents. Mirror images out of Vultr Container Registry. Self-managed control plane on Nova."
  href="/docs/kubernetes/migration/migrate-from-vke"
  difficulty="advanced"
  services={["Kubernetes"]}
/>
</UseCaseGrid>

## What's portable and what's not

### Fully portable (no changes required)

Deployments, StatefulSets, DaemonSets, ConfigMaps, Secrets (values), Namespaces, ServiceAccounts (minus cloud IAM annotations), all RBAC resources, NetworkPolicy, HPA, VPA, PodDisruptionBudget, CronJobs, and Jobs migrate without modification. Helm charts using standard Kubernetes resources deploy cleanly with updated values.

### Portable with adaptation

| Resource | What changes |
|---|---|
| Ingress | `ingressClassName` and provider-specific annotations must change |
| Service (LoadBalancer) | Works through the cloud controller; remove provider-specific annotations |
| PersistentVolumeClaim | `storageClassName` must reference the Cinder StorageClass |

### Provider-specific (must be replaced)

| Component | All providers | Quake AI replacement |
|---|---|---|
| Block storage CSI driver | Provider-specific CSI | `cinder.csi.openstack.org` (Cinder CSI) |
| Cloud controller manager | Provider-specific CCM | `openstack-cloud-controller-manager` |
| Ingress controller | ALB (EKS), GCLB (GKE), AGIC (AKS) | ingress-nginx or Traefik with a `LoadBalancer` Service |
| Pod identity (IAM) | IRSA (EKS), Workload ID (GKE/AKS) | OpenStack app credentials in K8s Secrets |
| CNI | VPC CNI (EKS), Azure CNI / Azure CNI Overlay (AKS), GKE Dataplane V2 (Cilium, default on Autopilot) | Calico (VXLAN) or Cilium |
| Node autoscaler | Karpenter (EKS standalone or EKS Auto Mode), AKS Node Auto-Provisioning (NAP), GKE NAP or managed Cluster Autoscaler | Cluster Autoscaler with OpenStack provider, or manual scaling |
| Monitoring | CloudWatch, Cloud Operations, Azure Monitor | Prometheus + Grafana + Loki (self-managed) |
| Secret store | AWS Secrets Manager, Azure Key Vault CSI | K8s Secrets or HashiCorp Vault |

Each provider guide documents additional provider-specific resources you must remove. Notable examples: GKE Config Connector CRDs (`cnrm.cloud.google.com`), the AKS Azure Policy pod, the AKS `omsagent` and `ama-logs` DaemonSets, and EKS Security Group Policies for Pods.

### Operators and Helm charts that are fully portable

cert-manager, external-dns, prometheus-operator (kube-prometheus-stack), Loki, Grafana, Velero, Istio, Linkerd, ArgoCD, Flux, ingress-nginx, Traefik, Metrics Server, and HashiCorp Vault all deploy on Quake AI without modification. Only configuration values (endpoints, credentials) change.

## Recommended self-managed stack on Quake AI

If you provision Kubernetes yourself on Nova instances, this stack is a solid starting point.

| Component | Recommendation |
|---|---|
| Infrastructure provisioning | OpenTofu with `openstack` provider |
| K8s installer | RKE2 (production) or k3s (lightweight) |
| Cloud controller | `openstack-cloud-controller-manager` |
| Block storage | Cinder CSI (`cinder.csi.openstack.org`) with `cinder-flash` StorageClass |
| CNI | Calico (VXLAN) or Cilium |
| Ingress | ingress-nginx |
| TLS certificates | cert-manager + Let's Encrypt |
| DNS management | external-dns (Cloudflare, NS1, or other provider) |
| Observability | kube-prometheus-stack + Loki + Grafana |
| Backup and migration | Velero with Swift/S3 backend |

Each migration guide documents both provisioning paths. Some lead with Magnum and others with the self-managed path, depending on the source platform and how closely you need to match its Kubernetes version and CNI. See [Two paths to Kubernetes on Quake AI](#two-paths-to-kubernetes-on-quake-ai) for the trade-offs.

## Data migration with Velero

[Velero](https://velero.io/) is the primary tool for migrating K8s resources and persistent volume data between clusters. It backs up all API objects to object storage and uses filesystem-level backup (via node-agent) to copy PVC data independent of the source CSI driver.

For cross-provider migration, use `--default-volumes-to-fs-backup` so PVC data is captured at the filesystem level instead of through cloud-native snapshots.

Velero supports **StorageClass remapping** at restore time via a ConfigMap, so it maps source StorageClass names (like `gp2`, `do-block-storage`, `hcloud-volumes`) to `cinder-flash` on Quake AI automatically.

## Migration complexity by provider

| Provider | Complexity | Primary drivers | Estimated timeline |
|---|---|---|---|
| DigitalOcean DOKS | Low | Minimal lock-in, simple CSI/CCM swap | 1-2 weeks |
| Kubernetes on Hetzner Cloud | Low-Medium | Similar architecture, IaC rewrite | 1-2 weeks |
| AWS EKS | Medium-High | IRSA, EBS data, ALB, VPC CNI, Fargate | 4-8 weeks |
| GCP GKE | Medium-High | Workload Identity, Config Connector, Autopilot | 3-6 weeks |
| Azure AKS | High | Entra ID, Key Vault CSI, Azure CNI, AGIC | 6-12 weeks |

## See also

- [Migrate to Quake AI](/resources/migration): cross-service migration hub
- [Kubernetes on Quake AI](/docs/kubernetes): service overview
- [Compute migration guides](/docs/compute/migration): if you also need to move non-K8s VMs
- [Network migration guides](/docs/network/migration): networking topology migration
- [Object storage migration](/docs/object/migration): if you also need to move storage
