Understanding the Different Ways Applications run in the Cloud

So far in this series we have talked about ideas such as scalability, elasticity, cloud pricing, and deployment models. Those ideas matter because they give us the foundation. But eventually, you need to ask a more practical question.

Where does my application actually run?

That is what Cloud Compute is for.

Cloud compute, or just Compute, is the category of cloud services is used to run:

It is, in plain terms, the hosting model for the resources your application runs on.

That sounds simple, but cloud providers give you several different ways to do it. At one end you can run a full virtual machine, or a whole group of them together as a scaling group. You can run containers on their own, or under Kubernetes when there are a lot of them. You can host web applications on a managed platform, or run small pieces of code as serverless functions that wake up when something happens.

The challenge is not just knowing what each option is called. The real skill is understanding what each one is for.

A quick note before we go further: every cloud provider has its own names for all of this. What one calls a function, another calls something slightly different, and the marketing pages rarely line up neatly. The later Azure and AWS series cover the specific product names and how to set them up. For now, we are staying with the underlying concepts, because once those are clear the product names tend to fall into place.

Why there are several compute options

At first, it might seem strange that a cloud platform has so many ways to run code. Why not just have one service?

The answer is that not all workloads are the same.

By workload, I mean the work you want the cloud to carry out. That could mean keeping a web application available for users, processing data in the background, training a machine learning model, or running a small piece of code when a file is uploaded.

Each of those workloads has different requirements. Some applications need a full server environment, including control over the operating system, installed software, and configuration. This may be necessary when an application depends on older software, custom settings, or middleware, which is software that helps different parts of a system communicate.

Other applications simply need somewhere to run and do not require direct access to the server underneath.

Some workloads only run when an event occurs. Others need to run continuously. Some teams use containers, which package an application with the software and settings it needs so that it behaves consistently across development, testing, and production.

Larger organisations may need orchestration tools to coordinate many containers across multiple machines. These tools can decide where containers run, restart them if they fail, and add or remove them as demand changes.

This is why cloud platforms offer different compute options. Each one gives you a different balance of control, flexibility, scalability, and maintenance.

A useful way to compare them is to ask three questions.

  1. How much control do I need?
  2. How much maintenance am I willing to take on?
  3. How much scaling does this workload need?

In general, more control means more management. The less infrastructure you want to maintain yourself, the more you should lean towards managed services, where the cloud provider handles more of the underlying system, or serverless options, where you focus mainly on the code and the provider manages the servers for you.

This trade-off appears throughout cloud computing, so it is worth keeping in mind as we look at each compute model.

Virtualisation and virtual machines

Before talking about virtual machines, it helps to understand virtualisation.

Imagine you have one physical server. You could install an operating system directly on it, then install several applications on that same operating system. That works in simple cases, but it can become messy quickly. The applications share the same file system, network ports, services, libraries, configuration, and operating system environment. If one application needs a different version of a dependency, or if two applications try to use the same port, they can interfere with each other.

Virtualisation helps solve this problem.

With virtualisation, a physical machine can run multiple virtual machines. Each virtual machine behaves like a separate computer. It has its own operating system, its own configuration, its own file system, and its own isolated environment. The physical hardware is still underneath, but each virtual machine has its own sandbox.

This is powerful because it lets you run different applications, operating systems, and configurations on the same physical infrastructure without everything colliding.

A virtual machine gives you server-style computing in the cloud. Instead of buying a physical server, you create a virtual machine from the provider. You choose an operating system image, such as a version of Windows Server or Linux. You choose a size, which controls the amount of CPU, memory, and other performance characteristics. You choose the region, networking, disks, and other settings. In a few minutes, you have a server running in the cloud.

Virtual machines are Infrastructure as a Service. That means the provider manages the physical infrastructure, but you still manage the operating system, installed software, configuration, patches, security settings, and the application itself.

The provider manages the physical hardware and the virtualisation platform, but you still manage the operating system, installed software, configuration, patches, security settings, and the application itself.

This gives you a high level of control. You can install custom software, configure the operating system, run older applications, and migrate workloads that were originally designed to run on traditional servers.

That is why virtual machines are often used for lift-and-shift migration. Lift-and-shift means moving an existing application to the cloud without completely redesigning it. If an application currently runs on a server in an on-premises environment, a virtual machine may be the most straightforward cloud target.

Virtual machines are also useful for development and testing environments, self-managed databases, specialist software, and workloads that need full access to the operating system.

The trade-off is maintenance. Because you control the operating system, you are also responsible for looking after it. You need to think about updates, security, backups, monitoring, availability, and configuration.

A virtual machine gives you freedom, but it also gives you work.

Scaling a group of virtual machines

A single virtual machine gives you control, but it does not automatically solve scaling or availability.

If one virtual machine is not enough, you need a way to run several instances of the same workload. Most cloud providers offer a service for managing a group of virtual machines created from the same template, rather than treating each one as a completely separate server.

For a web application, traffic can be sent through a load balancer, which distributes requests across the available instances. The group can also be configured to add or remove instances as demand changes.

This is known as horizontal scaling. Instead of making one machine more powerful, you add more machines. If demand increases, the group can create more instances. If demand falls, it can remove instances that are no longer needed.

graph TD U[Users] --> LB[Load balancer] LB --> V1[VM instance 1] LB --> V2[VM instance 2] LB --> V3[VM instance 3] %% cc-caption: Users reach a load balancer, which spreads requests across several virtual-machine instances.

A managed group can also improve availability. If one instance becomes unhealthy, the platform can replace it and direct traffic to the remaining instances while the replacement starts.

These groups are still Infrastructure as a Service. You are still working with virtual machines, operating systems, machine images, networking, and infrastructure configuration. The difference is that the machines are managed as a group.

This approach is useful for workloads that can run across several interchangeable instances, such as web servers, APIs, and background processing workers.

The main benefit is that you can handle more demand and reduce your reliance on a single machine. The trade-off is complexity. You still need to manage the virtual machine environment, but now you also need to think about load balancing, scaling rules, instance health, and how the application behaves when it runs across several machines.

Containers

A virtual machine behaves like a complete computer with its own operating system. Containers take a different approach.

A container packages an application with the dependencies it needs to run, but it does not include a complete operating system of its own. Instead, it uses the operating system of the machine underneath while keeping the application separate from other containers.

This usually makes containers lighter than virtual machines. They tend to need fewer computing resources, start more quickly, and make applications easier to move between compatible environments.

A team creates a container image, which is a packaged version of the application and everything it needs to run. When that image is started, it becomes a running container.

The same image can be used during development, testing, and production. This helps the application behave consistently as it moves between environments and reduces the familiar problem of something working on a developer’s computer but failing elsewhere.

Containers are useful when you want a consistent application environment without the overhead of a complete virtual machine. They are often used to run web applications, APIs, background processing, and scheduled tasks.

Containers do not remove infrastructure concerns entirely. The images need to be stored somewhere, and the containers still need software to start and run them. You also need a way to deploy new versions and replace old ones.

It is also important to remember that a container still runs on a machine somewhere. That machine might be a virtual machine you manage yourself, infrastructure managed by the cloud provider, or one of several machines in a larger cluster.

A single machine can run several containers at the same time. Each container remains separate, but they share the CPU, memory, and other resources available on that machine. How many containers it can run depends on the size of the machine and how many resources each container needs.

When a system grows to involve many containers across several machines, managing them individually becomes difficult. At that point, you may need orchestration software to coordinate where containers run, restart them when they fail, and add more when demand increases.

That brings us to two fairly different ways of running containers in the cloud.

Running containers on managed infrastructure

The simplest way to run a container in the cloud is through a managed container service. You provide a container image, and the provider runs it.

Behind the scenes, the container still runs on a physical or virtual machine. The difference is that you do not create or manage that machine yourself. The provider decides where the container runs and looks after the underlying infrastructure.

You do not need to create a virtual machine first. You do not need to manage a full Kubernetes cluster. You do not need to think much about the underlying server.

That makes this approach useful for simple container workloads. You might use it to run a small web app, a background job, a scheduled task, a build task, or a short-lived process. It is often described as serverless container hosting because the servers still exist, but their management is largely hidden from you. You focus on the container, not the machine running it.

A managed container service may also run several instances of the same container when demand increases. Those instances may run on the same machine or across several machines, but the provider handles that decision for you.

The limitation is that this is not designed to be a full orchestration platform. If you need to coordinate many containers, control how they communicate, or manage a large application made up of several services, a managed container service may be too simple.

That simplicity is the point. Reach for it when you want to run a container quickly without managing much infrastructure.

Running containers across a Kubernetes cluster

For running containers at a larger and more sophisticated scale, the common answer is Kubernetes.

Kubernetes is an open-source container orchestration platform. Because it is open source, it has the same name almost everywhere, even though each cloud provider gives its managed service a different product name.

A Kubernetes cluster is made up of one or more machines called nodes. A node is usually a virtual machine, although it can also be a physical server. Each node can run several containers at the same time.

A cluster can run on a single machine, which is useful for learning and development. In production, however, Kubernetes usually runs across several machines. This gives the application more capacity and means it does not have to depend on one machine staying available.

Kubernetes coordinates these machines through an API server, which acts as the main point of communication for the cluster. When you use a command-line tool or dashboard to tell Kubernetes what to run, your instructions are sent to the API server.

Each node runs a small Kubernetes program called a kubelet. The kubelet communicates with the API server over a secure network connection. It receives instructions for its node, starts the required containers, and reports their status back to Kubernetes.

This means Kubernetes does not need to log in to each virtual machine and control it manually. The nodes are already connected to the cluster, and the kubelet on each one acts as the link between that machine and Kubernetes.

Orchestration means coordinating how containers run across those machines. Kubernetes decides which node should run each workload, helps scale it, manages updates, and replaces containers when they fail. If one node stops working, Kubernetes can recreate the affected workloads on another available node.

Most cloud providers offer a managed Kubernetes service, where they look after a good chunk of the underlying cluster machinery for you.

This is still a container-based approach, but it is much more powerful than running containers individually. With managed Kubernetes, you can run many containers across many nodes. You can manage complex applications made up of multiple services. Scaling workloads, rolling out updates, handling failures, and making services available to users are all part of what it does.

graph TD A[Command-line tool or dashboard] --> API[Kubernetes API server] API --> K1[Kubelet on Node 1] API --> K2[Kubelet on Node 2] K1 --> C1[Container] K1 --> C2[Container] K2 --> C3[Container] K2 --> C4[Container] %% cc-caption: Instructions are sent to the Kubernetes API server. The kubelet on each node receives work and manages the containers running on that machine.

This makes managed Kubernetes a strong option for organisations building serious container platforms or applications made up of many smaller services.

But it is not the easiest option. Kubernetes has a learning curve. It introduces its own terminology, configuration, networking, security, and operational practices. A managed service reduces some of the infrastructure burden, but it does not remove the need for Kubernetes knowledge.

That is why Kubernetes is powerful, but not always the right starting point. For a small web app, a managed app platform may be much simpler. For a quick container workload, a managed container service may be enough. For a large containerised platform with advanced requirements, Kubernetes may be the better fit.

Managed application and web hosting platforms

Managed application platforms are designed for hosting web applications, APIs, and backend services. This is one of the more approachable compute options because you do not need to manage the underlying server in the same way you would with a virtual machine.

You create the app, choose a runtime stack, and deploy your code. A runtime stack is the prepared software environment used to run your application, such as a particular version of .NET, Java, Node.js, or Python.

The provider handles much of the hosting platform underneath. These platforms commonly support languages and frameworks such as .NET, Java, Node.js, Python, and PHP. Some also allow you to deploy an application that has been packaged as a container. Exactly what is available depends on the provider and platform.

This makes them a good fit for many standard web applications. If your goal is to host a website, web API, or backend service without managing operating systems and virtual machines, a managed application platform is often a strong choice.

Managed application platforms are a common example of Platform as a Service. The provider manages the infrastructure and much of the application platform, while you focus more on your code, configuration, deployment, scaling, and monitoring.

Compared with virtual machines, a managed application platform gives you less control over the underlying environment. But for many web workloads, that is a good trade. You have less maintenance to deal with, and the platform usually makes deployment, scaling, HTTPS, custom domains, and monitoring easier.

These platforms are not automatically cheaper than virtual machines. Pricing depends on the provider and the hosting plan. Some plans charge for a set amount of computing capacity whether the application is busy or quiet. The saving may come from having less infrastructure to manage rather than from paying a lower raw compute price.

The key question is whether your application fits the platform’s model. If it does, you probably do not need a virtual machine.

Serverless functions

Serverless functions are used for running focused pieces of code in response to events. This is commonly called serverless computing.

Each cloud provider has its own name for this type of service. On AWS, it is called AWS Lambda, and the code you deploy is called a Lambda function. On Azure, the equivalent service is called Azure Functions. The underlying idea is the same: you provide the code, and the cloud platform runs it when something triggers it.

Serverless does not mean there are no servers. It means you do not manage them. The provider handles the servers, operating system, and other infrastructure needed to run and scale your code.

The event that causes a function to run is called a trigger. A trigger might be an HTTP request sent to your application, a file being uploaded to cloud storage, a timer reaching a scheduled time, or a message being added to a queue.

In this context, a message is not a chat message. It is a small package of data that one part of an application sends for another part to process. A queue holds those messages until a function or another service is ready to handle them.

For example, when a customer places an order, the application could add a message containing the order details to a queue. A serverless function could then run, read that message, and begin processing the order. Using a queue means the customer-facing part of the application does not have to wait for all of that work to finish immediately.

Functions work best when each one has a clear, focused job. This allows the platform to run several copies of the function when demand increases, retry an individual task if it fails, and stop the function when the work is complete.

A large traditional application may keep information in memory, maintain long-running connections, and contain many parts that depend closely on one another. Trying to place that entire application inside one function can make scaling and failure handling more difficult. It can also conflict with limits on how long a function can run or how much memory it can use.

This does not mean functions cannot form part of a larger application. It means the application is usually divided into smaller tasks, with each function responsible for a particular piece of work.

Functions are useful for tasks such as resizing an image after it is uploaded, processing an order from a queue, sending a notification, running scheduled cleanup work, or providing a lightweight API endpoint. An API endpoint is an address that another application can send a request to.

Functions are not usually the best place to build a large traditional application as one giant function. They work best when the application can be divided into focused tasks that run independently.

The benefit is simplicity and scalability. You write the code for the task and define its trigger. The platform then runs the function whenever that event occurs and can start additional instances when many events arrive at the same time.

Serverless functions can also be cost-effective, particularly when the code only runs occasionally or demand changes throughout the day. With consumption-based pricing, you are charged according to how often the function runs, how long it runs, and how many computing resources it uses. You are not paying to keep a server running continuously while it waits for work.

That does not mean functions are always the cheapest option. If a function runs constantly, processes a very large number of events, or needs a lot of memory, another compute model may cost less. The answer depends on the workload and the provider’s pricing model.

The trade-off is control. You do not manage the server environment directly, which is usually helpful, but you must work within the rules of the service. There may be limits on how long a function can run, how many resources it can use, and how its environment can be configured.

Serverless functions are excellent for event-driven code, automation, integrations, lightweight APIs, and background processing. They are not the answer to every compute problem.

The control-versus-maintenance ladder

The right compute option depends on what you are trying to run. It helps to picture the choices as a ladder.

Comparison of virtual machines, scaling groups, containers, Kubernetes, managed platforms, and functions, showing which cloud computing responsibilities are managed by the user and which are managed by the service provider.

The ladder is a simplified way to understand the general trade-off. The options do not fit into a perfect order, and containers in particular can be run in several different ways. You can run them on virtual machines you manage, through a managed container service, or across a Kubernetes cluster.

Use virtual machines when you need full control over the operating system, custom software, or a straightforward migration path for an existing server-based application. Use an autoscaling group when you need several similar virtual machines that can be added or removed as demand changes. For web applications, those machines often sit behind a load balancer.

Use a managed container service when you want to run containers without managing the machines underneath or operating a full orchestration platform. Use managed Kubernetes when you need to coordinate many containers across several machines and require more control over how they are deployed, connected, scaled, and updated.

Use a managed app platform when you want to host a web application or API without managing virtual machines. Use serverless functions when you want to run focused pieces of code in response to events with minimal infrastructure management.

As the provider manages more of the underlying platform, you usually have less direct control over it. That does not mean the more managed option is always better, cheaper, or more advanced. It simply means that more of the operational responsibility belongs to the provider.

This is why the right answer is rarely “always use this service.” The better approach is usually to choose the simplest option that meets the workload’s needs.

Do not use Kubernetes just because it sounds impressive. Do not use a virtual machine just because it feels familiar. Do not use functions for a large application that really needs a more structured hosting model.

Cloud architecture is not about picking the most advanced tool. It is about picking the appropriate one.

You do not need to become an expert in every compute option before you begin. But you should understand what each one is designed for, what you are responsible for managing, and whether it fits the way your workload needs to run.

The practical question is always the same. What are you trying to run, and how much of the underlying platform do you really want to manage?