Subchapter 25.7
references/design-refs/compute.mdMarkdown13 KBView on GitHub
Pass-2 rubric for every compute type index.md routes here. Loaded only when the
inventory contains one.
Outcome is confidence: inferred, or measured when observed utilization backed the
sizing. Never deterministic — that tier is reserved for fast-path-services.json rows,
and no compute decision is architecture-invariant.
Checked first, before any preference. An eliminator is physics or a product boundary, not a judgement, so it removes a candidate outright.
| Candidate | Eliminated when |
|---|---|
| AWS App Runner | ALWAYS. It is not a candidate for anything. No longer accepting new customers as of April 2026. Do not offer it, do not mention it as a forward-look, do not put it in a candidate list. ECS Express Mode may be mentioned only as a forward-look on the Fargate path |
| Lambda | the workload runs longer than 15 minutes per invocation — a hard ceiling, not a quota |
| Lambda | the function is a Durable Function (an orchestrator, entity, or activity binding). Durable’s state machine has no Lambda equivalent; it maps to Step Functions plus Lambda, which is a re-architecture and therefore a rubric decision, not a like-for-like |
| Lambda | the plan is not a consumption plan and always_on is true — a warm always-on process is not what Lambda is |
| Lambda | the app needs a writable local filesystem beyond /tmp, or persistent local state |
| Elastic Beanstalk | the workload is Windows Containers. EB supports Windows Server platforms and Linux Docker, not Windows containers |
| Elastic Beanstalk | more than one distinct process type must scale independently. EB scales an environment, not a process within it — this is heroku-to-aws’s non-web-formation finding, and it applies identically here |
| Fargate | the workload needs GPU. Fargate has none — route to EC2 and gpu-hpc.md |
| Fargate | the workload needs a privileged container, a kernel module, or a custom kernel |
| EKS | never eliminated, but never selected without a signal — see criterion 2 |
| EC2 | never eliminated. It is the floor: anything can run on EC2 |
Do not weigh these. Apply them in sequence and stop at the first that fires. Adding a seventh, or reordering, breaks the property that makes the outcome reproducible.
Section 1. Whatever survives is the candidate set.
What the source workload is decides more than anything the customer could tell us.
| Source | Target |
|---|---|
Microsoft.ContainerService/managedClusters | EKS — fast-path row, never reaches this file |
Microsoft.Web/serverfarms whose hosted sites are all functions on a consumption plan (Y1, FC1) | Lambda |
Microsoft.Web/serverfarms hosting web apps | Elastic Beanstalk |
Microsoft.App/containerApps / managedEnvironments | Fargate |
Microsoft.ContainerInstance/containerGroups | Fargate — a one-shot task becomes a Fargate task, not a service |
Microsoft.Compute/virtualMachines | EC2, MGN-based cutover |
Microsoft.Compute/virtualMachineScaleSets | EC2 Auto Scaling group |
Microsoft.Web/staticSites | S3 + CloudFront, plus Lambda + API Gateway for its managed functions |
Elastic Beanstalk is the App Service Plan default, and the reason is posture not preference. App Service is a managed platform the customer already pays for: AWS manages deployments, scaling, patching, and health. Fargate hands them a container lifecycle they did not previously own. Moving a PaaS workload to containers during a cloud migration changes two variables at once, and when it goes wrong there is no way to tell which one caused it.
preferences.json → design_constraints.compute_target overrides 2.2, per-resource
overrides beating the global default. This is the criterion the customer’s own answer
lives in, and it sits above feature parity deliberately: a team that has decided to run
containers has decided, and re-deriving Elastic Beanstalk from the source shape would be
overruling them.
Recognised values: elastic_beanstalk, ecs-fargate, eks-managed, ec2, lambda.
An absent preference is not a preference — fall through, do not default here.
Only reached when 2.2 and 2.3 disagree with what the workload can actually do.
| Signal | Consequence |
|---|---|
the plan runs containers (linux_fx_version is a DOCKER|… image) | Fargate over Elastic Beanstalk — the app is already a container, so the PaaS argument in 2.2 does not apply |
| VNet integration is configured on the site | any target, but the design must place it in private subnets and say so |
an app runs WEBSITE_RUN_FROM_PACKAGE | EB source bundles are equivalent; no target change, worth a note |
| a deployment slot exists | EB blue-green via swap URL, or a weighted target group on Fargate |
always_on = false on a non-consumption plan | the customer is tolerating cold starts; Lambda becomes viable if 2.2 pointed at EB |
Read the cluster’s other members via azure-resource-clusters.json and its
pattern_id. A pattern may narrow the candidate set; it may never override a
deterministic mapping — and it never reaches this file for one, because a fast-path
row does not run a rubric.
The useful case is homogeneity: a function app inside a cluster whose primary is a
Fargate-bound container workload probably belongs on Fargate rather than Lambda, because
one runtime is cheaper to operate than two. When the cluster’s pattern_status is
catalog_absent or unclassified, this criterion has nothing to say — skip it rather
than inventing an architecture.
The tiebreak, and it has a direction: prefer the target with fewer moving parts the customer has to operate. EB over Fargate over EKS, all else equal. If two candidates survive to here, they are genuinely equivalent for this workload and the operational burden is the only remaining difference.
Enforced in design-infra.md; restated here only as the thing that makes sizing
correct. The plan is the compute unit. Its apps are deployments onto it. Five web
apps on one S1 plan cost one S1. Size from the plan’s sku_name and worker_count,
never from the app count, and emit exactly one compute entry per plan carrying
hosted_app_azure_ids and sizing_source.
Default x86_64. This diverges from the rest of the repo deliberately. Graviton is
the default in gcp-to-aws and heroku-to-aws; here it is an offered optimization with its
own savings line.
The reason is base rates, not capability: Azure fleets carry Windows and .NET far more
often than GCP or Heroku fleets, and references/shared/graviton.md‘s escape path
(Windows, .NET Framework, GPU/CUDA, RDS SQL Server) fires routinely. Defaulting to
Graviton would mean walking the recommendation back on a large fraction of real estates,
and a recommendation that gets withdrawn costs more trust than one that was never made.
Offer Graviton when all hold: Linux, no .NET Framework (modern .NET on Linux is fine), no GPU requirement, and no x86-only binary dependency in the app-code signals.
Runs after a service is chosen. It is not a seventh criterion, because the six select a service and never touch capacity; adding one would break first-match-wins.
knowledge/design/appservice-eb-sizing.json
(or vm-ec2-sizing.json for VMs), confidence: inferred.az monitor metrics list) → apply the
bands and the aggressiveness slider in knowledge/estimate/rightsizing-thresholds.json,
and stamp confidence: measured citing the evidence.confidence: inferred, and
say why. A short window over a quiet fortnight is how a workload gets sized for a
trough it will leave.Sizing never revisits the service choice. If the right size for the chosen service does not exist, that is a finding for the report, not a reason to re-run the rubric.
Per schema-design-aws.md § services[]: aws_service, aws_config (instance type or
task size, count, scaling bounds, platform), confidence, rubric_applied: "compute.md",
and a rationale naming which criterion fired. “Elastic Beanstalk, because the source
is a managed App Service Plan (criterion 2.2) and no compute-target preference was
recorded” is auditable. “Elastic Beanstalk is a good fit” is not.
Implemented for App Service Plans, VMs, VMSS, container apps, container instances, and
static sites. The sizing tables now exist: knowledge/design/appservice-eb-sizing.json
for App Service plans and knowledge/design/vm-ec2-sizing.json for VMs and scale sets,
with knowledge/estimate/rightsizing-thresholds.json for the measured path. Look the size
up and stamp sizing_provenance: "table".
If a SKU is not in the table, stamp sizing_provenance: "model_prior", add a
warnings[] entry naming the SKU, and say in the rationale that the number is not sourced.
Do not write table for a row you did not find. The earlier instruction here — “state the
dev-tier default and say the table is absent rather than inventing a number” — was
unsatisfiable: with no table, the default WAS the invented number, and every size in the
committed golden turned out to be a pretrained association. gpu-hpc.md is still to land;
GPU sizes are decisions with named options in vm-ec2-sizing.json, not lookups.