CH04-06: Compute Choice Scenario
Goal
This section applies the Chapter 4 compute model to a realistic SaaS modernization scenario.
The goal is not to produce the only possible architecture. The goal is to show how a team can explain compute choices by matching each component to its runtime shape, scaling behavior, control needs, and operating responsibility.
The durable idea is:
Mixed workloads usually need a compute portfolio, not one compute answer forced everywhere.
Scenario
A SaaS company is modernizing a customer platform.
The platform needs:
A public customer portal.
Internal APIs used by the portal and back-office tools.
Background file processing for customer uploads.
A few containerized services and workers.
One legacy Windows reporting component.
The team wants fast delivery. It has application developers and cloud engineers, but it does not yet have a large platform engineering team. It can operate managed services well. It is not ready to build and run a broad Kubernetes platform unless there is a strong reason.
The design challenge is not to pick the most powerful compute service. A strong answer gives each component the simplest compute boundary that can run it safely.
Restating the Architecture Problem
Before choosing services, translate the scenario into component questions:
| Component | Architecture Question |
|---|---|
| Customer portal | What managed web hosting model supports user-facing releases, scaling, and monitoring? |
| Internal APIs | Are these best deployed as web/API apps, containers, or a mix? |
| File processing | Is the work trigger-based, asynchronous, and short enough for event-driven execution? |
| Containerized services | Do these need container hosting, or do they truly need Kubernetes control? |
| Legacy reporting | What compatibility requirement prevents a managed or containerized option? |
| Whole platform | How will identity, networking, monitoring, deployment, and cost governance stay consistent across compute choices? |
These questions stop the architecture from becoming a product-name exercise.
Proposed Compute Model
One pragmatic first design is:
Users
|
v
Azure App Service: customer portal
|
+-- Azure App Service or Container Apps: internal APIs
|
+-- Event or queue trigger
| |
| v
| Azure Functions: file processing
|
+-- Azure Container Apps: containerized services and workers
|
+-- Private internal path
|
v
Azure VM: legacy Windows reporting component
Future option:
AKS only if Kubernetes platform control becomes justified
This model uses several compute services because the workload has several jobs. The design stays coherent because each service has a clear reason.
Customer Portal
The customer portal is a user-facing web application. It needs predictable deployments, custom domain support, authentication integration, monitoring, scaling rules, and a clear application boundary.
Azure App Service is a strong fit:
| Requirement | Why App Service Fits |
|---|---|
| Web hosting | It is designed for web apps and APIs. |
| Fast delivery | Developers can deploy application code without managing web servers. |
| Release safety | Deployment slots and CI/CD patterns can support safer releases. |
| Scaling | The app can scale up or out based on demand. |
| Operations | The team focuses on app health, configuration, identity, networking, and monitoring rather than OS administration. |
The team should still design the portal seriously. Managed hosting does not remove the need for health checks, logs, alerts, deployment rollback, secure configuration, and private access to dependencies where required.
Internal APIs
The internal APIs may fit App Service or Container Apps.
Choose App Service if the APIs are conventional application deployments, share the same runtime style as the portal, and the team benefits from a consistent web hosting model.
Choose Container Apps if the APIs are already containerized, have different runtime dependencies, or need container revision and scaling patterns without Kubernetes control.
Do not choose AKS just because the word "API" appears many times. AKS becomes attractive only if the organization needs Kubernetes as a shared platform model.
Background File Processing
The file-processing workload is asynchronous. A customer uploads a file, an event or message starts processing, and the result is stored or attached to the customer record.
Azure Functions is a strong fit when the work is focused and trigger-based:
Customer upload -> Storage or queue event -> Azure Function -> Processed result
The design should include:
Retry behavior.
Poison message or failure handling.
Idempotency so repeated processing does not corrupt data.
Monitoring across the event source, function execution, and result storage.
Limits on concurrency if downstream systems cannot handle bursts.
If processing becomes long-running, heavily customized, or container-dependent, Container Apps jobs or workers may become a better fit. The first answer should match the actual work, not the label "background job."
Containerized Services and Workers
The platform has a few services that are already packaged as containers. The team wants the consistency of container deployment, but it does not need Kubernetes APIs or cluster-level customization.
Azure Container Apps is the pragmatic starting point:
| Need | Container Apps Response |
|---|---|
| Run container images | Deploy containers without building a Kubernetes platform. |
| Host workers or APIs | Support HTTP services, background workers, and event-driven processing. |
| Scale elastically | Use scaling rules based on traffic, events, CPU, memory, or supported scalers. |
| Release versions | Use revisions and traffic splitting patterns. |
| Reduce platform overhead | Keep the team focused on services rather than cluster operations. |
AKS should remain a future option, not a default. It may become appropriate if the company grows into a platform team, standardizes on Kubernetes, needs advanced Kubernetes ecosystem tools, or runs many services that benefit from shared cluster governance.
Legacy Reporting Component
The legacy Windows reporting component is the clearest VM candidate.
It needs installed software and OS-level compatibility that do not fit the managed services cleanly. Azure Virtual Machines give the team that control.
The VM should be treated as a governed production component:
Place it in the right subscription, resource group, and network boundary.
Use private access paths rather than casual public exposure.
Monitor OS and application health.
Patch and harden the server.
Back up data and configuration.
Document recovery steps.
Tag it for ownership, cost, and lifecycle.
Create a modernization review point.
Temporary systems still create real risk. The VM is acceptable because compatibility requires it, not because it is operationally convenient.
Cross-Cutting Design
Using several compute services does not mean every team invents its own operating model.
The architecture should standardize cross-cutting concerns:
| Concern | Design Response |
|---|---|
| Identity | Use managed identities where possible and avoid long-lived secrets. |
| Networking | Keep private dependencies private and use the network patterns from Chapter 3. |
| Configuration | Separate configuration from code and protect secrets with a proper secrets service. |
| Monitoring | Use consistent logs, metrics, traces, alerts, and correlation IDs. |
| Deployment | Use repeatable pipelines, environment separation, and rollback plans. |
| Cost | Use tags, budgets, alerts, and service-specific cost reviews. |
| Governance | Apply policy, access boundaries, and ownership consistently across services. |
This is how a mixed compute architecture stays understandable.
Requirement-to-Compute Map
| Requirement | Compute Choice | Why It Helps |
|---|---|---|
| Public customer portal | App Service | Managed web hosting fits a request-driven web application. |
| Internal APIs | App Service or Container Apps | Choose based on deployment model and container need. |
| File processing | Azure Functions | Trigger-based background work can run without a dedicated always-on host. |
| Containerized services | Container Apps | Containers run with lower platform overhead than AKS. |
| Legacy Windows reporting | Virtual Machine | OS-level compatibility and installed dependencies justify the control boundary. |
| Future Kubernetes platform | AKS only if justified | Kubernetes should be chosen for platform control, not container packaging alone. |
The key is that every compute choice has an explanation. In architecture discussions, that explanation matters more than simply naming the service.
Trade-Offs
This design is intentionally pragmatic.
It favors managed services for speed and reduced operations. That helps a team without a large platform group. It also means the team must understand each service's configuration, networking, scaling, and monitoring model.
It avoids AKS at the start. That reduces platform overhead. It may also limit low-level control for workloads that later need Kubernetes-specific capabilities. The design should leave room to introduce AKS when the organization is ready and the requirement is real.
It keeps the legacy reporting engine on a VM. That reduces migration risk. It also creates patching, backup, hardening, and recovery work. The VM should have an owner and a modernization path.
Good architecture is not pretending trade-offs disappear. Good architecture makes the trade-offs visible and manageable.
Common Mistakes
Forcing all components onto one compute service.
Choosing AKS before the organization can operate it.
Leaving the legacy VM ungoverned because it is temporary.
Ignoring networking, identity, monitoring, and deployment consistency across compute services.
Choosing Functions for every background process without checking duration, state, retries, and observability.
Choosing VMs for managed web workloads because the team is used to servers.
If Someone Asks You
How would you choose compute services for a SaaS modernization?
A good answer is:
I would break the platform into compute responsibilities instead of forcing one service everywhere. The customer portal likely fits App Service. Trigger-based file processing can fit Azure Functions. Containerized workers and services can start with Container Apps unless Kubernetes control is required. A legacy component can stay on a VM if compatibility demands it, but it still needs governance and operations. I would introduce AKS only when the organization has a real Kubernetes platform requirement and the skills to operate it.
What You Should Remember
Let each component's runtime, scale, and operating needs choose the compute service.
Questions to Check Your Understanding
Why might one platform use several Azure compute services?
Which component in the scenario most clearly justifies a VM?
What would have to be true before AKS becomes the better answer?