worksheet № 1 basis measured prices yours, not ours opinion on your discount none

OpenShift · FinOps · capacity planning

corepair

What does this cluster actually need, and what should we therefore buy?

corepair measures real demand, converts it into a subscription count using the rules that actually apply, and produces a cost case that shows its working — including which part of a multi-year saving is a contract term and which part is just a forecast.

$pipx install corepair
Source on GitHub PyPI

Why

Two things go wrong between the cluster and the purchase order.

The count is wrong. Core-pair rounding happens per node, so ten 6-vCPU nodes cost twenty core-pairs rather than fifteen. Infra nodes are exempt only if they are tainted, not merely labelled. Meanwhile most estates reserve several times the CPU they use — and requests, not usage, are what force nodes to exist at all.

The savings case is mostly assumptions. A three-year lock gets justified with one number that quietly combines a discount differential you can hold a vendor to with assumed price growth and an assumed worse renewal discount, which you cannot.

The headline, itemised

Where a three-year saving actually comes from

32 units over three years, on the figures from a real quote. The headline saving is €15,110. Here is what it is made of.

Term differential — €6,336A contract term. Enforceable.
Avoided list growth — €3,953A forecast.
Avoided discount decay — €4,822A forecast.
58% of the headline rests on forecasts, not on the contract.

Which is not an argument against the longer term — it is an argument for converting those forecasts into terms. A written commitment to hold the renewal discount turns an assumption into an obligation. If the vendor won't commit to it, the case is weaker than the headline suggested, and now you know by exactly how much.

Sizing

Node count is set by whichever resource saturates first.

corepair plan — cumulative demand by migration wave
Through waveAppsvCPUGiBNodes (CPU)Nodes (RAM)BindingCore-pairs
wave-1 · pilot23.51411memory4
wave-2 · core systems413.55433memory8
wave-3 · remainder517.58644memory10

Each row is cumulative: it is the capacity you need in place by that wave — which is also when you should be buying it, not three years early.

Finding

Memory saturates before CPU on this shape. Adding vCPU to the node template would raise the licence count without relieving the actual constraint; adding RAM raises capacity without raising it.

Finding

Halving the quantity beats any plausible term discount. Quantity is the larger lever, and right-sizing is the thing that moves it — which is why the measuring comes before the negotiating.

The rules it encodes

Counting — each of these is a unit test
RuleWhy it matters
Core-pair = 2 cores = 4 vCPU, rounded up per nodeNode shape drives cost independently of workload
Control-plane nodes are exemptUnless the cluster is compact and they are schedulable
Infra nodes need the label and the taintAn untainted infra node can still run application pods
Bare-metal is per node, with an optional core capBreak-even against core-pairs depends entirely on density
Sizing follows the binding resourceMemory-bound estates pay for CPU-rich nodes and get nothing
Headroom and HA spares are licensed tooThe N+1 node is not free

The test file doubles as the readable specification. Disagree with a rule? The useful contribution is a failing test plus a citation — a rule with no citation is folklore, and folklore is what this replaces.

Four commands

The workflow

  1. corepair measure --prometheus …What do we run, versus what did we reserve?
  2. corepair auditWhat are we subscribing that we needn't be?
  3. corepair plan --plan plan.yamlWhat will the waves need, and when?
  4. corepair cost --pricing pricing.yamlWhat should we buy, and what is the saving made of?

It ships no prices

Vendor pricing is confidential and contract-specific. A figure copied from someone else's repository is worse than none, because it looks authoritative. The example file carries placeholders, and the tool refuses to run until you have replaced them with your own quote.

The same goes for your plan and your snapshots. Publish the schema, never the estate.

$ corepair cost --pricing pricing.yaml
error: pricing.yaml still contains
placeholder prices. Replace them with
figures from your own quote before
relying on any output.

Reproducibility

Numbers nobody can reproduce are an assertion, not a recommendation.

--snapshot-out freezes a measurement so it can be replayed, reviewed, and committed next to the proposal. The workbook it exports is built from live formulas rather than pasted results: shaded input cells, everything else recalculating from them.

That last part matters more than it sounds. A reader who disagrees with an assumption can change the cell and watch the answer move, instead of asking you to run it again and waiting a day to find out whether it mattered.