Why we abandoned Kubernetes for raw EC2

A controversial but necessary move that saved our client $2M annually and reduced deployment complexity by an order of magnitude.
There's an industry-wide obsession with Kubernetes. It's become the default answer to every infrastructure question, regardless of whether the scale of the problem actually warrants the complexity of the solution. We're not anti-Kubernetes; most of our engagements involve running it well. This is the story of the minority case where the right call was to walk away from it entirely.
The client was a fast-growing fintech processing payment reconciliation batches. Their entire production footprint was 5 stateless Go binaries and a Postgres instance. Nothing about the workload was bursty, nothing needed horizontal pod autoscaling reacting in seconds, and nothing benefited from a service mesh; at the time, there were exactly two services that talked to each other.
What they had instead was a 40-node EKS cluster, three ingress controllers installed at different points in the company's history by different engineers who'd each read a different blog post, a Helm chart per service with enough templated `values.yaml` overrides that nobody could predict what a `helm upgrade` would actually change, and a platform team of 2.5 FTEs whose entire job was keeping the cluster itself alive. We measured it directly: 40% of engineering cycles for the infra-adjacent team went to cluster maintenance, node group upgrades, CNI plugin compatibility issues, cert-manager renewal failures, and debugging why a pod was stuck in `CrashLoopBackOff` for reasons unrelated to the application.
We didn't do this migration blind. Before touching production, we ran a two-week assessment scoring the workload against the conditions that actually justify Kubernetes: does deployment frequency or team count require self-service multi-tenancy, does the traffic pattern need sub-minute autoscaling, is there a real need for the ecosystem (operators, service mesh, GitOps at scale)? The answer was no on every count. This was a team of 6 engineers who owned every service, deploying maybe 3 times a day, on a workload with a traffic curve so predictable it barely needed autoscaling at all.
The migration itself: Packer built immutable AMIs baking in the application binary and its runtime dependencies, so no configuration drift was possible because there was no live configuration to drift. Ansible handled the remaining host-level bootstrapping (log shipping agent, monitoring agent, nothing else). Deployment became: build AMI, roll a new Auto Scaling Group launch template, trigger an instance refresh with a health-check-gated rolling replacement. No Helm, no ingress controller; an Application Load Balancer with target groups per service did the job three ingress controllers had been fighting each other over.
We kept this simple on purpose and it's worth naming what we deliberately gave up: no self-service deploys for a hypothetical future team of 50 engineers, no built-in service mesh for a hypothetical future of 30 microservices, no operator ecosystem. If any of those become real, EC2 with ASGs stops being the right answer. This isn't a 'Kubernetes is bad' post, it's a 'we sized the tool to the actual system' post.
Results, measured over the following two quarters: deployment time dropped from 45 minutes (a full Helm release cycle plus rollout verification) to under 3 minutes (an ASG instance refresh with health check gating). Infrastructure cost dropped by roughly $2M annually. A meaningful chunk of that was the 40-node cluster's control plane and over-provisioned node groups sized for headroom the workload never used, and the rest was reclaiming the platform team's time, which we costed against their fully-loaded salary. Incident volume attributable to the platform itself (not the application) dropped to effectively zero, because there was no longer a complex orchestration layer to have opinions about.
The generalizable point isn't 'EC2 beats Kubernetes.' It's that Kubernetes' value proposition, self-service, dynamic scheduling, a large operator ecosystem, has a fixed cost that only pays off past a certain team size, deployment frequency, and topology complexity. Below that line, you're paying platform-team salary to operate infrastructure complexity your actual workload doesn't need. Size the tool to the system you have, not the system a conference talk assumes you'll eventually have. If you're weighing a similar build-vs-simplify call, that's exactly the kind of decision our cloud migration and modernization work is built around.
Stop guessing.
Start shipping.
Thirty minutes with a senior engineer. No sales deck, no junior SDRs. Just a technical conversation about what's actually breaking or slowing you down.