All posts

AWS vs Google Cloud vs Azure compute: choosing VMs, containers, and serverless

· 10 min read

Compare EC2, Compute Engine, Azure VMs, ECS on Fargate, Cloud Run, Container Apps, EKS, GKE, and AKS by control, startup latency, scaling, database connections, and cost. Use an order API to decide which responsibilities to delegate and what to test.

Start with the order API and the work you want to delegate

An order API already runs in a container and receives more traffic during the day than at night. It is stateless and stores orders in an external PostgreSQL database. If the team wants less OS and cluster maintenance, managed container execution is a useful starting point. Requirements for a custom Kubernetes Operator or guest OS changes move the comparison to another level.

Map VMs, Kubernetes, and managed containers before comparing

Required controlAWSGoogle CloudAzure
VM with guest OS administrationAmazon EC2Compute EngineAzure Virtual Machines
Kubernetes APIs and resourcesAmazon EKSGoogle Kubernetes Engine (GKE)Azure Kubernetes Service (AKS)
Container execution without node administrationAmazon ECS on AWS FargateCloud RunAzure Container Apps
Event-triggered functionsAWS LambdaCloud Run functionsAzure Functions

The table starts the investigation. Fargate provides container compute; the row uses it with ECS. Cloud Run and Container Apps also provide application ingress and execution modes. The serverless label alone does not establish equivalent HTTP exposure or recovery from zero instances.

Delegation also varies within Kubernetes. EKS Standard versus Auto Mode and GKE Standard versus Autopilot change node responsibilities and constraints. Check ownership of application permissions, resource settings, releases, and monitoring in every mode. A shared container image does not make IAM and networking portable without changes.

Compare ECS on Fargate, Cloud Run, and Container Apps

CandidateSelection-relevant featuresValidate before adoption
ECS on FargateRun tasks with specified CPU, memory, networking, and IAMLoad balancer for the public API, service scaling, startup time
Cloud RunHTTPS ingress and request-based service scaling; separate execution modes include jobsService, job, or worker pool; concurrent requests and CPU allocation mode
Container AppsKEDA-based scaling using HTTP or queues, revisions, and jobsSelected scaling rules, minimum replicas, environment networking, and plan

Run the actual order API container on each candidate with equivalent authentication, timeouts, and dependencies. Evaluate a suitable execution mode separately if continuous background work or long batches are added. Container Apps uses Kubernetes internally but does not expose the Kubernetes API directly. Compare AKS or another Kubernetes service when that control is required.

For sparse traffic and bursts, examine cold starts and scaling delay

With a configuration that scales to zero at night, the first request may wait for startup. Keeping execution environments ready reduces this wait but retains capacity costs. When comparing Cloud Run minimum instances and Container Apps minimum replicas, determine how much capacity is ready and what happens when demand exceeds it.

Set scaling limits together with the database connection budget

Assume two processes per instance and a database pool limit of 10 per process. Twenty instances can open 20 × 2 × 10 = 400 connections; 50 can open 1,000. These are aggregate configuration limits if the pools fill, not measurements of active connections or throughput.

Illustrative connection limits: 2 processes/instance × 10 connections/process; deployment adds 10 instances to the normal 20
  • Normal: 20 instances: 400 connections
  • Deploy: 30 instances: 600 connections
  • Scaled: 50 instances: 1,000 connections

If the database allocates 500 connections to the application, normal operation fits but deployment does not. Sum old and new revisions and all services; with a proxy, count client-side and database-side connections separately. Combine pool limits, global concurrency control, and bounded waits instead of relying solely on a maximum instance setting.

Compare costs across both idle periods and continuous utilization

Workload characteristicCosts to includeWhat changes the decision
Sparse, highly variable trafficActive compute, requests, minimum capacityCan latency targets be met without warm capacity?
High utilization all dayContinuous capacity, commitments, operations laborDoes the option remain attractive with headroom and maintenance included?
Private networking and heavy communicationLoad balancing, NAT or other paths, transfer, logsDo surrounding services change the total for equivalent CPU?

Align region requirements, runtime, HA, transfer volume, and log retention in each estimate. Container compute prices alone do not establish the cheapest system. For this API, maintenance time saved is a valid reason to adopt managed execution if requirements are met. A team already operating Kubernetes effectively and using its specific capabilities may reach another conclusion.

Validate the candidate and record a conditional decision

  1. Use the real container to verify public and private access, application authorization, and required protocols. Check for dependencies on durable local state.
  2. Reproduce sparse traffic, bursts, and deployments. Measure startup, errors, latency, and database connection waits together.
  3. Vary minimum capacity and scaling limits, then estimate the cost of configurations that meet latency and database capacity requirements.
  4. Record the reasoning: this HTTP API fits the execution contract, and tests establish latency and connection behavior. Reevaluate if Kubernetes-specific control becomes necessary.

Primary sources for product scope and settings

Tips this post digs into