Containers and serverless
Containers and serverless are not competing religions. They are cost and control trade-offs that suit different workload shapes, and most estates end up with both.
The standard. A method to evaluate, design and operate containerized and serverless architectures against the workload's actual requirements.
Evaluation criteria
| Factor | Question |
|---|---|
| Workload characteristics | Is the workload long-running, bursty, event-driven, or stateful? |
| Scalability | Does traffic spike predictably, seasonally, or unpredictably? |
| Resource patterns | Is the workload CPU-bound, memory-bound, or mostly idle? |
| Operational pain | What is the current pain — deployment time, scaling, availability, cost? |
| Team capability | Can the team operate an orchestrator, or does a managed runtime fit better? |
| Data and state | Is state externalised, or does the process depend on local disk? |
| Compliance | Are there requirements about runtime control, patching, or isolation? |
Decision matrix
| Criteria | Containers (ECS / EKS) | Serverless (Lambda, Step Functions, Fargate) |
|---|---|---|
| Application type | Long-running processes, microservices, stateful applications | Event-driven, short-lived, stateless |
| Scaling | Complex scaling, manual or automated configuration | Automatic, event-driven |
| Infrastructure control | Full control over runtime, OS and dependencies | Minimal; AWS manages runtime and scaling |
| Startup time | Slower; depends on image size and orchestration | Fast; cold starts are the exception |
| Cost model | Pay for allocated compute, including idle | Pay per invocation and duration |
| Complexity | Orchestration, networking, container lifecycle | No servers or containers to manage |
| Languages | Anything the container runtime supports | Lambda-supported runtimes or custom runtimes; Fargate supports any |
| Integration | Good for legacy systems and custom middleware | Ideal for S3, DynamoDB, API Gateway, EventBridge |
| Execution duration | Unbounded | 15 minutes per invocation |
| State | Suitable for stateful workloads with persistent storage | Stateless; external state required |
| Event-driven | Possible, with explicit configuration | Native |
| Vendor lock-in | Lower; containers are portable | Higher; tightly integrated with AWS |
| Hybrid / on-premises | ECS Anywhere, EKS Anywhere | Not practical |
| Security model | Explicit IAM, network policy, image controls | AWS shared-responsibility runtime controls |
| Latency | Predictable with tuning | Cold starts can add latency |
| Best-fit examples | Real-time applications, ML models, legacy migration, microservices | API backends, file processing, IoT events, data pipelines |
Choosing
Choose containers when:
- The application needs full control of the runtime or the operating system.
- It is stateful, or has long-running processes and background workers.
- It is a legacy application being migrated with minimal change.
- Consistent, predictable latency matters more than scale-to-zero.
- The team already operates an orchestrator.
Choose serverless when:
- The workload is event-driven or has unpredictable, intermittent traffic.
- Operational overhead should be minimal.
- The application is stateless with short-lived execution.
- The workload integrates natively with S3, DynamoDB, API Gateway or EventBridge.
- Scale-to-zero matters for cost.
Choose a hybrid when:
- A steady-state core serves most traffic, and event-driven side work handles peaks.
- The team wants serverless for new features without re-platforming the existing service.
- Workloads have different compliance or isolation requirements within one product.
Container patterns
ECS on Fargate
Managed orchestration without managing nodes. The default for most containerized web services.
- A cluster per environment.
- One service per application component, with its own task definition.
- ALB target groups per service, health-checked.
- Task roles scoped to the resources the service uses.
- Service Connect or Cloud Map for service-to-service discovery.
EKS
For teams that need Kubernetes APIs, a wider ecosystem, or multi-tenant cluster isolation.
- Managed node groups or Fargate profiles.
- Namespace per team, with resource quotas and network policies.
- IRSA for pod-level AWS permissions.
- Cluster autoscaler or Karpenter for node capacity.
- GitOps delivery where the team is already fluent.
Common container controls
- Images from a private registry, immutable tags, scanned in the pipeline.
- Non-root user, read-only root filesystem where possible.
- Resource requests and limits set — no unbounded container.
- Secrets from Secrets Manager or Parameter Store, injected at runtime.
- Logging to CloudWatch; tracing via X-Ray or OpenTelemetry.
- No shell access to production containers; debug through ephemeral containers with an audited role.
Serverless patterns
API backend
API Gateway → Lambda → DynamoDB
↓
EventBridge → downstream consumers
- One function per bounded responsibility, not one function per endpoint.
- Idempotency keys for write paths.
- Reserved concurrency for critical functions; provisioned concurrency where cold starts breach latency targets.
- Structured logging with a correlation id.
Event processing
S3 event → Lambda → SQS → Lambda (batch) → DynamoDB
↓ DLQ
- Dead-letter queues on every asynchronous path.
- Visibly handle retries; Lambda retries twice by default, then drops unless a DLQ exists.
- Batch size and window tuned to cost and latency.
Long-running workflow
API → Step Functions → Lambda / ECS task / manual approval
Use Step Functions when the process has multiple steps, waits, retries or human approval — not a chain of Lambdas calling each other.
Cost considerations
| Workload shape | Containers | Serverless |
|---|---|---|
| Steady 24×7 traffic | Lower — reserved capacity amortises | Higher at sustained volume |
| Bursty traffic with idle periods | Higher — pays for idle | Lower — scale to zero |
| Very high volume, predictable | Lower | Higher per-request |
| Very low volume | Higher — minimum capacity | Lower |
| Long-running jobs | Lower | Higher, and may hit the 15-minute limit |
Serverless is not automatically cheaper. At sustained load, a right-sized container service usually costs less; at intermittent load, scale-to-zero usually wins. The cost visibility practice exists so this is measured rather than assumed.