Cloud Tech by Victor
DevOpsIntermediate

AWS Compute

How EC2, Lambda, ECS, and EKS trade control for convenience differently, and how to actually choose between them instead of defaulting to whichever one you already know.

Updated 2026-07-243 min read

Overview

AWS compute spans the same control-versus-convenience spectrum every cloud provider offers: EC2 gives full OS-level control as plain virtual machines, Lambda gives fully serverless, event-driven functions with no server to manage at all, and ECS/EKS give managed container orchestration, AWS's own native model or a real managed Kubernetes control plane, respectively. Picking between them is a workload-fit decision: a short-lived, event-driven task is usually a worse fit for a hand-managed EC2 fleet than for Lambda, while a workload needing custom OS-level tuning, unsupported dependencies, or execution beyond Lambda's 15-minute ceiling genuinely needs EC2 regardless of how "modern" the alternatives look.

Quick Reference

ServiceModelYou manageBest fit
EC2IaaSOS, runtime, scaling, patchingCustom OS/runtime needs, full control, long-running processes
LambdaServerless / FaaSFunction code onlyEvent-driven, short-lived work (≤15 min per invocation)
ECSManaged orchestration (AWS-native)Task definitions, container imagesContainerized workloads without adopting Kubernetes
EKSManaged KubernetesNodes/workload compute unless using Fargate or EKS Auto Mode (control plane billed separately)Kubernetes-based orchestration, portability, ecosystem

Syntax

bash
# Lambda - deploy a function without managing any server
aws lambda create-function \
  --function-name process-orders \
  --runtime nodejs20.x --handler index.handler \
  --role arn:aws:iam::111122223333:role/lambda-orders-exec \
  --zip-file fileb://function.zip
bash
# ECS - run a task definition on serverless Fargate capacity,
# no EC2 instances to patch or scale for this workload.
aws ecs run-task \
  --cluster app-cluster --launch-type FARGATE \
  --task-definition orders-api:3

Examples

bash
# EC2 Auto Scaling Group - scale on a custom CloudWatch metric
# (queue depth), not just CPU, when that's the real bottleneck.
aws autoscaling put-scaling-policy \
  --auto-scaling-group-name orders-worker-asg \
  --policy-type TargetTrackingScaling \
  --target-tracking-configuration file://queue-depth-target.json

Start with the most managed option that fits

Default to Lambda or ECS/EKS for new workloads, and drop to plain EC2 only when you hit a specific, genuine requirement it can't satisfy, not as a default starting point.

Visual Diagram

Common Mistakes

  • Defaulting to EC2 out of familiarity for an event-driven, short-lived workload that Lambda would handle with far less operational burden.
  • Choosing EKS for a simple containerized workload without a real need for Kubernetes portability, then paying its per-cluster control-plane fee on top of the added operational surface.
  • Not accounting for Lambda's 15-minute execution ceiling and cold-start latency when picking it for a long-running or strictly latency-sensitive workload.
  • Scaling an EC2 Auto Scaling Group on CPU alone when the actual bottleneck is queue depth, memory, or a downstream dependency, leaving the workload effectively under-provisioned despite autoscaling being "on."

Performance

  • Lambda cold starts add real latency on infrequently-invoked functions; provisioned concurrency removes this at an added, standing cost.
  • ECS and EKS worker-node performance is standard EC2 instance performance unless the workload runs on Fargate or, for EKS, EKS Auto Mode, in which case AWS manages that compute; instance-type and sizing choices matter exactly as much as they would running EC2 directly.
  • Auto Scaling Group scale-out has real instance warm-up time; very spiky traffic may need a lower scale-out threshold or pre-warmed capacity to stay ahead of demand.

Best Practices

  • Choose compute by execution model first, event-driven and short-lived → Lambda, containerized → ECS/EKS, needs OS-level control or long-running state → EC2, rather than by habit.
  • Use EKS specifically when Kubernetes's API and ecosystem portability matter; use ECS when a simpler, AWS-native model is enough.
  • Scale on the metric (including custom CloudWatch metrics) that actually reflects the workload's bottleneck, not CPU by default.
  • Revisit the compute choice as a workload matures; constraints that justified EC2 early on may no longer apply once the workload's shape is well understood.

Interview questions

When would you choose AWS Lambda over EC2 for a workload?

Lambda fits event-driven, short-lived work, an API request, a file landing in S3, a queue message, where you want to pay only for actual invocation time and never manage a server at all; a function can run for at most 15 minutes and has no state between invocations. EC2 fits workloads that need to run continuously, need OS-level control, exceed Lambda's execution-time or memory ceiling, or need to retain in-process state between requests. The decision is about execution model and constraints, not maturity, a long-running stateful service is a worse fit for Lambda regardless of how "serverless-first" a team wants to be.

What is the difference between ECS and EKS?

Both are managed container orchestrators, but ECS is AWS's own native orchestration model (task definitions, services, clusters) with no separate control-plane fee, while EKS runs an actual, standard, upstream Kubernetes control plane that AWS manages for you, and Amazon EKS charges a per-cluster fee specifically for that managed control plane, on top of whatever compute the worker nodes cost. Both can run workloads on EC2 instances you manage, or offload node/workload compute to AWS via Fargate or, on EKS specifically, EKS Auto Mode, so "serverless containers" is available either way; the real choice is whether you want Kubernetes's API and ecosystem (EKS) or a simpler, AWS-native model with less portability (ECS).

What does an EC2 Auto Scaling Group actually manage, and why does the scaling metric choice matter?

An Auto Scaling Group keeps a fleet of EC2 instances at a desired size, launching or terminating instances automatically based on configured scaling policies, and replacing instances that fail health checks, so nobody is manually adding or removing servers as load changes. The scaling metric determines whether that automation actually tracks the real bottleneck: scaling purely on CPU utilization looks like "autoscaling is working" on a dashboard while a memory-bound or queue-depth-bound workload keeps falling behind, because the metric driving the scaling policy never reflected the actual constraint. Choosing a metric (or combination of metrics, including custom CloudWatch metrics) that matches the workload's real bottleneck is what makes the automation actually correct rather than just present.

References

ShareXLinkedInReddit
Was this page helpful?
Suggest an improvement