Skip to content

Cloud Deployment Roadmap

Kubernetes is not the right answer for every team. It solves real problems at scale β€” but it introduces significant operational complexity and cost that can sink a small team or startup before they ship their first feature. This class maps the deployment landscape and provides a decision framework: given your team size, service count, and operational maturity, what is the right infrastructure choice right now, and how do you grow into the next tier?

The previous class, Service Models, gave the vocabulary (IaaS, PaaS, CaaS, DBaaS). This class turns it into concrete platforms, prices and a migration path for the store: gateway, account, order, Postgres.

Learning objectives

By the end of this class you should be able to:

  • Compare the main deployment platforms (Railway, Render, Fly.io, Lightsail, ECS Fargate / Express Mode, EKS, K3s) by what they hide and what you still manage.
  • Choose a platform for a given team size, service count and operational maturity, and justify why Kubernetes is or is not worth it yet.
  • Estimate the monthly cost of a small microservice system from unit prices, and point out the fixed costs (control plane, load balancer, NAT gateway) that dominate at small scale.
  • Plan a migration path driven by concrete pain points instead of speculation about future scale.
  • Diagnose the common networking traps of simple platforms (private networking, reaching a managed database).

Slides

Click the slides and use ← β†’ to move through them; F goes full screen and P opens the presenter view, with the notes. Open the slides in a new tab


1. The Spectrum of Managed Infrastructure

Cloud providers have progressively abstracted away infrastructure concerns. The tradeoff is always the same: the more the platform manages, the less control you have and the less operational burden you carry. The diagram reads from the most managed option on the left to the most control (and most work) on the right:

flowchart LR
    subgraph dx ["Developer-experience path"]
        railway["Railway / Render<br/>(git push β†’ URL)"] -->|"more control, more ops"| fly["Fly.io<br/>(Dockerfile, regions)"]
        fly -->|"more control, more ops"| lightsail["Lightsail<br/>(simple VM or containers)"]
    end
    subgraph aws ["AWS-native path"]
        express["ECS Express Mode<br/>(image β†’ HTTPS URL)"] -->|"more control, more ops"| ecs["ECS Fargate<br/>(task definitions, no nodes)"]
        ecs -->|"more control, more ops"| eks["EKS<br/>(full Kubernetes)"]
        eks -->|"more control, more ops"| vm["EC2 VMs<br/>(you run everything)"]
    end

Two paths, not one axis

There is no single spectrum here. ECS Express Mode is not "more managed" than Railway in any measurable way β€” they target different use cases. The diagram shows two paths: the developer-experience path (PaaS-style platforms that hide almost everything) and the AWS-native path (services that live in your AWS account, next to RDS, IAM and your VPC). Your team's context determines which path is relevant.

Platform Model What it hides What you manage Best for
Railway / Render PaaS Everything except code Env vars, domains Startups, prototypes, side projects
Fly.io PaaS / CaaS Infrastructure Dockerfile, regions, machine sizes Global low-latency apps, edge deployments
AWS Lightsail IaaS (VPS) or simple CaaS Hardware, networking Instance: OS and runtime; containers: image and scale First cloud deployment, student projects, fixed budgets
AWS ECS Express Mode CaaS Load balancer, scaling, networking setup Container image, env vars, two IAM roles Stateless services on AWS, the simple entry to ECS
AWS ECS Fargate CaaS EC2 nodes Task definitions, service scaling, ALB Medium-scale, AWS-native, production
AWS EKS CaaS (managed Kubernetes) Control plane Node groups, networking, add-ons Large teams, complex workloads, multi-tenant
Self-hosted K3s IaaS + your own Kubernetes Nothing beyond the VM All K8s operations On-prem, homelab, cost-sensitive

Section 5 estimates the monthly cost of each one for the same workload.

AWS App Runner is closed to new customers

Earlier editions recommended AWS App Runner (container image or Git repo β†’ HTTPS URL). Since 30 April 2026, App Runner no longer accepts new customers; existing customers keep using it, but no new features are planned. AWS recommends Amazon ECS Express Mode as the replacement2. Managed platforms have a lifecycle β€” this is one more face of vendor lock-in.


2. Decision Roadmap by Team Size

Fewer than 10 services? Start here.

flowchart TD
    A{"Must it run on AWS?<br/>(credits, compliance)"}
    A -->|No| B{"Users spread over<br/>several continents?"}
    B -->|No| C["Railway / Render<br/>(git push β†’ URL)"]
    B -->|Yes| D["Fly.io<br/>(multi-region machines)"]
    A -->|Yes| E{"One VM or a few<br/>containers is enough?"}
    E -->|Yes| F["Lightsail<br/>(fixed monthly price)"]
    E -->|No| G["ECS Express Mode<br/>(Fargate + ALB)"]

Key recommendation: Railway or Render for the fastest time-to-live β€” connect a GitHub repo and you have a live URL in minutes. On AWS, Lightsail when a fixed, predictable bill matters most; ECS Express Mode when you want a managed container platform that can later grow into full ECS without migrating.

EKS at this scale

The EKS control plane alone costs $0.10/hour β‰ˆ $73/month1. Add a minimum node group (2 Γ— t3.medium β‰ˆ \(61/month), a load balancer and a database, and you are spending around **\)180/month** before any traffic β€” several times the whole bill on the simpler platforms (see section 5). For a small product team, Kubernetes is not an option here β€” it is a liability.

10–50 services. You need production-grade infrastructure but probably not a full platform engineering team.

flowchart TD
    A{"Dedicated ops /<br/>platform engineer?"}
    B["ECS Fargate + ALB + RDS<br/>(serverless containers, no nodes)"]
    C["EKS (managed node groups)<br/>or ECS with more control"]

    A -->|No| B
    A -->|Yes| C

Why ECS Fargate for medium teams: no EC2 nodes to patch, and native integration with AWS IAM, Secrets Manager, ECR, and service discovery (Cloud Map / Service Connect). You lose the Kubernetes ecosystem but avoid the fixed control-plane fee and the node operations, which makes day-to-day work dramatically simpler.

Fargate does not scale to zero by itself

An ECS service keeps its desiredCount of tasks running and billing 24/7. Auto scaling adjusts that count between a minimum and a maximum; reaching zero requires setting the minimum (or a schedule) to 0 yourself, and the next request then has no task to serve it.

ECS Fargate EKS
Node management None (serverless) You manage node groups (or pay for Auto Mode)
Learning curve Low (task definitions) High (full K8s API)
Ecosystem (Helm, CRDs) Limited Full
Fixed cost before any workload None β€” pay per task ~$73/month control plane per cluster
Multi-cloud portability AWS-only Portable (standard K8s API)
GitOps (ArgoCD, Flux) Limited First-class

50+ services. EKS is the right answer β€” now the operational cost is justified.

At this scale, you need:

  • Managed node groups (or Karpenter for bin-packing autoscaling)
  • ArgoCD for GitOps β€” declarative cluster state from Git
  • AWS Load Balancer Controller β€” provision ALB/NLB from Kubernetes Ingress resources
  • external-secrets-operator β€” sync Vault or AWS Secrets Manager secrets into Kubernetes Secrets
  • Separate clusters per environment β€” dev, staging, prod each get their own EKS cluster
Add-on Purpose
Karpenter Node autoscaling β€” provision exactly the right instance types for pending pods
ArgoCD GitOps β€” declarative cluster state reconciled from Git
AWS Load Balancer Controller Provision ALB/NLB from Kubernetes Ingress resources
External Secrets Operator Sync Vault/Secrets Manager secrets into Kubernetes Secrets
Metrics Server Enables HPA (Horizontal Pod Autoscaler)
Cluster Autoscaler Alternative to Karpenter for node scaling

EKS Auto Mode

Since December 2024, EKS Auto Mode lets AWS manage the worker nodes as well (Karpenter-based provisioning, OS patching) together with core add-ons such as load balancing and block storage, for a management fee on top of the EC2 price19. It reduces the node work in this list, not the need to understand Kubernetes.

Then why does the course project use EKS?

The project deploys the store on EKS with a team of 2–3 people β€” exactly what this class advises a startup not to do. The goal is different: the project exists to learn Kubernetes and AWS, not to minimise cost or time-to-market. Keep the cluster small, delete it when you are not using it, and use the Costs task to compare its bill with the alternatives from section 5.


3. Platform Deep-Dives

AWS Lightsail Containers

Lightsail wraps containers in an abstraction that feels like Heroku: push an image, set environment variables, choose a node size (power) and a number of nodes (scale), get a public HTTPS endpoint. No VPCs, security groups, or IAM policies to configure, and a fixed monthly price per node4.

$ aws lightsail create-container-service --service-name my-api \
    --power small --scale 1
$ aws lightsail create-container-service-deployment \
    --service-name my-api \
    --containers '{"my-api":{"image":"my-registry/my-api:latest","ports":{"8080":"HTTP"}}}' \
    --public-endpoint '{"containerName":"my-api","containerPort":8080}'

The image must come from a public registry (e.g., Docker Hub) or be pushed to the service's own registry with aws lightsail push-container-image; Lightsail then refers to it as :my-api.<label>.<version>.

Lightsail networking limitations

Lightsail does not use standard AWS VPC networking. Each container service has one public endpoint and a private domain, <service-name>.service.local, reachable only from other Lightsail resources in the same Region β€” so the store's gateway can be public while account and order are reached as account.service.local:8080. Reaching an RDS instance in a normal VPC requires Lightsail VPC peering with the account's default VPC β€” an extra configuration step many tutorials skip. There are no security groups, service mesh or fine-grained network policies.


Amazon ECS Express Mode (successor to App Runner)

ECS Express Mode (launched November 20253) keeps App Runner's "image in, HTTPS URL out" simplicity, but everything it creates is an ordinary ECS resource in your own account. With one call you provide a container image and two IAM roles; ECS provisions a Fargate service, an Application Load Balancer with HTTPS, auto scaling, security groups and a default URL2. There is no extra charge for Express Mode β€” you pay for the Fargate tasks, the load balancer and the rest of the underlying resources.

aws ecs create-express-gateway-service \
    --service-name order-service \
    --execution-role-arn arn:aws:iam::123456789012:role/ecsTaskExecutionRole \
    --infrastructure-role-arn arn:aws:iam::123456789012:role/ecsInfrastructureRoleForExpressServices \
    --primary-container '{
        "image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/order:1.0",
        "containerPort": 8080,
        "environment": [{"name": "SPRING_PROFILES_ACTIVE", "value": "prod"}]
    }' \
    --health-check-path "/actuator/health" \
    --scaling-target '{"minTaskCount":1,"maxTaskCount":4}'
  • Image only. Unlike App Runner, Express Mode does not build from source: your CI must build and push the image to ECR β€” exactly what the Jenkins pipeline of Hands-on 4 does.
  • Shared load balancer. Several Express services (up to 25) can share one ALB, with rule-based routing keeping them isolated3 β€” useful for the store, which has several small services.
  • No dead end. Because the ALB, target groups and task definitions are visible in your account, "graduating" to full ECS Fargate means editing those resources, not migrating.

Reaching RDS

The tasks run in subnets of your VPC, so reaching an RDS instance is a matter of security-group rules (allow the task's security group on port 5432) β€” no special connector. App Runner, by contrast, ran in an AWS-managed VPC and needed a VPC Connector to reach private resources.


Railway

Railway provides the simplest developer experience in the ecosystem: connect a GitHub repo, Railway detects the language and framework, builds and deploys automatically. Billing is usage-based (per vCPU and GB of memory actually used, per second), on top of a small monthly plan fee that counts as usage credit6.

What Railway provides out of the box:

  • Automatic HTTPS with custom domains
  • Built-in Postgres, Redis, and MongoDB as add-on services
  • Deploy on push β€” no CI/CD pipeline needed initially
  • Private networking between services of the same project (<service>.railway.internal), so only the gateway needs a public domain
  • Dashboard with logs, metrics, and environment variable management

Railway trade-offs at scale

Railway gives you very little control over networking β€” you cannot design VPCs, subnets or security group equivalents, only choose which services get a public domain. There is also no Kubernetes ecosystem (no Helm, no CRDs, no GitOps tooling). Vendor lock-in becomes a real risk once you have more than 10–15 services and complex inter-service networking requirements.


Fly.io

Fly.io runs containers as lightweight VMs (Machines) on servers in regions around the world, close to your users. A fly.toml config file defines the application; fly deploy builds and deploys it7.

app = "my-order-service"
primary_region = "gru"  # SΓ£o Paulo

[build]
  dockerfile = "Dockerfile"

[http_service]
  internal_port = 8080
  force_https = true

[env]
  SPRING_PROFILES_ACTIVE = "prod"

Strong suit: Fly.io places your containers in regions close to your users. A user in SΓ£o Paulo reaches gru in a few milliseconds, against more than 100 ms of round trip to a US East region. Adding regions is one command β€” fly scale count 3 --region gru,iad,lhr β€” and Fly's Anycast routing sends each user to the nearest Machine. Apps in the same organisation talk over a private network (<app>.internal).

Weak suit: Stateful services are more complex than on AWS. The classic Fly Postgres is an app that you operate yourself (backups, failover, upgrades); the newer Managed Postgres removes that work but starts at a higher fixed price than the compute of a small app7. There is no free tier for new organisations, only a short trial.


4. Kubernetes Alternatives for Orchestration

If you want Kubernetes features but not EKS cost or complexity, these distributions are worth knowing. All of them expose the same Kubernetes API, so the manifests from Hands-on 5 run unchanged:

Minikube β€” Runs upstream Kubernetes in a VM or container on your laptop, single node by default, with add-ons (ingress, dashboard, metrics-server). It is the environment of Hands-on 5 and the MiniKube exercise β€” built for learning and local development, not for production.

K3s β€” Lightweight, CNCF-certified Kubernetes (single binary under 100 MB) originally from Rancher, now SUSE8. It implements the same API as upstream Kubernetes, uses SQLite instead of etcd by default on a single server (embedded etcd for HA), and bundles Traefik as ingress. Ideal for on-premises deployments, edge devices, and small production clusters on one or a few VMs.

K0s β€” "Zero-friction" Kubernetes from Mirantis. A single binary with no host dependencies beyond the kernel; it bundles and manages its own control-plane components (etcd, or kine with SQLite/MySQL/Postgres). Common choice for on-premises production where a vanilla, minimal distribution is preferred.

Kind (Kubernetes in Docker) β€” Runs each Kubernetes node as a Docker container. Created to test Kubernetes itself, it is now the standard choice for integration tests in CI and for validating manifests before pushing to a real cluster.

Minikube K3s K0s Kind
Use case Local dev On-prem / edge prod On-prem prod CI/CD testing
Full K8s API βœ“ βœ“ βœ“ βœ“
Production-grade βœ— βœ“ βœ“ βœ—
Resource requirements Medium Very low Very low Low

Self-hosting moves the work, not just the cost

K3s on a $24 VM gives you the Kubernetes API for a fraction of the EKS price (section 5), but the control plane is now yours: a single VM is a single point of failure, and upgrades, backups of the datastore and certificates are your job.


5. Cost Comparison

How much does it cost to run the store's three microservices (gateway, account, order) plus one small Postgres database on each platform? The table and the chart below are generated from one cost model: a list of unit prices and, for each platform, a low and a high configuration built from those prices. Change a price in the code and both update together.

Assumptions β€” read before quoting a number

  • Approximate on-demand list prices in USD, cheapest US region (AWS us-east-1 N. Virginia, Fly.io iad), checked in October 202614567. Prices change; confirm with the AWS Pricing Calculator and each provider's page.
  • Everything runs 24/7 (730 hours per month) at moderate traffic.
  • Not included: data transfer out, logs and metrics storage, domain names, taxes, free tiers and credits.
  • SΓ£o Paulo costs more. sa-east-1 list prices are noticeably higher than us-east-1 for most services, and Fly.io charges more in gru as well. Use your real region when you estimate.
PlatformLowHighLow estimate assumesHigh estimate assumes
Railway (Hobby)$19$603 services + Postgres, ~0.2 vCPU / 1.5 GB used in total ($19)3 services + Postgres, ~1 vCPU / 4 GB used in total ($60)
Fly.io$15$613 machines shared-1x 512 MB ($11) + self-run Postgres machine + 1 GB volume ($4)3 machines shared-1x 1 GB ($20) + Managed Postgres Basic + 10 GB ($41)
Lightsail$24$60one 4 GB instance running Docker Compose (Postgres in a container) ($24)3 container services (Small) ($45) + managed database ($15)
K3s on one VM$24$59Lightsail 4 GB instance, Postgres as a pod ($24)Lightsail 8 GB instance ($44) + managed database ($15)
ECS Fargate (or Express Mode)$71$1963 tasks 0.25 vCPU / 0.5 GB ($27) + ALB ($30) + RDS db.t4g.micro ($14)3 tasks 1 vCPU / 2 GB ($108) + ALB ($30) + RDS db.t4g.small ($26) + NAT gateway ($33)
EKS$180$350control plane ($73) + 2 Γ— t3.medium nodes ($61) + EBS 2 Γ— 20 GB ($3) + ALB ($30) + RDS db.t4g.micro ($14)control plane ($73) + 3 Γ— t3.large nodes ($182) + EBS 3 Γ— 30 GB ($7) + ALB ($30) + RDS db.t4g.small ($26) + NAT gateway ($33)
2026-10-12T22:08:24.181404 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/

Reading the estimate: where the money goes

Look at the assumes columns rather than the totals. At this scale the bill is dominated by fixed costs that exist even with zero traffic:

Line item Approx. per month Why it appears
EKS control plane $73 per cluster $0.10/hour for the managed API server, scheduler and etcd1
Application Load Balancer ~$30 Hourly fee + capacity units + its public IPv4 addresses
NAT gateway ~$33 + data Lets tasks or nodes in private subnets reach the internet (ECR, external APIs)
Public IPv4 address ~$3.65 each AWS charges every public IPv4 address since February 202410
Smallest RDS instance ~$14 db.t4g.micro + 20 GB storage, single-AZ (Multi-AZ doubles it)

The compute for three small Spring Boot services is often the smallest line. This is why a platform with a fixed control-plane fee loses at three services and wins at fifty: the fixed cost is spread across more workloads. It is also why "one EKS cluster per environment" (dev, staging, prod) triples the fixed part of the bill.

Protect your AWS account

Create an AWS Budget with an e-mail alert before you create a cluster, tag every resource with the project name, and delete NAT gateways, load balancers and clusters when you stop working β€” they bill by the hour whether you use them or not. The Costs task of the project asks for exactly this analysis.


6. Example: the store at each stage

The same four components, deployed on the three platforms of the migration path below:

Store component Day 1 β€” Railway Year 1 β€” ECS Fargate Year 2+ β€” EKS
gateway Service with a public domain ECS service behind the ALB (Express Mode creates it) Deployment + Service, exposed by an Ingress (AWS Load Balancer Controller)
account, order Services on private networking (account.railway.internal) ECS services discovered via Service Connect / Cloud Map Deployments + ClusterIP Services (as in Hands-on 5)
Postgres Railway Postgres add-on RDS, reached through security-group rules RDS, credentials synced by External Secrets
Deploy git push to main CI builds image β†’ ECR β†’ new task definition CI builds image β†’ ECR β†’ ArgoCD syncs manifests from Git

The application code does not change across the three columns: the 12-factor style (configuration in environment variables, stateless services, state in Postgres) is what makes each migration a deployment exercise rather than a rewrite.


7. Migration Path

The right answer changes as you grow

Start simple and migrate deliberately. Each migration should be driven by a concrete pain point, not speculation about future scale. A working app on Railway is worth more than a perfectly architected EKS cluster with no users.

flowchart TD
    start(["Idea / Prototype"])
    r["Railway / Fly.io<br/>(Day 1 β€” ship fast)"]
    ex["ECS Express Mode<br/>(Month 3 β€” AWS-native, stateless)"]
    ecs["ECS Fargate, full control<br/>(Year 1 β€” production)"]
    eks["AWS EKS<br/>(Year 2+ β€” scale, team grows)"]

    start --> r
    r -->|"Need AWS services<br/>or compliance"| ex
    ex -->|"Need sidecars, private<br/>services, fine control"| ecs
    ecs -->|"Multi-team, 50+ services,<br/>GitOps required"| eks

    style r fill:#4CAF50,color:#fff
    style ex fill:#FF9800,color:#fff
    style ecs fill:#FF5722,color:#fff
    style eks fill:#F44336,color:#fff

Note that the step from Express Mode to "full" ECS Fargate is not a migration at all: Express Mode is ECS, so you start editing the task definitions, load balancer rules and networking it created.

Avoid premature optimization

The cost of migrating from Railway to ECS at 20 services is a few weeks of focused engineering work. The cost of operating EKS for a 3-person startup for a year is 40+ hours of platform ops work that produces no user-facing features. Start simple. Migrate when the pain is real, measurable, and no cheaper fix exists.

Other common pitfalls

  • Forgotten resources. A test EKS cluster, NAT gateway or load balancer left running over a holiday is the classic student bill. Set a budget alert first.
  • Hidden networking steps. Lightsail needs VPC peering to reach RDS; on ECS and EKS, a missing security-group rule looks like a "connection timed out" from the service.
  • Quoting prices without assumptions. A cost number without region, date, sizing and hours per month cannot be compared or checked.
  • Betting on a single managed product. App Runner's closure to new customers shows that the simplest platforms can change under you; keep the application portable (containers, environment variables, Postgres).

Key takeaways

  • Kubernetes is not the default: pick the platform by team size, service count and operational maturity.
  • There are two paths: developer experience (Railway/Render β†’ Fly.io β†’ Lightsail) and AWS-native (ECS Express Mode β†’ ECS Fargate β†’ EKS β†’ raw EC2), each trading simplicity for control.
  • At small scale, fixed costs (EKS control plane ~\(73, ALB ~\)30, NAT ~$33) dominate the bill; state every estimate with its region, date and sizing.
  • Small teams: Railway, Render, Fly.io, Lightsail or ECS Express Mode. Medium teams: ECS Fargate. Large teams: EKS with Karpenter/Auto Mode, ArgoCD, the Load Balancer Controller and External Secrets.
  • K3s, K0s, Kind and Minikube give the Kubernetes API without EKS β€” and hand you the control plane's operations.
  • Migrate on concrete pain, keep the application portable, and never assume a managed product will exist forever (App Runner).

Connections


  1. Amazon EKS pricing β€” \(0.10 per cluster per hour with standard Kubernetes version support (\)0.60 with extended support); Auto Mode adds a per-instance management fee. ↩↩↩↩

  2. AWS App Runner availability change β€” closure to new customers and migration guide to ECS Express Mode. ↩↩

  3. Announcing Amazon ECS Express Mode, AWS What's New, November 2025. ↩↩

  4. Amazon Lightsail pricing and Lightsail container services. ↩↩

  5. AWS Fargate pricing ↩

  6. Railway pricing ↩↩

  7. Fly.io resource pricing ↩↩↩

  8. K3s documentation ↩

  9. Amazon EKS Auto Mode ↩

  10. New β€” AWS Public IPv4 Address Charge, AWS News Blog, 2023. ↩