FullStack Course LogoFullStack Course
Module: System Design
System Design·277·12 MIN READ

277: Cloud Architecture: VMs, Containers, Kubernetes Concepts, Serverless, and Managed Services

TOPICS COVERED: Cloud Architecture: VMs, Containers, Kubernetes Concepts, Serverless, and Managed Services

Learning outcomes

By the end of this lesson, you can:

  • explain and apply virtual machines in a realistic implementation;
  • explain and apply containers in a realistic implementation;
  • explain and apply kubernetes concepts in a realistic implementation;
  • explain and apply serverless functions in a realistic implementation;
  • explain and apply managed services in a realistic implementation.

Prerequisites and retrieval

This lesson assumes the earlier 01–06 foundation and the preceding lessons in this module. Before you read, retrieve one concrete example from an earlier project in which this kind of infrastructure concern appeared. It might be a deployed API, a worker, a database, or a service that had to handle uneven traffic. The point is not to memorize a list of cloud-product names. The point is to make a defensible choice for a large-scale distributed service, with its requirements, traffic pattern, failure modes, cost limits, and operational constraints stated explicitly.

Terminology

  • Virtual machines: A VM gives you strong isolation and flexible control over the runtime, but you also take on operating-system patching, image maintenance, capacity planning, and a scale-up path that is often slower than lighter abstractions.
  • Containers: A container packages a process and its filesystem dependencies into a consistent unit that can usually start quickly. It is a packaging and isolation boundary, not a complete replacement for hosts or orchestration.
  • Kubernetes concepts: Pods, Deployments, Services, Config/Secrets, autoscaling, probes, and controllers work together to automate a desired state. That automation is useful, but the platform introduces complexity that many small teams do not need.
  • Serverless functions: A function runs in response to an event or request and scales around that work. This reduces server management and is a good fit for many bursty, stateless workloads.
  • Managed services: Managed databases, queues, caches, object storage, and identity services remove much of the undifferentiated operational work. They do not remove the need to configure the service, understand quotas, manage backups and security, or control cost.
  • Shared responsibility: The provider secures the underlying infrastructure according to the service model. The customer remains responsible for identities, data, network policies, configuration, application vulnerabilities, and often some patching.

The useful distinction is between handing over routine infrastructure work and handing over responsibility for the system. Managed services and serverless products can reduce the first without eliminating the second.

Mental model

Treat Cloud Architecture: VMs, Containers, Kubernetes Concepts, Serverless, and Managed Services as a design problem with observable inputs, outputs, invariants, and failure modes. Cloud primitives move operational responsibility; they do not make systems constraints disappear. Select the abstraction level based on the workload shape, the team's skills, scaling requirements, compliance needs, and portability requirements.

A strong implementation makes its assumptions visible, narrows uncertainty at boundaries, and leaves evidence for why the design is safe. That evidence may be tests, types, resource constraints, metrics, deployment configuration, or a diagram. If you cannot explain what happens when a dependency is slow, unavailable, duplicated, or over quota, the abstraction has hidden rather than solved the problem.

A useful sequence for both interviews and production design is:

text
requirement -> constraints -> model -> implementation -> failure analysis -> verification

Do not jump from a requirement directly to a product or library call. First state what must remain true. Then choose the mechanism that enforces that invariant and decide how you will verify it.

Deep dive

1. Virtual machines

When you need a familiar operating-system environment, custom kernel or networking behavior, or a strong isolation boundary, a virtual machine can be the clearest choice. A VM provides strong isolation and flexible runtime control. The trade-off is that your team is now involved in OS patching, image creation, capacity management, and the slower scale characteristics that commonly come with a full machine.

That responsibility affects the design even when the application code does not change. An instance can be healthy while its image is outdated, its disk is full, or the fleet has too little spare capacity. Those are operational concerns that need an owner, a rollout strategy, and observable signals.

Decision rule: Use virtual machines deliberately when they make the contract or invariant easier to prove. If they only reduce the amount of application code while hiding an assumption, prefer the more explicit design.

2. Containers

Containers address a common deployment problem: the process works in one environment because its runtime and filesystem dependencies happen to be present there, but fails in another. Packaging those dependencies consistently makes the unit easier to build, move, and start. Containers generally start quickly, but they still depend on hosts or orchestrators.

The container boundary does not make resource usage safe by itself. Set CPU and memory limits, use trusted and maintainable images, and define graceful shutdown behavior so in-flight work is not abandoned during replacement. Image security and dependency updates remain part of the team's responsibility.

Decision rule: Use containers deliberately when they make the contract or invariant easier to prove. If they only reduce typing while hiding an assumption, prefer the more explicit design.

3. Kubernetes concepts

Kubernetes is useful when a fleet of containerized workloads needs a consistent way to declare and maintain its desired state. Pods provide the execution unit, Deployments manage replicated rollout state, and Services provide stable discovery and routing. Config/Secrets separate configuration from the image, probes communicate health, autoscaling responds to demand, and controllers continually reconcile the actual state toward the declared state.

This is powerful precisely because the platform is doing a lot of work. It also means there are more objects, controllers, failure modes, and operational concepts to understand. A small team with a small, stable service may spend more effort operating Kubernetes than operating the application. The platform should solve a real fleet, rollout, or scheduling problem rather than serve as a default badge of scale.

Decision rule: Use kubernetes concepts deliberately when they make the contract or invariant easier to prove. If they only reduce typing while hiding an assumption, prefer the more explicit design.

4. Serverless functions

Serverless functions are a useful fit when work is naturally triggered by an event or request and can remain stateless between invocations. The platform handles much of the server provisioning and can scale execution around demand, which is particularly attractive for bursty traffic.

The trade-off is a different set of limits, not the absence of limits. Cold starts can affect latency, execution duration may be capped, and opening connections per invocation can overload a database. Logging and tracing may require deliberate setup, and the function's event model can increase provider coupling. These constraints matter before choosing the model for latency-sensitive, long-running, or stateful work.

Decision rule: Use serverless functions deliberately when they make the contract or invariant easier to prove. If they only reduce typing while hiding an assumption, prefer the more explicit design.

5. Managed services

Managed services are often the pragmatic choice for capabilities that are not the product's differentiator. A managed database, queue, cache, object store, or identity service can remove routine infrastructure operations and provide established durability or availability features.

That convenience is not a free pass. Configuration still determines behavior, quotas can become a production limit, backups need to be tested, security settings need review, and usage-based pricing needs monitoring. A managed database can still be mis-indexed, a queue can still fill, and an object store can still be exposed by an incorrect policy.

Decision rule: Use managed services deliberately when they make the contract or invariant easier to prove. If they only reduce typing while hiding an assumption, prefer the more explicit design.

6. Shared responsibility

Shared responsibility is the boundary that prevents a dangerous assumption: “the cloud provider handles security.” Providers secure the underlying infrastructure according to the service model, but the customer still owns identities, data, network policies, configuration, application vulnerabilities, and often patching. The exact boundary varies by service, so verify it in the provider's documentation rather than relying on the product label.

For example, a provider may patch the managed database engine while your team must restrict who can connect, protect credentials, define backup retention, and authorize each application operation. Security and reliability work therefore remains part of architecture, even when the infrastructure is managed.

Decision rule: Use shared responsibility deliberately when it makes the contract or invariant easier to prove. If it only reduces typing while hiding an assumption, prefer the more explicit design.

Worked example

Consider a large-scale distributed service whose requirements, traffic, failure modes, cost, and operational constraints must be made explicit. Start with the requirement in one sentence. Then list the input and output contracts and identify which concept owns each failure mode. The useful architectural move is separation: parsing and validation belong at the boundary; domain rules belong in the domain or service layer; persistence rules belong in the database or repository; presentation rules belong in the client.

Keeping those responsibilities separate may make a happy-path demo look slightly longer, but it makes failures and edge cases much easier to locate. A cloud choice does not change that ownership model. Whether the API runs on a VM, in a container, on Kubernetes, or as a function, malformed input should not be allowed to reach a layer that is not responsible for interpreting it.

text
Client
  |
DNS -> CDN / Edge
  |
Load Balancer -> API instances -> Cache
                          |          |
                          +------> Primary datastore
                          |
                          +------> Queue / Stream -> Workers

Walk through the architecture using at least four cases: the normal path; an empty or missing value; a duplicate, retry, or concurrent path where relevant; and a dependency failure. For each case, state which layer detects the problem and what the caller observes. For instance, a boundary may reject malformed input, a repository may surface a uniqueness conflict, and a timeout may cause the service to return a controlled dependency error rather than hang indefinitely. The exact response depends on the contract, but the ownership and observable behavior should be explicit. This is the level of explanation expected in a senior code review or technical interview.

Production perspective

Production correctness is broader than “the code works on my machine.” Ask how the design behaves during deployments, retries, partial failure, stale clients, concurrent requests, malformed data, schema changes, and high-cardinality telemetry. Prefer explicit contracts, bounded resource usage, structured errors, and measurable behavior. Optimize only after evidence identifies a bottleneck or risk.

When the topic involves an external dependency, define a timeout and cancellation strategy. When it involves persistence, define transaction and consistency expectations. When it involves user-visible state, define loading, empty, error, stale, and success states. When it involves security, assume the client can be modified and every network input is untrusted. These requirements still apply when a provider operates the servers for you.

Guided lab

Map a three-tier application to VM-only, managed-container, Kubernetes, and serverless variants. Compare operational burden, scaling behavior, cold start, networking, cost, and vendor coupling. Do not stop at naming the deployment model: for each variant, identify who patches the runtime, how instances or invocations scale, where state lives, and what happens when the database or queue is unavailable.

Complete the lab with this discipline:

  1. Write the requirement and two non-requirements.
  2. List input, output, and error contracts before implementation.
  3. Implement the smallest correct vertical slice.
  4. Add at least one invalid-input test and one edge-case test.
  5. Instrument or inspect the behavior instead of guessing.
  6. Refactor one hidden assumption into an explicit type, constraint, function, or configuration.
  7. Explain one alternative design and why you did not choose it.
  8. Record a short “what would break at 10× scale?” note.

Edge cases and failure modes

  • Virtual machines: Test absence, malformed input, duplicates, ordering or concurrency where applicable, and behavior at the smallest and largest credible sizes. Also consider stale images, exhausted capacity, and an instance that is running but not serving correctly.
  • Containers: Test absence, malformed input, duplicates, ordering or concurrency where applicable, and behavior at the smallest and largest credible sizes. Include resource limits, image failures, and graceful shutdown during replacement.
  • Kubernetes concepts: Test absence, malformed input, duplicates, ordering or concurrency where applicable, and behavior at the smallest and largest credible sizes. Check incorrect probes, failed rollouts, unavailable capacity, configuration mistakes, and autoscaling that reacts too slowly or to the wrong signal.
  • Serverless functions: Test absence, malformed input, duplicates, ordering or concurrency where applicable, and behavior at the smallest and largest credible sizes. Include retries, duplicate events, cold starts, connection limits, execution timeouts, and a downstream service that is unavailable.
  • Managed services: Test absence, malformed input, duplicates, ordering or concurrency where applicable, and behavior at the smallest and largest credible sizes. Also test quota exhaustion, failed or unverified backups, permission errors, stale cache data, and unexpected cost growth.

Common mistakes and debugging

  • Solving the example instead of the requirement: a copied pattern may be syntactically correct but architecturally wrong for the actual traffic, reliability, or cost constraints.
  • Hiding uncertainty with assertions, broad exception handlers, permissive schemas, or “temporary” any values.
  • Testing only the happy path and discovering the real contracts only after integration.
  • Optimizing before measuring, or selecting a scalable mechanism without a scale requirement.
  • Letting client-side behavior stand in for server-side authorization, validation, or persistence guarantees.

For debugging, reproduce the smallest failing case first. Inspect the actual value, request, log context, metric, or execution plan rather than the value you expected to see. Trace the boundary where the invariant first becomes false, then fix the layer that owns that invariant instead of adding a downstream patch. In cloud systems, also check deployment configuration, resource limits, identity permissions, dependency health, and provider quotas; “the application is up” does not prove that its complete request path is healthy.

Interview questions

  1. What problem do virtual machines solve, and what trade-off or failure mode would make you choose a different approach?
  2. What problem do containers solve, and what trade-off or failure mode would make you choose a different approach?
  3. What problem do Kubernetes concepts solve, and what trade-off or failure mode would make you choose a different approach?
  4. What problem do serverless functions solve, and what trade-off or failure mode would make you choose a different approach?
  5. What problem do managed services solve, and what trade-off or failure mode would make you choose a different approach?

Checkpoint

Without notes, explain Cloud Architecture: VMs, Containers, Kubernetes Concepts, Serverless, and Managed Services to another developer in five minutes. Your explanation must include one invariant, one edge case, one production failure mode, and one alternative design. Then implement a small example without copying the lesson code.

Mastery checklist

  • I can define the core terms precisely.
  • I can choose a design from requirements instead of from habit.
  • I can implement and test the normal path and edge cases.
  • I can explain the runtime, storage, or complexity cost.
  • I can identify which layer owns validation, errors, and recovery.
  • I can compare at least two reasonable alternatives.
  • I can explain how the design changes at larger scale or stricter reliability.

References

Reader page: /system-design/lesson/277/cloud-architecture-vms-containers-kubernetes-concepts-serverless-and-managed-services