← Back

Evaluating serverless Container-as-a-Service platforms: Knative, Cloud Run and AWS Fargate

20/01/2022 · 9 min

Serverless became popular through Function-as-a-Service, but the function programming model constrains running general-purpose applications. Platforms implementing Container-as-a-Service (CaaS) deliver software as container images: they ease migration of traditional applications, give control over the runtime, remove hard execution-time limits and reduce lock-in. The dissertation evaluates these platforms on two fronts — qualitative and quantitative.

Source code and reproduction scripts on GitHubnewtonisaac/master-lab ↗

Qualitative evaluation

Seven platforms were characterised against execution criteria (memory, CPU, storage, GPU, execution time limit, concurrent executions), scalability (autoscaling, autoscaling metric, scale to zero, warming), triggers, security and integration: Knative, OpenWhisk, OpenFaaS, Azure Container Instances, Google Cloud Run, AWS Lambda and AWS Fargate.

  • Open source frameworks (Knative, OpenWhisk, OpenFaaS) run on top of orchestrators and give full control, but require management — and several rely on custom image templates, which pushes them away from pure CaaS.
  • Public cloud services (Cloud Run, ACI, Fargate, Lambda) shift management to the provider in exchange for restrictions.
  • Azure Container Instances and AWS Fargate keep containers continuously active: no scale to zero, but no cold starts either.
  • Knative, OpenFaaS and Cloud Run allow a minimum container count — a hybrid model that mitigates cold starts.
  • Selection criterion for the quantitative phase: only Knative, Cloud Run and AWS Fargate. OpenWhisk, OpenFaaS and Lambda require custom image templates; ACI has no autoscaling.

Experiment architecture

All infrastructure, benchmark images and load scripts are in the master-lab repository. Locally, the project spins up a Kubernetes cluster via Terraform for Knative; for Cloud Run and AWS Fargate, the same container set and scripts can be reused on each platform.

master-lab repository on GitHubTerraform · Docker · k6 ↗
  • Benchmark machines (BM) in two geographically close European regions: AWS Stockholm (eu-north-1) and GCP Hamina (europe-north1).
  • Each BM boots via docker-compose with two containers: InfluxDB (time-series store for metrics, centralised on GCP) and a custom Jupyter Notebook image holding the automation scripts.
  • The load agent is k6.io, launched by a bash script parameterised with URL, platform, test id, run id and the third independent variable.
  • k6 streams per-request metrics into InfluxDB; Python scripts in Jupyter query, aggregate and plot them.
  • Knative ran on a 3-node GKE cluster of e2-standard-4 VMs (16 GiB, 4 vCPUs), exposed through an Ingress. Platforms were configured without scale to zero, to avoid cold starts, and with a single container per instance.
  • Benchmark images for C#, Go, Java, Node.js, PHP and Python, with yarn commands to build, run locally and push to GCP/AWS.
  • Terraform and Docker Compose in the repository allow the test environment to be reproduced: local cluster, metrics collector and Grafana dashboard.

The seven tests

  • T1 — Load: a sequence of low-cost GET requests (a Node.js “Hello World” endpoint) over 60 s with a single virtual user, measuring end-to-end latency.
  • T2 — Concurrent load: latency, request count and success rate with virtual users (vus) ramping in parallel. It is the base for T4 to T7.
  • T3 — Spike: elasticity, with a ramp-up and ramp-down phase to force scale-out and scale-in.
  • T4 — Payload size: T2 with payload size as the third variable (I/O impact).
  • T5 — Programming language: T2 varying the container language/image.
  • T6 — Memory and CPU: T2 across proportional memory and CPU settings.
  • T7 — Compute intensive: recursive Fibonacci, correlating the Fibonacci number with increasing vus.
Figure 4.3 — internal architecture of the benchmark machine and test flow: **Jupyter**, **k6** and **InfluxDB** in **Docker** containers.
Figure 4.3 — internal architecture of the benchmark machine and test flow: Jupyter, k6 and InfluxDB in Docker containers.
Figure 4.1.2 — architecture deployed on AWS: VPC, public and private subnets, ELB, ECS/Fargate and ECR.
Figure 4.1.2 — architecture deployed on AWS: VPC, public and private subnets, ELB, ECS/Fargate and ECR.
Figure 4.1.3 — architecture deployed on GCP: **GKE** with **Knative** (kourier, HPA, ksvc), **Cloud Run** and the Serverless VPC Access Connector.
Figure 4.1.3 — architecture deployed on GCP: GKE with Knative (kourier, HPA, ksvc), Cloud Run and the Serverless VPC Access Connector.

Results

  • Low-load latency (T1): Knative and AWS Fargate are practically tied; Cloud Run shows latencies around five times higher.
  • Scalability (T2/T3): the order flips under stress — Cloud Run improves as vus grow, followed by Knative and last AWS Fargate. Success rates stayed at 100% (99.99% in the spike test).
  • Stability: despite the best behaviour at scale, Cloud Run was unstable across every experiment, with high latency spikes — an argument against it for critical systems that need predictable latency.
  • Payload (T4): AWS Fargate is indifferent to payload size; Knative and Cloud Run improve response times, likely because heavier I/O resource usage triggers scale-out earlier.
  • Language (T5): Go and JavaScript perform best under parallel load; Java and especially Python degrade response times sharply.
  • Memory and CPU (T6): more resources improve performance, but the gain is limited and depends on application efficiency and the configured scaling rules.
  • Compute intensive (T7): Knative is the most efficient, with more computations and lower average latency; AWS Fargate failed to compute large Fibonacci numbers and showed high latency.
T1 — **Cloud Run** latency over 60 s: spikes above 150 ms reveal instability.
T1 — Cloud Run latency over 60 s: spikes above 150 ms reveal instability.
T1 — Knative latency over 60 s.
T1 — Knative latency over 60 s.
T1 — AWS Fargate latency over 60 s.
T1 — AWS Fargate latency over 60 s.

Cost and implementation effort

  • Cloud Run and AWS Fargate show similar estimated and actual costs, but Cloud Run allocates more CPU time, supports scale to zero and bills only for request execution time — making it cheaper.
  • Knative is the most expensive option, since it depends on a VM pool for the Kubernetes cluster. It is justified when private cloud or avoiding vendor lock-in matters.
  • Learning curve: Cloud Run is the simplest (one CLI command creates a scalable service); Knative comes second if cluster setup is excluded; AWS Fargate demands more components and specific AWS networking knowledge.

Conclusion: CaaS platforms respond well to increasing traffic and offer concrete mechanisms for serverless's classic problems — cold starts and execution limits. The choice comes down to the trade-off between scalability (Cloud Run), predictability and portability (Knative), and integration with existing infrastructure (AWS Fargate).

Master's dissertation in Computer Science, January 2022. Supervisor: Professor Isabel Alvarez.
Master's dissertation in Computer Science, January 2022. Supervisor: Professor Isabel Alvarez.
Read the full dissertation (PDF, PT)PDF · PT ↓