Table of contents
Finance asks it in one sentence: “would this cost us less at a hyperscaler?” You have what you need to answer — a per-namespace allocation on vks-fret-01, and a known gap between reserved and consumed capacity. Except that the question compares a price to a calculation, and the two-column table everyone expects from you is wrong before it is filled in.
This article establishes what each platform actually bills — Amazon EKS, Azure AKS, Google GKE — then what VCF Operations calculates instead. It states the four assumptions without which no comparison exists, publishes the formula with its variables, and shows which one decides the outcome. It publishes no monetary amount, and that is a choice, not a shortfall.
TL;DR
- The decision: do not produce a comparison figure, produce an interval with its assumption sheet. Three of the four platforms publish a price without a method; the fourth publishes a method without a price. These are not two levels of transparency, they are two natures of figure.
- The trade-off that costs you: establishing each platform’s billed unit takes half a day of documentation reading, and the result forbids you the four-column table everyone is waiting for.
- Monday morning: read the configured value of Expected CPU Utilization in VCF Operations. That parameter sits in the denominator of the vendor’s published base rates — it decides the private unit cost, and chances are nobody knows which value is wired in there.
This article’s figure contract
This section is for you, not for the writer: a cost article reads differently depending on what it lets itself quantify. It publishes billing structures quoted verbatim, published durations, dates and SLAs, Broadcom’s formulas as they stand, formulas posed by the article and labelled as reconstructions with their variables visible, API field names and FOCUS column names.
It refuses any amount in any currency, any savings percentage — including those published by AWS and Microsoft on their own pages — any illustrative amount even when announced as fictional, any column aligning amounts from different platforms, and any conclusion naming one platform as the cheapest.
That refusal is counter-intuitive, so it needs justifying. On 2026-08-16, the public Amazon EKS pricing page did render its amounts — but it names no region, shows no effective date and carries no caveat about regional variation. An amount without a region and a date is not a price, it is a memory. So the rule is not “the page does not load”, it is “the page is not enough”.
If your case needs an amount, collect it through an API and publish it in this shape: <amount> <currency> / <unit> — <region>, public on-demand rate collected on <YYYY-MM-DD> via <named API>, excluding contractual discounts. An amount missing any of the four is removed, not corrected. Finally, to be straight about this text’s limits: no lab was run, no bill was read.
What each platform bills
Establish the billed object first, and only then ask whether it is comparable to another.
Amazon EKS — a cluster-hour indexed on the calendar
The documentation publishes the structure in one sentence: “Amazon EKS has per cluster pricing based on Kubernetes cluster version support, pricing for Amazon EKS Auto Mode, and per vCPU pricing for Amazon EKS Hybrid Nodes.” Then the one that matters for a model: “When using Amazon EKS, you pay separately for the AWS resources you use to run your applications on Kubernetes worker nodes.” The published example names three services for a single workload line — EC2, EBS, VPC IPv4 address. Careful, that structure sentence is not exhaustive: the link list on the same page and the pricing page name a fourth axis, Amazon EKS Capabilities.
The most interesting point about the EKS model is structural, not monetary: the cluster rate depends on the age of its Kubernetes version. Standard support for 14 months after release, then extended support for 12 months “at an additional cost per cluster hour”, on by default for new and existing clusters alike. The switch has a date published in advance, with its timezone: “Billing for extended support starts at the beginning of the day that the version reaches end of standard support, in the UTC+0 timezone.” In other words, a billing line changes because time passes, without anyone deploying anything.
| Version | Upstream release | EKS release | End of EKS standard support | End of EKS extended support |
|---|---|---|---|---|
1.36 |
2026-04-22 | 2026-06-02 | 2027-08-02 | 2028-08-02 |
1.35 |
2025-12-17 | 2026-01-27 | 2027-03-27 | 2028-03-27 |
1.34 |
2025-08-27 | 2025-10-02 | 2026-12-02 | 2027-12-02 |
Note the gap: kubernetes.io puts the end of life of 1.35 at 2027-02-28, EKS the end of standard support at 2027-03-27. A managed provider’s lifecycle is not the upstream lifecycle — and that is an assumption item in its own right.
Azure AKS — a management tier, not a resource
AKS bills three cluster management tiers, and the free tier’s description says exactly what is free: “Free cluster management. Pay as you go for consumed resources.”
| Tier | What is published | Nodes | SLA |
|---|---|---|---|
| Free | “Includes all current AKS features. […] No financially backed uptime SLA.” | ≤ 1,000 | best-effort |
| Standard | “Uptime SLA enabled by default. Higher reliability profile.” | ≤ 5,000 | 99.95% with zones, 99.9% without |
| Premium | Microsoft maintenance beyond community support, 24-month long-term support | ≤ 5,000 | 99.95% with zones, 99.9% without |
So what an AKS tier buys is not compute: it is an availability commitment and a support duration. Consumed resources are still billed separately in all three tiers.
Google GKE — two billing models inside the same cluster
Pod-based billing covers “Pods that run on the container-optimized compute platform in Autopilot clusters or Standard clusters” as well as “Pods that select the Balanced or Scale-Out built-in ComputeClasses in Autopilot clusters”. Node-based billing covers the rest: “Pods that select specific hardware, such as Compute Engine machine series or hardware accelerators, use a node-based billing model. In this model, you pay for the underlying hardware and a node management premium.”
Heavy consequence: two Pods in the same cluster can fall under two different billed units, depending on what their spec asks for. The cost unit is a property of the Pod, not of the cluster — a GKE model reasoning “per node” is wrong for part of the workloads. An acknowledged gap: the GKE pricing page came back truncated on loading, twice. Neither the node management premium nor an Autopilot / Standard comparison could be established; this article builds neither.
VCF — it does not bill, it calculates
Ten cost drivers are published for the vCenter infrastructure type: Server Hardware: Traditional, Server Hardware: Hyper-Converged, Storage, License, Applications, Maintenance, Labor, Network, Facilities, Additional Cost. The mechanism fits in one sentence: “The total cost set by you is distributed across resources in the data center.” Three of those drivers have no equivalent inside a public instance price — Labor, Facilities, Network. They come back as the fourth assumption.
The VCF calculation chain, stage by stage
Stage 1 — the input is an amount you enter, the total of the ten cost drivers, then distributed across data centre objects.
Stage 2 — hardware depreciates, with a published formula: “Yearly straight line depreciation = [(original cost - accumulated depreciation) / number of remaining depreciation years]”. Two methods are offered, Straight Line and Max of Double or Straight, “you can set the depreciation period from two to five years”, and “The default discount % value is zero.”
Stage 3 — the base rate, with the utilization rate in the denominator: “Per GHz CPU base rate = (Cluster Total CPU Cost) / (Expected CPU Utilization * Cluster CPU Capacity in gHZ)”, and its memory equivalent. The origin of the expected percentages is published — “These percentages are arrived based on historical actual use of clusters” — as is their period: “The base rates are monthly rates.”
Stage 4 — aggregation up to Kubernetes: “VCF Operations calculates the cost for VKS cluster, supervisor cluster, and Kubernetes node, by aggregating the cost of the supporting VMs.” So the Kubernetes cost in VCF Operations is an infrastructure cost pushed up, not a consumption cost pushed down: the exact opposite of OpenCost’s path, described in OpenCost: seeing before acting on Kubernetes spend. Both produce a figure per Kubernetes object; they do not build it the same way round.
The 9.1 release notes add costing “across your entire Kubernetes ecosystem, including nodes, clusters, vSphere namespaces, projects, and organizations” and chargeback “specifically for VMware Kubernetes Service (VKS) nodes in addition to the traditional VM pricing”.
Three gaps to own on the VCF side
The published chain stops at the node and the vSphere namespace: no Pod, no container. The method for attributing supporting-VM cost to a vSphere namespace, a project or an organisation is not published — the objects are named, the split is not. Finally, the 9.1 pricing cards page assigns cards only to vCenters or Clusters: the VKS chargeback configuration announced in the release notes was not found in the documentation that was loaded. This article describes what is exposed, not a procedure it has not read.
The legitimate table: properties, not amounts
The columns are platforms, but the rows are properties of the model. That is what makes the table defensible — and why it has no price row.
| Amazon EKS | Azure AKS | Google GKE | VCF / VCF Operations | |
|---|---|---|---|---|
| Billed object | the cluster, per hour | the management tier | the Pod or the node, depending on the Pod | not billed — cost entered, then distributed |
| What triggers the amount | the cluster existing + the age of its version | the tier you choose | the Pod spec | writing the cost drivers |
| What is included | managed control plane; control-plane-side traffic absorbed | full features in all 3 tiers; SLA from Standard up | hardware + management premium in the node model | nothing — everything is a driver |
| Billed separately | EC2, EBS, VPC IPv4, customer-side traffic, Auto Mode, Hybrid Nodes, Capabilities | every consumed resource | depends on the model applying to the Pod | not applicable |
| Who sets the amount | the provider | the provider | the provider | the operator |
| What it depends on | region, version, duration | tier, region | applicable model, hardware | depreciation, expected utilization, cost ratio |
| Published granularity | billed resource | billed resource | Pod (Pod model) | node / vSphere namespace |
| Published method | no — a rate, not a formula | no | no | yes — base rates and aggregation |
The last row inverts the intuition. Hyperscalers publish a price without a method; VCF publishes a method without a price. A price needs no method: it is enforceable, it is what will be invoiced. A method without a price is not — it only becomes a figure once you have poured your own amounts into it. Hence the non-commensurability in one sentence: an EKS figure is the outcome of a contract, a VCF figure the outcome of a calculation whose inputs the operator supplies. Putting them side by side without saying so is comparing a bank statement to a budget.
The one honest bridge: commitment against depreciation
All three hyperscalers publish a commitment mechanism. AWS: “Savings Plans provide savings beyond On-Demand rates in exchange for a commitment of using a specified amount of compute power (measured per hour) for a one or three year period”, with the rate locked for the term. Azure applies the discount automatically by SKU, region and scope. GCP commits on a minimum hourly spend or on a quantity of eligible resources, and publishes the clause that defines the risk: “Any overage usage that takes your hourly spend amount over your committed amount is charged at the on-demand rate.”
A multi-year commitment is not a discount: it is a transfer of risk in exchange for a lower rate, exactly the structure of buying hardware depreciated over two to five years. So the only naturally commensurable comparison is not “on-demand against private”, it is commitment against depreciation — with the same penalty for forecasting badly: committed capacity you never consume on one side, an occupancy rate that never rises on the other.
The four assumptions, the formula, the sensitivity
These assumptions are not an academic frame bolted onto a product: two of them are published parameters of VCF Operations, so they are arguable on evidence rather than on opinion.
# assumption sheet — ⚠️ this block is NOT a Kubernetes manifest: no apiVersion, no kind.
# It travels with every figure this model produces. A figure without its sheet is removed, not corrected.
assumptions:
- id: H1
name: "hardware depreciation period"
variable: REPLACE_WITH_DEPRECIATION_YEARS
published_bound: "two to five years — Cost Settings for Financial Accounting Model"
published_method: "Straight Line | Max of Double or Straight"
applies_to: "the hardware share only; license, maintenance, labor, facilities stay recurring"
- id: H2
name: "expected utilization rate of the private platform"
variable: REPLACE_WITH_UTILIZATION_RATE
published_status: "Expected CPU/Memory Utilization sits in the DENOMINATOR of the published base rates"
note: "private unit cost varies as 1/H2; the public rate does not vary with H2"
- id: H3
name: "lifetime and workload profile"
variable: REPLACE_WITH_WORKLOAD_PROFILE
values: [permanent, elastic, seasonal, bounded_project]
note: "permanent → commitment vs depreciation; elastic → on-demand rate vs capacity already bought"
- id: H4
name: "cost scope retained on each side"
variable: REPLACE_WITH_SCOPE
private_list: "the ten cost drivers, including Labor, Facilities and Network"
public_list: "what a reservation does not cover; what EKS bills separately"
rule: "an item present on one side and absent on the other is added to both sides, or removed from both"
The formula below is a reconstruction: it chains official pages together, it is published nowhere in this form, and none of its variants produces a publishable result. It produces an interval, with its sheet attached.
# public side — unit cost of a vCPU-hour on a managed cluster
PUBLIC_UNIT_COST_VCPU_HOUR =
( REPLACE_WITH_NODE_HOURLY_RATE
+ REPLACE_WITH_CLUSTER_HOURLY_FEE / REPLACE_WITH_NODES_PER_CLUSTER
+ REPLACE_WITH_ATTACHED_STORAGE_HOURLY
+ REPLACE_WITH_DATA_TRANSFER_HOURLY
+ REPLACE_WITH_MANAGED_ADDONS_HOURLY )
/ REPLACE_WITH_NODE_VCPU_COUNT
# every term ! come from a dated lookup, on REPLACE_WITH_REGION, at REPLACE_WITH_LOOKUP_DATE
# REPLACE_WITH_CLUSTER_HOURLY_FEE depends on the cluster version (standard or extended support)
# ∴ this term moves with the calendar, not with the load
# private side — the chain published by VCF Operations, rewritten in variables
CLUSTER_COMPUTE_COST = TOTAL_INFRA_COST - STORAGE_COST - DIRECT_VM_COST
YEARLY_STRAIGHT_LINE_DEPRECIATION =
( REPLACE_WITH_HARDWARE_CAPEX - ACCUMULATED_DEPRECIATION ) / REMAINING_YEARS
# REMAINING_YEARS bounded by REPLACE_WITH_DEPRECIATION_YEARS ∈ [2..5]
CPU_BASE_RATE_PER_GHZ = CLUSTER_CPU_COST / ( REPLACE_WITH_UTILIZATION_RATE * CLUSTER_CPU_CAPACITY_GHZ )
RAM_BASE_RATE_PER_GB = CLUSTER_RAM_COST / ( REPLACE_WITH_UTILIZATION_RATE_MEM * CLUSTER_RAM_CAPACITY_GB )
VKS_NODE_COST = SUM( cost of the VMs supporting the node )
VKS_CLUSTER_COST = SUM( VKS_NODE_COST )
# ⚠️ the published chain stops here: no Pod, no container
# the break-even point is a RATE, not a saving
BREAK_EVEN_UTILIZATION_RATE =
PRIVATE_UNIT_COST_AT_100_UTILIZATION / PUBLIC_UNIT_COST_VCPU_HOUR
Without a single amount, these formulas give a direction of variation, and it is decisive. The private curve against utilization is a hyperbola: unit cost varies as 1/H2. The public line is horizontal — an instance rate does not change because your cluster is half empty. So an under-occupied private cluster is not “a bit more expensive”: it gets more expensive the emptier it is, with no floor. That is what rightsizing with VPA and KRR makes measurable: capacity reserved and never consumed degrades H2.
Sensitivity to H1 is decreasing but floored: H1 only covers the hardware share, and license, maintenance, labor and facilities are recurring. A model that only becomes favourable to private by stretching depreciation postpones a decision, it does not justify one. Neither curve is a measurement: they are the shapes imposed by the published formulas. You can know a model’s direction of variation without knowing a single one of its amounts.
Collecting it yourself: the three APIs and the FOCUS vocabulary
Two values are fixed first and never move again: REPLACE_WITH_REGION and REPLACE_WITH_LOOKUP_DATE. A comparison carries a region and a date, the way a bill carries a month.
# AWS — Price List Query API, GetProducts action; SigV4-signed request ∴ AWS account required
aws pricing get-products \
--service-code AmazonEC2 --format-version aws_v1 --max-results 100 \
--filters \
Type=TERM_MATCH,Field=instanceType,Value=REPLACE_WITH_INSTANCE_TYPE \
Type=TERM_MATCH,Field=operatingSystem,Value=REPLACE_WITH_OS \
Type=TERM_MATCH,Field=tenancy,Value=Shared
# keep: terms.OnDemand[].priceDimensions[].pricePerUnit, unit, description,
# effectiveDate, publicationDate, and the product attribute location carrying the region in clear
# ⚠️ no regional filter field name is published: read the region from the attributes,
# ⊥ invent a plausible field name
# Azure — Retail Prices API, unauthenticated
curl -s -G "https://prices.azure.com/api/retail/prices" \
--data-urlencode "api-version=2023-01-01-preview" \
--data-urlencode "\$filter=serviceName eq 'Virtual Machines' \
and armRegionName eq 'REPLACE_WITH_REGION' \
and armSkuName eq 'REPLACE_WITH_INSTANCE_TYPE' \
and priceType eq 'Consumption'"
# case-sensitive since 2023-01-01-preview; 1,000 records max per page + NextPageLink;
# commitment rates are only returned on this preview version
# GCP — Cloud Billing Catalog API, services.skus.list
curl -s "https://cloudbilling.googleapis.com/v1/services/REPLACE_WITH_SERVICE_ID/skus?currencyCode=REPLACE_WITH_CURRENCY" \
-H "Authorization: Bearer REPLACE_WITH_ACCESS_TOKEN"
# filter client-side on serviceRegions[] == REPLACE_WITH_REGION
# rate = tieredRates[].unitPrice.units + tieredRates[].unitPrice.nanos / 1e9
# startTime/endTime must sit within a single calendar month
Microsoft publishes a currency caveat worth relaying: “The currency that Microsoft uses to price all Azure services is USD. […] Other non-USD prices returned by the API are for your reference to help you estimate budget expenses.” An amount returned by that API in another currency is a conversion estimate, not a rate.
What remains is saying which cost you are talking about, and FOCUS gives the exact words. Specification 1.4, ratified on 2026-06-04, publishes: “BilledCost represents the cash-based view […]. EffectiveCost represents the accrual-based view: costs recognized when resources are consumed, services are used, or contract commitments are recognized. ListCost provides the pre-discount baseline. ContractedCost reflects pricing after negotiated discounts.”
| Figure | FOCUS column | Where you meet it |
|---|---|---|
| what OpenCost shows by default — “the on-demand list pricing” | ListCost |
article 1 |
| what reconciliation with the negotiated bill produces | ContractedCost, then EffectiveCost |
article 1, commercial tier |
| what you see on your invoice | BilledCost |
this article |
| what a commitment changes | CommitmentDiscount* columns |
this article |
Two honest clarifications on FOCUS and VCF. The fact first: a post on Broadcom’s VCF blog, dated 2026-06-03, announces “we are aligning VCF 9.1 with the FinOps Open Cost & Usage Specification (FOCUS)” — but no product documentation page that was loaded confirms it, and no FOCUS version is named there, while the FOCUS site’s vendor adoption page returned no list. So one writes neither “VCF is FOCUS-compliant” nor “VCF produces no FOCUS dataset”: one writes the dated announcement and the absence of confirmation.
The deeper limit next, which will survive any product update: FOCUS normalizes the schema, not the nature of the figure. A perfectly conformant FOCUS export of a VCF cost would carry a BilledCost column — but nobody invoiced that amount: it was entered as cost drivers, then distributed. The columns would be identical, the meaning would not.
Pitfalls
Counting the utilization rate twice
The most expensive trap in the model, and it comes straight out of the published formula. The VCF base rate is already divided by the expected utilization rate: “CPU base rate is then prorated by dividing the CPU base rate by expected CPU use percentage”. An analyst who starts from that base rate and then applies their own occupancy correction applies the divisor twice — the private unit cost comes out inflated and the conclusion tips the wrong way, without anyone spotting the error, because each step taken alone is correct. Pick your entry point: either the cluster compute cost and you divide yourself, or the published base rate and you divide no more. Never both.
- The example amount inside API documentation. Response examples contain real amounts, stale by construction:
GetProductscarries aneffectiveDatefrom 2017, the Azure exampleseffectiveStartDatevalues from 2019 to 2021. - The vendor’s savings percentage. AWS and Microsoft each publish a maximum savings figure on their commitment pages. Those figures compare a commitment rate to the on-demand rate of the same provider, on a permanently running workload: that is not a gain against your current state. A gain is told as a mechanism — a node removed, capacity not bought — never as a percentage.
- Comparing a discounted rate on one side with a public rate on the other. A public
ListCostagainst a private cost that contains real hardware and license discounts mostly measures your negotiating position. Compare the same FOCUS column on both sides, and say which one. - The asymmetric scope. VCF exposes Labor, Facilities and Network; an Azure reservation “doesn’t cover additional software, Windows, networking, or storage charges”. The ten drivers on one side and an instance rate on the other is a complete cost against a partial one — as wrong as its mirror image.
- Attributing to VCF a granularity it does not publish. The chain stops at the node and the vSphere namespace, and the published method is an aggregation of supporting VMs, not an allocation by consumption. Symmetrically, do not write “VCF sees nothing on the Kubernetes side”: that has been false since 9.1.
- The wired-in utilization rate nobody chose. The expected percentages “are arrived based on historical actual use of clusters”, but the documentation does not say who sets them, over which window, or whether they can be changed. Read the configured value; do not infer a window.
- The model that stays correct and goes stale. A rate changes without notice, a version tips into extended support, a depreciation period ends — the model signals nothing, it keeps calculating. Hence the expiry date written into the sheet.
Conclusion
The question as asked has no single answer, and saying so is a result, not an admission of failure. What you hand back to finance is not two columns: it is three questions in return — over what period do we depreciate, at what utilization rate do we run, and did we put the same items on both sides? An organisation that can answer those three knows how to build its own figure, and how to defend it.
The billed unit comes first
A cluster-hour, a management tier, a Pod request and depreciated hardware are not four values of one variable.
H2 decides the outcome
Private unit cost varies as 1/utilization; the public rate does not move as your cluster empties. The vendor says so before we do.
The deliverable is a pair
A figure and its sheet — region, date, API, four assumptions, scope, expiry. Separated from its sheet, a figure is withdrawn.
The loop closes back on the start of the series for a mechanical reason: the utilization rate that decides the comparison is exactly the quantity that per-namespace allocation makes readable and that rightsizing moves. Multi-cloud comparison is not the step after measurement — measurement is what makes it possible.
Related reading on the blog
VCF 9.1: the infrastructure efficiency behind the -40% TCO claim applies the same method to a vendor figure and concludes it is a conditional ceiling. See also The new VCF 9 architecture explained for architects, VCF 9.1: self-service Kubernetes for the per-project delegation that per-team showback depends on, and VKS Day-2 Ops: lifecycle and upgrades for the version lifecycle — which, as we have just seen, is also a cost item. Back to the start of the series: OpenCost: seeing before acting on Kubernetes spend and Rightsizing Kubernetes workloads with VPA and KRR.
Get the next one by email
New articles and series, sent when they are published. No other mail.



