Fargate vs Cloud Run vs Azure Container Instances
Compare serverless container platforms across AWS, GCP, and Azure. Learn pricing models, scaling behavior, and when to use each platform for your containerized workloads.
Running containers without managing servers is the sweet spot of modern cloud infrastructure. AWS Fargate, Google Cloud Run, and Azure Container Instances each promise this — but they differ significantly in execution model, pricing, and capabilities. Let’s break them down.
Quick Comparison
| Feature | AWS Fargate | Google Cloud Run | Azure Container Instances |
|---|---|---|---|
| Execution Model | Task/Service | Request-driven | Container Group |
| Min instances | 0 (with caveats) | 0 | 1 |
| Max timeout | Unlimited | 60 min | Unlimited |
| GPU support | No | Yes | Yes |
| VPC integration | Native | Serverless VPC | VNet injection |
| Pricing | Per vCPU-hour + memory | Per request + CPU/memory | Per second (vCPU + memory) |
AWS Fargate
Fargate runs containers as ECS tasks or EKS pods without EC2 instances to manage.
Basic Task Definition
{
"family": "my-service",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "512",
"memory": "1024",
"executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
"containerDefinitions": [
{
"name": "app",
"image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latest",
"portMappings": [
{
"containerPort": 8080,
"protocol": "tcp"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/my-service",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "ecs"
}
},
"environment": [
{ "name": "NODE_ENV", "value": "production" }
]
}
]
}
Terraform Deployment
resource "aws_ecs_cluster" "main" {
name = "my-cluster"
setting {
name = "containerInsights"
value = "enabled"
}
}
resource "aws_ecs_service" "api" {
name = "api-service"
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.api.arn
desired_count = 2
launch_type = "FARGATE"
network_configuration {
subnets = var.private_subnet_ids
security_groups = [aws_security_group.ecs.id]
assign_public_ip = false
}
load_balancer {
target_group_arn = aws_lb_target_group.api.arn
container_name = "app"
container_port = 8080
}
deployment_circuit_breaker {
enable = true
rollback = true
}
}
resource "aws_appautoscaling_target" "ecs" {
max_capacity = 10
min_capacity = 2
resource_id = "service/${aws_ecs_cluster.main.name}/${aws_ecs_service.api.name}"
scalable_dimension = "ecs:service:DesiredCount"
service_namespace = "ecs"
}
resource "aws_appautoscaling_policy" "cpu" {
name = "cpu-autoscaling"
policy_type = "TargetTrackingScaling"
resource_id = aws_appautoscaling_target.ecs.resource_id
scalable_dimension = aws_appautoscaling_target.ecs.scalable_dimension
service_namespace = aws_appautoscaling_target.ecs.service_namespace
target_tracking_scaling_policy_configuration {
predefined_metric_specification {
predefined_metric_type = "ECSServiceAverageCPUUtilization"
}
target_value = 70.0
}
}
Fargate Pros & Cons
Pros:
- Deep AWS integration (IAM, VPC, CloudWatch)
- Spot pricing available (up to 70% savings)
- Long-running tasks supported
- EKS integration for Kubernetes workloads
Cons:
- No scale-to-zero for services
- Higher baseline cost than Cloud Run
- Complex networking setup
- Limited to AWS ecosystem
Google Cloud Run
Cloud Run is truly serverless — scales to zero and bills per request.
Deploying a Service
# Build and push to Artifact Registry
gcloud builds submit --tag gcr.io/my-project/my-app
# Deploy to Cloud Run
gcloud run deploy my-app \
--image gcr.io/my-project/my-app \
--platform managed \
--region us-central1 \
--allow-unauthenticated \
--memory 512Mi \
--cpu 1 \
--min-instances 0 \
--max-instances 100 \
--concurrency 80 \
--timeout 300
Terraform Deployment
resource "google_cloud_run_v2_service" "api" {
name = "api-service"
location = "us-central1"
template {
scaling {
min_instance_count = 0
max_instance_count = 100
}
containers {
image = "gcr.io/${var.project_id}/my-app:latest"
ports {
container_port = 8080
}
resources {
limits = {
cpu = "1"
memory = "512Mi"
}
cpu_idle = true # Scale to zero
}
env {
name = "NODE_ENV"
value = "production"
}
env {
name = "DB_PASSWORD"
value_source {
secret_key_ref {
secret = google_secret_manager_secret.db_password.secret_id
version = "latest"
}
}
}
startup_probe {
http_get {
path = "/health"
}
initial_delay_seconds = 0
period_seconds = 10
failure_threshold = 3
}
}
vpc_access {
connector = google_vpc_access_connector.main.id
egress = "PRIVATE_RANGES_ONLY"
}
}
traffic {
type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST"
percent = 100
}
}
resource "google_cloud_run_service_iam_member" "public" {
service = google_cloud_run_v2_service.api.name
location = google_cloud_run_v2_service.api.location
role = "roles/run.invoker"
member = "allUsers"
}
Cloud Run Jobs (Batch Workloads)
resource "google_cloud_run_v2_job" "processor" {
name = "data-processor"
location = "us-central1"
template {
template {
containers {
image = "gcr.io/${var.project_id}/processor:latest"
resources {
limits = {
cpu = "2"
memory = "4Gi"
}
}
}
timeout = "3600s"
max_retries = 3
}
parallelism = 10
task_count = 100
}
}
Cloud Run Pros & Cons
Pros:
- True scale-to-zero
- Pay only for actual requests
- Simple deployment model
- GPU support for ML workloads
- Generous free tier
Cons:
- 60-minute max timeout
- Stateless only
- Limited CPU/memory combinations
- Cold start latency
Azure Container Instances
ACI provides the simplest container deployment — no orchestration needed.
CLI Deployment
# Create container group
az container create \
--resource-group my-rg \
--name my-container \
--image myregistry.azurecr.io/my-app:latest \
--cpu 1 \
--memory 1.5 \
--registry-login-server myregistry.azurecr.io \
--registry-username $ACR_USER \
--registry-password $ACR_PASS \
--ports 80 \
--dns-name-label my-app \
--environment-variables NODE_ENV=production
Terraform Deployment
resource "azurerm_container_group" "api" {
name = "api-container"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
os_type = "Linux"
ip_address_type = "Private"
subnet_ids = [azurerm_subnet.aci.id]
container {
name = "app"
image = "${azurerm_container_registry.main.login_server}/my-app:latest"
cpu = "1"
memory = "1.5"
ports {
port = 8080
protocol = "TCP"
}
environment_variables = {
NODE_ENV = "production"
}
secure_environment_variables = {
DB_PASSWORD = var.db_password
}
liveness_probe {
http_get {
path = "/health"
port = 8080
scheme = "Http"
}
initial_delay_seconds = 30
period_seconds = 10
}
}
container {
name = "sidecar"
image = "nginx:alpine"
cpu = "0.5"
memory = "0.5"
ports {
port = 80
protocol = "TCP"
}
}
image_registry_credential {
server = azurerm_container_registry.main.login_server
username = azurerm_container_registry.main.admin_username
password = azurerm_container_registry.main.admin_password
}
diagnostics {
log_analytics {
workspace_id = azurerm_log_analytics_workspace.main.workspace_id
workspace_key = azurerm_log_analytics_workspace.main.primary_shared_key
}
}
tags = var.tags
}
ACI with GPU
resource "azurerm_container_group" "gpu" {
name = "ml-inference"
location = "eastus"
resource_group_name = azurerm_resource_group.main.name
os_type = "Linux"
sku = "Standard"
container {
name = "inference"
image = "myregistry.azurecr.io/ml-model:latest"
cpu = "4"
memory = "16"
gpu {
count = 1
sku = "K80"
}
ports {
port = 8080
protocol = "TCP"
}
}
}
ACI Pros & Cons
Pros:
- Simplest deployment model
- GPU support with multiple SKUs
- Sidecar containers supported
- VNet integration
- Per-second billing
Cons:
- No built-in autoscaling
- Always running (no scale to zero)
- Limited orchestration features
- Best for simple workloads
Pricing Comparison
Example: 2 vCPU, 4GB RAM, running 24/7
AWS Fargate (us-east-1):
- vCPU: $0.04048/hour × 2 × 730 hours = $59.10
- Memory: $0.004445/GB/hour × 4 × 730 = $12.98
- Total: ~$72/month
Google Cloud Run (us-central1):
- CPU: $0.00002400/vCPU-second × 2 × 2,628,000 = $126.14
- Memory: $0.00000250/GiB-second × 4 × 2,628,000 = $26.28
- Total: ~$152/month (but scales to $0 when idle!)
Azure Container Instances (East US):
- vCPU: $0.0000125/second × 2 × 2,628,000 = $65.70
- Memory: $0.0000125/GB/second × 4 × 2,628,000 = $131.40
- Total: ~$197/month
Cost Winner by Use Case
| Scenario | Best Choice |
|---|---|
| Always-on service | Fargate (especially Spot) |
| Bursty traffic | Cloud Run |
| Batch jobs | Cloud Run Jobs |
| Simple deployment | ACI |
| GPU workloads | Cloud Run or ACI |
Decision Framework
Choose AWS Fargate when:
- You’re already in AWS
- Need long-running services
- Want Spot pricing
- Need deep VPC integration
Choose Google Cloud Run when:
- Traffic is variable/bursty
- You want true scale-to-zero
- Simplicity is paramount
- Cost optimization is critical
Choose Azure Container Instances when:
- Quick proof-of-concept
- GPU workloads in Azure
- Simple, single-container apps
- Already using Azure
Key Takeaways
- Cloud Run wins on simplicity — deploy with one command, scale to zero
- Fargate wins on features — best AWS integration, Spot pricing
- ACI wins on GPU availability — multiple SKUs, easy setup
- Consider hybrid — use the right tool for each workload
- Don’t forget hidden costs — load balancers, networking, logging
“The best serverless container platform is the one your team can deploy without a three-day training course.”