Moving self-managed Kubernetes (kubeadm, Rancher/RKE, OpenShift) to Amazon EKS is less a rewrite than a swap of the pieces underneath your workloads: EKS runs and upgrades the control plane and etcd for you, and you re-point storage to the EBS/EFS CSI drivers, load balancing to the AWS Load Balancer Controller, ServiceAccount RBAC to IRSA, your registry to ECR, and cluster-autoscaler to Karpenter. Your Deployments, Services, and ConfigMaps mostly carry over. This page walks the full mapping, how to move PersistentVolumes and Secrets, a Velero backup-restore cutover, and rollback. The kicker: on a qualifying migration, AWS MAP funds the work and a vetted partner runs it — often at little-to-no cost to you.
If your cluster already runs, the honest question is "what does EKS buy me that kubeadm or Rancher doesn't?" The answer is almost entirely operational: EKS removes the part of Kubernetes that is thankless to run and easy to get wrong — the control plane, etcd, and upgrades.
On a self-managed cluster you own the API server, scheduler, controller-manager, and etcd — which means you own etcd backups and restores, etcd disk and compaction, control-plane certificate rotation, HA across availability zones, and minor-version upgrades. None of this differentiates your product; it is pure toil, and it is the work that pages your platform team at 2 a.m. EKS runs that control plane as a managed, multi-AZ service and gives you a one-action upgrade path, so the stateful, high-blast-radius layer becomes someone else's on-call rotation. For most teams that is the entire reason to move: fewer ways to lose a cluster.
Beyond the control plane, EKS plugs you into the rest of AWS without glue code. EKS add-ons manage the VPC CNI, CoreDNS, kube-proxy, and the EBS/EFS CSI drivers as versioned, AWS-supported components; IRSA and Pod Identity give pods scoped IAM without long-lived keys; Karpenter gives you bin-packed node autoscaling; and ECR, CloudWatch Container Insights, and the AWS Load Balancer Controller wire images, observability, and ingress into managed services. If your workloads will live next to RDS, S3, SQS, and Bedrock anyway, EKS removes a lot of cross-cloud and self-hosted seams.
The honest tradeoff: EKS is neither free nor zero-effort. You pay an hourly per-cluster fee for the managed control plane on top of worker-node and data-transfer costs, and you still operate nodes, add-ons, and your apps. What you buy is the elimination of the highest-risk operational surface, plus native AWS integration — not the elimination of Kubernetes operations entirely. The next sections cover exactly what you re-wire to get there.
Self-managed Kubernetes makes you the on-call for etcd, control-plane HA, and upgrades. EKS makes AWS the on-call for that layer, and turns the VPC CNI, CSI drivers, CoreDNS, and IAM integration into versioned managed add-ons. You keep your manifests; you give away the 2 a.m. failure modes.
A self-managed cluster and EKS speak the same Kubernetes API, so your application objects move almost verbatim. What changes is the layer where Kubernetes touches infrastructure: storage, load balancing, identity, registry, and node scaling. Get these five right and the migration is mostly mechanical.
The useful mental model: sort everything into "workload objects" (portable) and "infrastructure integrations" (must be remapped). Deployments, StatefulSets, DaemonSets, ClusterIP Services, ConfigMaps, HPAs, NetworkPolicies, CRDs, and Helm charts are workload objects — they reference Kubernetes concepts, not your old cloud or data center, so they port over. The integrations below referenced your old StorageClass, ingress controller, node IAM, registry, and autoscaler — and those are what you rebuild on AWS primitives.
From: a self-managed StorageClass backed by local disks, Ceph/Rook, NFS, vSAN, or a vendor CSI; PVs pinned to that backend.
To: the Amazon EBS CSI driver for ReadWriteOnce block volumes (most databases and single-writer workloads) and the Amazon EFS CSI driver for ReadWriteMany shared filesystems — both installed as EKS managed add-ons, with new StorageClasses (e.g. gp3).
What you do: recreate StorageClasses, then migrate the data in the PVs — they don't teleport between clusters. Section IV covers the data-movement options (Velero, EFS DataSync, app-native replication).
From: an NGINX/Traefik/HAProxy ingress controller, a MetalLB Service of type LoadBalancer, or an OpenShift Route.
To: the AWS Load Balancer Controller. Ingress objects provision an Application Load Balancer (ALB) for HTTP/HTTPS; Services of type LoadBalancer provision a Network Load Balancer (NLB) for L4. You can keep NGINX/Traefik in front of an NLB to preserve existing ingress rules verbatim — a common low-risk first step.
What you do: install the controller (it needs an IRSA role), add ALB ingress annotations, request ACM certificates for TLS at the ALB, and decide per-service between native ALB ingress or your existing controller behind an NLB.
From: pods inheriting the node's IAM role, mounted long-lived cloud credentials, or instance-profile-wide permissions.
To: IAM Roles for Service Accounts (IRSA) or the newer EKS Pod Identity — both bind a ServiceAccount to a scoped IAM role so a pod gets least-privilege, short-lived AWS credentials with no static keys.
What you do: create an IAM role per ServiceAccount that needs AWS access (S3, SQS, Secrets Manager), annotate the ServiceAccount or create a Pod Identity association, and delete mounted keys. Your in-cluster Kubernetes RBAC is unchanged — only the cloud-credential path changes.
From: Docker Hub, Harbor, Quay, GitLab Registry, or a self-hosted registry.
To: Amazon Elastic Container Registry (ECR) — private, IAM-controlled, with image scanning and lifecycle policies; in-VPC pulls stay off the public internet.
What you do: create repositories, re-tag and push images (or use ECR pull-through cache for upstream public images), update every image: reference, and grant nodes/pods ECR pull permission via their IAM role.
From: Cluster Autoscaler bound to fixed-size node groups / ASGs you sized by hand.
To: Karpenter, which watches for unschedulable pods and launches right-sized nodes (and consolidates underused ones) directly, choosing instance types and Spot/On-Demand mix for you. Keep managed node groups for a stable baseline and let Karpenter handle burst.
What you do: install Karpenter, define NodePools and EC2NodeClasses (instance families, capacity type, limits), and remove Cluster Autoscaler. This is where a lot of the EKS cost win comes from — Karpenter bin-packs and uses Spot aggressively.
From: Calico/Cilium/Flannel for pod networking and your own CoreDNS deployment.
To: the Amazon VPC CNI (pods get real VPC IPs, making security-group and flow-log integration trivial) plus CoreDNS and kube-proxy as managed add-ons; layer Cilium on top if you need its advanced policy/observability.
What you do: plan VPC IP capacity (the VPC CNI consumes ENI/IP space — prefix delegation helps on dense nodes) and port NetworkPolicies (the VPC CNI supports them natively in current versions, or run Cilium for richer policy).
This is the single biggest reason teams move, so it deserves its own section. On EKS, the work that most often breaks a self-managed cluster simply stops being your job.
etcd. On a self-managed cluster, etcd is the state of your entire world and the thing most likely to take you down — disk fills, compaction goes wrong, a quorum-losing AZ outage, a botched backup you discover is unusable only during a restore. On EKS, etcd is fully managed: multi-AZ, encrypted at rest with KMS, backed up and scaled by AWS. You never run etcdctl snapshot in anger again.
Control-plane HA and scaling. EKS runs the API server, scheduler, and controller-manager across multiple Availability Zones and scales the API server with load. You stop sizing control-plane nodes, rotating their certificates by hand, and owning their patch cadence.
Version upgrades. Kubernetes ships a minor version roughly every four months and supports each for a limited window, so "we'll upgrade later" is how clusters become unupgradeable. On a self-managed cluster a minor upgrade is a careful multi-component dance (control plane, then kubelets, then CNI/CSI/CoreDNS compatibility). On EKS you upgrade the control plane with a single action, then roll worker nodes (managed node groups make this guided, and Karpenter can recycle nodes onto the new version). EKS extended support gives you a paid runway if a workload pins you to an older version. Either way, the upgrade goes from a project to a routine.
The net effect: the high-blast-radius, low-differentiation operations move to AWS. Your team's remaining Kubernetes work is the part that relates to your applications — deployments, autoscaling policy, network policy, capacity — not keeping the cluster's own organs alive.
Stateless workloads are the easy part — re-tag images to ECR, apply manifests, done. The real work is the stateful data in PersistentVolumes and the secrets your pods consume. Here's how each moves.
Stateless workloads. For Deployments and DaemonSets the migration is: push images to ECR, update image: references and IRSA annotations, apply, and shift traffic. Helm charts and Kustomize overlays port directly — typically you only change values that referenced the old registry, StorageClass, ingress class, and IAM. This is where Velero's backup-and-restore (below) shines: it recreates these objects on EKS wholesale.
PersistentVolumes do not move between clusters by themselves; a PV points at storage in the source environment, and on EKS you need new EBS/EFS-backed volumes with the data copied in. Three approaches, by workload type:
1) Velero with restic/Kopia (file-level). Velero's file-system backup copies PV contents to S3, then restores them into freshly provisioned EBS/EFS volumes on EKS. Best for moderate-sized volumes you can quiesce briefly — and it's storage-backend-agnostic, which is exactly why it works across a self-managed→EKS boundary.
2) Shared-filesystem sync (EFS). For ReadWriteMany data, provision an EFS filesystem, mount it via the EFS CSI driver, bulk-copy with AWS DataSync (or rsync) ahead of cutover, then do a short final delta sync. Good for content/asset stores and shared scratch.
3) Application-native replication (databases). Prefer the engine's own replication over copying raw volume bytes: stand up a replica on the EKS side, or — better — move the database off the cluster onto Amazon RDS/Aurora via DMS and cut over with minimal downtime. Copying a live database's block volume risks an inconsistent snapshot; streaming replication does not. For many teams, "migrate to EKS" is also the moment to get stateful databases out of the cluster.
You can Velero-restore Kubernetes Secret objects directly, and for low-sensitivity config that's fine. But a migration is the right moment to move secrets to a managed backend: AWS Secrets Manager or SSM Parameter Store via the Secrets Store CSI Driver, so pods mount secrets at runtime through an IRSA-scoped role — no plaintext Secrets in etcd, with rotation available.
If you already use Sealed Secrets or external-secrets, point external-secrets at AWS Secrets Manager and your GitOps flow barely changes. The correctness point: re-issue anything sensitive rather than lifting base64 blobs across clusters, and confirm each consuming pod's IAM role reads exactly the secrets it needs and nothing more.
Move stateless first (reversible, builds confidence), then shared-filesystem data via pre-sync + delta, then databases last via engine-native replication or DMS to RDS/Aurora. Never cut a database over by copying a live block volume.
The lowest-risk way to move a running cluster is to treat it as a backup/restore between two clusters that briefly run in parallel — never an in-place mutation. Velero is the tool most teams use to make that practical, and it pairs naturally with a DNS/weighted cutover.
The shape of it. You run the source (self-managed) cluster and the new EKS cluster side by side. Velero, installed on both with an S3 backup store, captures namespaces — Kubernetes objects plus, optionally, PV contents via file-system backup — from the source and restores them onto EKS. Because both clusters exist at once, cutover becomes a traffic decision and rollback is "send traffic back to the old cluster," not "rebuild from scratch."
Two correctness notes from doing this for real. First, DNS TTLs are your rollback latency — lower them well before cutover so "send traffic back" takes effect in seconds, not the old 3600-second cache. Second, the EKS side must be genuinely warm before you shift meaningful traffic: pre-pulled images, Karpenter NodePools sized for the load, HPAs configured, and a real load test against the ALB. A cold cluster that scales from zero under production traffic is how a "low-risk" cutover becomes an incident.
1) Stand up the target. Build the EKS cluster and landing zone as Infrastructure-as-Code: VPC, control plane, managed add-ons (VPC CNI, CoreDNS, EBS/EFS CSI), AWS Load Balancer Controller, Karpenter, ECR repos, IRSA roles.
2) Install Velero on both clusters pointed at the same S3 bucket; confirm a test restore actually round-trips before you trust it.
3) Backup + restore non-prod first. Velero-restore a staging namespace onto EKS, fix the integration deltas (StorageClass, ingress class, registry, IAM), and validate end to end.
4) Pre-sync stateful data. Seed the EKS side ahead of time — Velero file-system backup for PV contents, DataSync for EFS, native replication for databases — so cutover needs only a small final delta.
5) Run parallel where it helps. For services that tolerate it, dual-write or replicate so the EKS side stays warm and current.
6) Cut traffic over gradually. Use Route 53 weighted records (or your global load balancer / API gateway) to shift a slice of traffic to the EKS ALB/NLB, watch error rates and latency, then ramp to 100%. For a hard cutover, take a maintenance window, do the final delta sync, flip DNS, and verify.
7) Keep the old cluster as rollback until the EKS side has proven itself across a full traffic cycle, peak included. Only then decommission.
Plain Kubernetes ports cleanly. The further your source sits from vanilla upstream, the more distro-specific constructs you have to translate. OpenShift is the biggest lift because much of it is non-portable by design.
Across all three, one rule holds: don't adopt new platform components mid-migration. Bring a GitOps controller (Argo CD or Flux) to apply your manifests and a service mesh only if you already depend on one — migrate like-for-like first, modernize second. That discipline is what keeps the cutover boring.
The cleanest source. Your manifests are already standard Kubernetes; the work is purely the Section II integration remap (storage, LB, IAM, ECR, Karpenter, CNI). If you used Calico/Cilium, decide whether to adopt the VPC CNI or run Cilium on EKS. This is the fastest profile to migrate.
Workloads are standard Kubernetes and port directly. What you replace is the Rancher management layer: Rancher Projects map to namespaces + RBAC; catalog apps become Helm releases; Rancher Fleet maps cleanly to Argo CD or Flux on EKS. EKS doesn't bring a Rancher-style multi-cluster UI — if you relied on it, plan for Argo CD/Flux + the EKS console + (optionally) a fleet manager. The cluster contents themselves are easy.
The heaviest migration, because OpenShift adds proprietary constructs on top of Kubernetes. Translate: Routes → Ingress (ALB); DeploymentConfigs → Deployments; ImageStreams + internal registry → ECR; BuildConfigs/S2I → a normal CI pipeline (CodeBuild/GitHub Actions to ECR); SecurityContextConstraints → Pod Security Standards; OpenShift OAuth → IAM/OIDC + RBAC. Workloads that assumed OpenShift's restricted SCC (e.g. arbitrary UID handling) may need securityContext changes. Budget materially more time, and consider whether ROSA (Red Hat OpenShift Service on AWS) fits better than EKS if you want to keep OpenShift semantics.
Everything above is the real work. The reason to route it through CloudRoute rather than absorb it into your roadmap is funding and de-risking: AWS will often pay for most of the migration, and a partner who has done dozens of EKS cutovers runs it.
CloudRoute routes companies to vetted AWS partners who run the migration for you — landing zone, EKS cluster build as Infrastructure-as-Code, the Section II integration remap, the Velero backup-restore, cutover, and rollback. You stay in control of timing and acceptance; the partner does the heavy lifting and carries the playbook for the gotchas (PV data movement, OpenShift translation, warm-cluster cutover).
The funding mechanism is the AWS Migration Acceleration Program (MAP), which runs in three phases — Assess (a TCO and readiness review, frequently free), Mobilize (landing zone + a pilot workload), and Migrate & Modernize (production cutover). AWS provides funding and credits scaled to the migration size, and on a partner-led engagement the partner is paid through MAP — so for a qualifying migration the work lands at little-to-no cost to you.
The honest framing: MAP funding applies to qualifying migrations — typically a meaningful committed post-migration AWS spend (your EC2, EKS, EBS, data-transfer, and any RDS/Bedrock usage). If your migration is too small to qualify, CloudRoute still routes you to a vetted partner who de-risks the cutover; you just don't get the AWS-funded discount. We tell you which bucket you're in during the assessment, not after.
Because MAP is an AWS funding program, the EKS migration ties directly into the AWS credits world. For the funding mechanics in depth, see the credits cluster (the $100K AWS credits path and how AWS POC funding works); for the platform you'll land on, the DevOps cluster (the AWS landing zone and AWS DevOps practices). The migration persona detail lives at /for/migration.
On a qualifying migration, AWS MAP credits a large share of the cost and the partner is paid through MAP — so you migrate at little-to-no cost. No qualifying spend? You still get a vetted partner who de-risks the cutover, just without the AWS-funded discount.
The decision is rarely about features — both run the same Kubernetes API. It's about who carries the operational burden, what the all-in cost looks like, and how much effort each layer takes. Representative for a mid-sized production cluster as of 2026; your numbers will vary.
| Dimension | Self-managed K8s (kubeadm / Rancher / OpenShift) | Amazon EKS |
|---|---|---|
| Control plane | You run + scale API server, scheduler, controllers across AZs | AWS-managed, multi-AZ, auto-scaled |
| etcd | You own backups, compaction, disk, quorum, restores | Fully managed, encrypted at rest (KMS) |
| Version upgrades | Manual multi-component project every few months; risk of falling behind | One-action control-plane upgrade + guided node roll; extended support available |
| Control-plane cost | Cost of the control-plane nodes you run (often 3+ instances) + your time | Flat hourly per-cluster fee (no control-plane nodes to run) |
| Worker nodes | You manage instances + an autoscaler you tuned | Managed node groups + Karpenter (bin-packed, Spot-aware) |
| Storage integration | Self-managed CSI (Ceph/NFS/vendor) you operate | EBS/EFS CSI as managed add-ons |
| Load balancing | In-cluster NGINX/Traefik/MetalLB or Routes you maintain | AWS Load Balancer Controller → ALB/NLB (AWS-managed) |
| Cloud identity | Node IAM roles or mounted static keys | IRSA / Pod Identity — scoped, keyless, short-lived |
| On-call blast radius | Highest layer (control plane/etcd) is yours | Highest layer is AWS's; you own apps + nodes + add-ons |
| Migration effort to get here | n/a (already running) | Mostly integration remap + data movement; weeks, not a rewrite |
Situation: Four self-managed Kubernetes clusters (Rancher/RKE2) running ~120 microservices plus a Postgres and a Kafka in-cluster. Platform team of three was spending roughly a third of its time on etcd incidents, node-image upgrades, and a perpetually-deferred Kubernetes version bump that had left two clusters two minors behind. Colo hardware refresh was due, which forced the build-vs-move decision. Wanted out of control-plane ops without rewriting 120 services, and wanted the databases off the clusters.
What CloudRoute did: CloudRoute routed within 24 hours to an EU-Central AWS partner (Advanced tier, container + MAP track record). MAP Assess (free) sized the workloads and projected post-migration spend; it qualified, so Mobilize → Migrate ran funded through MAP. The partner built the EKS landing zone as Terraform (VPC CNI, EBS/EFS CSI, AWS Load Balancer Controller behind a retained NGINX ingress for like-for-like routing, Karpenter, ECR, IRSA, Argo CD). Stateless services moved via Velero backup-restore cluster by cluster; PV data via Velero file-system backup; Postgres moved off-cluster to Aurora PostgreSQL via DMS and Kafka to MSK. Cutover was Route 53 weighted, ramped over a week per cluster with the old clusters kept warm for rollback.
Outcome: All four clusters consolidated onto two EKS clusters (prod + non-prod) over 9 weeks. Control-plane/etcd on-call eliminated; the platform team's Kubernetes time dropped to roughly a tenth of before. Databases now off-cluster on Aurora + MSK. MAP funded ~50% of the migration and the partner was paid through MAP — net cost to the customer was effectively $0. The two minor-version-behind clusters became a non-issue: EKS upgrades are now a routine action.
engagement window: 9 weeks · clusters: 4 → 2 · databases moved off-cluster · MAP-funded ≈50% · migration cost to customer: ≈$0
CloudRoute routes you to a vetted AWS partner who builds the EKS landing zone, runs the Velero backup-restore cutover, and carries the rollback plan. On a qualifying migration, AWS MAP funds the work — often at little-to-no cost to you.