E 会計/ファイナンス・コスト効率 — GKE の CUD(確約利用割引)購入稟議を「解約できない3年の支払義務」として書き直す(ピーク24台の3年リソースCUD × SUD を無視した「定価×55%」 × 適正化と Autopilot 移行で約束が宙に浮く → 持続曲線と損益分岐稼働率 × 床だけ先に長期で買う段階購入)

2026-09-25 金曜 金曜 E: 会計/ファイナンス・コスト効率 ★★★★☆ CUD / SUD / flexible CUD 持続曲線 / 損益分岐稼働率 / 段階購入

概要

📜

割引ではなく、解約できない約束

約束した分は使わなくても毎月払う。評価は「約束額 − 約束しなかった場合の請求額」。

🏷️

今払っている値段と比べる

N2 は常時稼働なら SUD で既に20%引き。「定価×55%」は二重に数えている。

📉

層ごとに損益分岐稼働率と比べる

k 台目が月の何%動くか。3年リソースなら48%、1年flexなら87%を下回る層は買わない。

🪜

減らしてから、床だけ先に、段階的に

適正化が先。どのシナリオでも残る量だけ長期で買い、残りは判断日の後に買う。

問題

MOps 販促システムチームの後輩エンジニアが、GKE Standard クラスタ(N2 ノード、asia-northeast1)のノード費を下げるため、Compute Engine の 3年リソースベース CUD を購入したいと稟議を上げてきた。あなたはシニアエンジニアとしてレビューを頼まれた。CUD は「一定量を1年または3年使うと約束する代わりに割り引く」契約で、途中解約できない。

ノードの使われ方(2026年9月の Billing export から集計。n2-standard-8 の台数)

日の種類日数/月9〜24時(15h)1〜5時(4h、夜間バッチ)それ以外(5h)
通常日24.416台14台10台
セール日(月2回×3日)6.024台22台18台

決まっている予定と、決まっていない予定

時期内容確度
2026-12末(M3末)リソース要求の適正化: 床 10→7台、昼の上乗せ +6→+4台、セールの上乗せ +8→+6台確定(ステージングで実測済み)
2026-12末(M3末)夜間バッチ(4台×4h)を GKE Autopilot へ移行確定
2027-10(M13)販促 API 本体も Autopilot へ。移すと Standard に残るのはシステム用の2台だけ50%(2027-09 に判断)
2027-09レコメンド API を SaaS に置き換えるか(9/17 の build vs buy)。置き換えると昼の上乗せ分が消える未定

制約・前提条件

  • 1か月 = 30.4日 = 729.6時間。n2-standard-8 のオンデマンド単価 $0.50/h 仮定
  • 今の請求書には N2 の 継続利用割引(SUD) が自動で付いている。9月の SUD は −$986 導出
  • 同じ負荷を Autopilot で動かしたときの費用は Standard ノード費の 0.9 倍 仮定。為替 150円/$、資本コスト 年8% 仮定
  • 割引率 公式(参照日 2026-09-25): リソースベース CUD(N2・リージョンとプロジェクトに固定)1年37%/3年55%。Compute flexible CUD(金額コミット、Compute Engine・GKE Standard/Autopilot・Cloud Run 共通、リージョン横断)1年28%/3年46%。N2 の SUD は最大20%
  • SUD は CUD でカバーされた使用には付かない。リソースベース CUD は Autopilot の Pod には効かない。どの CUD も購入後は解約できない 公式
  • 読み手は CFO と開発部長。CUD は毎月請求で前払いはない

期待する回答形式: (1) 問題点の列挙(7点)(2) 試算コード(Python 3.12+、Google スタイル docstring・名前付き定数・インラインコメント)(3) 実行例 (4) 推奨案と稟議の書き直し (5) 購入後の監視と止め方 (6) 迷った案と採らなかった理由

悪い稟議 (Before)

この稟議には 7つの問題 が隠れています。見つけてから先へ進んでください。
後輩の稟議メモ

件名: GKE ノード費 55% 削減のため 3年 CUD を購入したい

販促システムの GKE Standard クラスタ(N2, asia-northeast1)の9月のノード費は定価で月 $5,835(約88万円)でした。Google Cloud の資料では 3年コミットで最大 55% 割引になるので、ピーク時(セール日の昼)の 24 ノード分を 3年 CUD で購入すれば、

削減額 = $5,835 × 55% = $3,209/月 → 3年で $115,537(約1,733万円)

の削減になります。セール時にノードが足りなくなるのが怖いので、ピークに合わせました。来週中に購入手続きをしたいので承認をお願いします。(費用が減る話なので、予算申請は不要と考えています)

問題点サマリー(7点)
1-2比べる値段と量 — SUD 後の実額でなく定価に55% / ピーク24台で約束(24台目は稼働12%)
3-4時間軸 — 確定済みの適正化・バッチ移行を無視 / Autopilot 移行でリソースCUDが効かなくなる
5-7意思決定の作法 — 解約不能総額が稟議に無い / シナリオ・期待値なし / 一括購入で監視・止め方なし
試算すると、Bad 案は「コミットなし」に比べて 36か月で +295万円(移行なし)〜 +1,259万円(移行あり)の損。「−1,733万円」は符号から逆。

ヒント(段階的開示)

ヒント1 — 方向性
「55%引き」の55%は何に対する割引か、そしてその値段を今払っているかを確かめる。次に、24台目のノードが月のうち何時間動いているかを数える。CUD は「使った分を割り引く」のではなく「約束した分を、使わなくても割引価格で払う」契約である。
ヒント2 — アプローチ
  • 持続曲線(ノードを稼働時間の長い順に1台ずつ積み上げた図)を描き、k 台目の稼働率 uk を出す
  • k 台目を約束して得をする条件は「約束の単価 < 約束しなかったときの単価」。3年リソースなら 0.45 < SUD 後の単価比
  • 時間軸を足す。M3 末の適正化と Autopilot 移行、M13 の移行判断で曲線そのものが変わる。今日の曲線で最適化した量は、来年の曲線では過剰になりうる
  • リソースベースは「N2・東京・このプロジェクト」に縛られる。flexible は金額で約束し、Standard でも Autopilot でも使える
  • 稟議に載せる数字は削減見込みだけではない。解約できない支払総額も載せる
ヒント3 — 骨格
今日の持続曲線(M1〜M3)
  1〜10台目: 稼働率100%   → SUD後の単価比 0.80
  11〜14台目: 83.3%       → 0.84
  15〜16台目: 69.9%       → 0.88
  17〜18台目: 19.7%       → 1.00(SUDなし)
  19〜24台目: 15.6%/12.3% → 1.00
損益分岐稼働率(SUD込み): 3年リソース 48%、1年リソース 72%、3年flex 60%、1年flex 87%
→ 今日だけ見ても、17台目より上はどの契約でも赤字

シナリオ: S1(API は Standard のまま)/ S2(M13 に Autopilot へ)を各50%
案ごとに 36か月の請求額を計算し、「コミットなし」との差の期待値と、悪い方のシナリオでの差を並べる
床(どちらのシナリオでも消えない量)= システム用 N2 2台 + API の最低負荷(オンデマンド換算 $2.25/h)

問題点分析(7点)

#問題点分類何が起きているか(数字)改善方法
1定価×55%で計算比べる値段今の請求は SUD 後 $4,849。常時稼働の台への3年CUDの上乗せは 1−0.45/0.80 = 43.75%(1年なら21%)。SUD と CUD は重ならないSUD 後の実額と比べる
2ピーク24台で約束比べる量24台目の稼働率12.3%。約束の利用率は今日で67%、削減は $909/月(主張の28%)。CUD は容量を予約しない持続曲線 × 損益分岐稼働率で量を決める
3確定済みの削減を無視時間軸M4 以降は Bad 案が「なし」より月 $678 高い(利用率45%)。適正化だけで月 −$1,368減らしてから買う
4移行で CUD が効かなくなる時間軸S2 では M13 以降、約束の8%しか使えず月 $7,010(なしなら $3,654)移行しても使える flexible で床を押さえる
5解約不能総額が無い意思決定解約できない支払総額 $141,834(約2,128万円)を「予算不要」としている削減見込みと並べて総額を稟議に載せる
6単一点推定意思決定36か月で S1 +295万円、S2 +1,259万円、期待値 +777万円の損(現在価値でも +668万円)シナリオ × 期待値 × 最悪ケース × 現在価値
7一括購入・監視なし意思決定次の判断日も、利用率・カバー率のしきい値も無い段階購入。更新・追加を判断日に揃える

持続曲線・月額推移・契約の層(SVG)

① 持続曲線 — k 台目のノードは月の何%動いているか 黄 = 今日(M1〜3)/青緑 = 適正化・バッチ移行後(M4〜) 分岐線より下の台を約束すると、約束しないより高くつく 0%25%50%75%100% 1271011161724 3年リソースの分岐 48%1年リソースの分岐 72% k 台目(稼働時間の長い順に積んだノード) Bad: 3年リソース 24台(今日の約束利用率 67%、M4以降 45%)res 2台flex $2.25/hM13 に判断 ② 月額の推移 — S2(M13 に API を Autopilot へ移行) リソースベース CUD は Autopilot Pod に効かない(公式) → 移行した月から、約束の大半が使われなくなる $0$2,000$4,000$6,000$8,000M1M4M13 移行M36Bad $7,010/月(約束の8%しか使えない)なし $3,654G $2,269(約束の利用率93〜100%)M4〜: Bad > なしコミットなしBadG(推奨)

左: 棒の高さが「k 台目が月の何%動いているか」。緑の破線(3年リソース 48%)より低い台を約束すると、約束しないより高くつく。Bad は24台すべてを約束している。右: 移行ありのシナリオでの月額。Bad は M4 以降「なし」より高く、M13 以降は約2倍になる。

③ 使用量の層ごとに契約を割り当てる(G: 段階購入) システム用 N2 2台 3年リソース 55% / M1 購入 API の最低負荷 $2.25/h 3年 flexible 46% / M1 購入 昼の上乗せ $1.75/h(稼働率83%) 3年 flexible / 2027-09 の判断後に買う セールの山(稼働率20%以下) 約束しない(オンデマンド+SUD) S1: API は Standard のまま res 2台 → システム用ノード flex → Standard の N2 に充当 36か月で −479万円 S2: API を Autopilot へ(M13) res 2台 → システム用ノード(残る) flex → Autopilot Pod に充当(移っても使える) 36か月で −630万円 Bad: 全層を 3年リソースで N2・東京・このプロジェクトに固定 セールの山まで約束(24台目は稼働12%) S2 では約束の 8% しか使えない S1 +295万円 / S2 +1,259万円 解約不能総額 2,128万円 主張「−1,733万円」は符号から逆 原則: 長く深い契約は「どのシナリオでも残る層」だけ。移行で消えうる層は、判断が出てから買う。稼働率が分岐点を下回る層は買わない。

使用量を層に分け、層ごとに契約を選ぶ。長く深い契約(3年リソース)はどのシナリオでも残る2台だけ。移行しても使える量は flexible。消えうる層は判断日の後に買う。

模範解答

黄色 = 設計意図のコメント、緑 = Bad の問題番号を直した箇所、赤 = 比較のために残した Bad 案。

Before — 定価に割引率を掛けるだけ
list_price = 5_835          # ① SUD 後の実額 $4,849 ではない
discount   = 0.55            # ① 常時稼働の台でも上乗せは 43.75%
commit     = 24              # ② ピーク。24台目は月の12%しか動かない

saving = list_price * discount   # ②③④ 使用量が約束を下回る月を考えない
print(saving * 36)               # ⑥ 1点推定。シナリオも現在価値も無い
# → 115,537(約1,733万円の削減)
# ⑤ 解約不能総額 141,834 はどこにも出てこない
# ⑦ 次の判断日・監視指標なし
After — 約束額 − 約束しなかった場合の請求
# 1. 層ごとの稼働率 u_k を持続曲線から出す
u = hours_with_at_least_k_nodes / MONTH_HOURS

# 2. 約束しなかった場合の単価は SUD 後
no_commit = sud_ratio(u)        # 1.0 → 0.80
commit_ok = (1 - d) < no_commit  # 3年res: 0.45

# 3. 月ごとに曲線を切り替える(M4 適正化 / M13 移行)
profile = profile_for(month, scenario)

# 4. 請求 = 約束の固定料 + 約束を超えた分(SUD 後)
bill = fee + autopilot_on_demand + n2_after_sud

# 5. 2シナリオ × 36か月 → 期待値・最悪・現在価値
# 6. 解約不能総額 = 月額固定料 × 12 × 年数
obligation = monthly_fee * 12 * years
# → Bad: S1 +$19,652 / S2 +$83,919(損)
# → G  : S1 −$31,939 / S2 −$41,971

cud_decision.py(Python 3.12+、標準ライブラリのみ)。緑の行の右に、直した Bad の問題番号を表示している(コピーには含まれない)。

"""GKE の CUD(確約利用割引)購入案を、2つの移行シナリオ × 36か月で比較する.

前提の出所ラベル:
    [公式] Google Cloud ドキュメント(参照日 2026-09-25)
    [仮定] 本問の設定値。実務では Billing export の SKU 単価・使用量に置き換える
"""
from __future__ import annotations

from dataclasses import dataclass
from typing import Literal

# ── 時間 ──────────────────────────────────────────────
NORMAL_DAYS = 24.4                  # [仮定] 1か月のうち通常日
SALE_DAYS = 6.0                     # [仮定] 月2回×3日のセール日
MONTH_HOURS = (NORMAL_DAYS + SALE_DAYS) * 24   # 729.6h(365/12日の丸め)
HORIZON_MONTHS = 36                 # 3年CUDの期間に合わせた評価期間
MIGRATION_MONTH = 13                # S2 で販促APIが Autopilot へ移る月

# ── 単価と割引率 ──────────────────────────────────────
NODE_PRICE_USD_H = 0.50             # [仮定] n2-standard-8 オンデマンド単価
AUTOPILOT_TO_NODE = 0.9             # [仮定] 同じ負荷の Autopilot 費 ÷ Standard ノード費
RESOURCE_CUD = {1: 0.37, 3: 0.55}   # N2 リソースベース。3年は[公式]"up to 55%"、1年37%は価格表の値として
                                    # 広く引用される値 → 購入前に Billing の SKU で確認
FLEX_CUD = {1: 0.28, 3: 0.46}       # [公式] Compute flexible CUD(GKE/Cloud Run/GCE 共通)
                                    # 本コードではコミット額を「オンデマンド換算 $/h」で表す
# [公式] N2 の SUD: 月の稼働率 0-25/25-50/50-75/75-100% の区間に掛かる基本料金比
N2_SUD_BANDS = (1.0, 0.8678, 0.733, 0.60)
ANNUAL_DISCOUNT_RATE = 0.08         # [仮定] 資本コスト(現在価値の計算用)
USD_JPY = 150                       # [仮定] 稟議用の換算レート

AP = NODE_PRICE_USD_H * AUTOPILOT_TO_NODE   # Autopilot 1ノード相当の $/h

# 1日を時間帯ブロックに分ける: (時間数, Standard の N2 ノード数, Autopilot の $/h)
Block = tuple[float, float, float]
Profile = dict[str, list[Block]]

PHASE0: Profile = {  # M1-3: 現状(夜間バッチも Standard 上)
    "normal": [(15, 16, 0.0), (4, 14, 0.0), (5, 10, 0.0)],
    "sale":   [(15, 24, 0.0), (4, 22, 0.0), (5, 18, 0.0)],
}
PHASE1: Profile = {  # M4-: 適正化(床10→7台)+ 夜間バッチを Autopilot へ
    "normal": [(15, 11, 0.0), (4, 7, 4 * AP), (5, 7, 0.0)],
    "sale":   [(15, 17, 0.0), (4, 13, 4 * AP), (5, 13, 0.0)],
}
PHASE2: Profile = {  # S2 の M13-: 販促APIも Autopilot へ。Standard はシステム用2台だけ
    "normal": [(15, 2, 9 * AP), (4, 2, 9 * AP), (5, 2, 5 * AP)],
    "sale":   [(15, 2, 15 * AP), (4, 2, 15 * AP), (5, 2, 11 * AP)],
}


@dataclass(frozen=True, slots=True)
class Commitment:
    """1本の CUD 契約.

    Attributes:
        kind: "resource"(N2・東京リージョン固定)か "flex"(支出額、サービス横断)。
        start_month: 購入月(1 始まり)。
        years: 1 または 3。途中解約はできない [公式]。
        amount: resource はノード台数、flex はオンデマンド換算の $/h。
    """

    kind: Literal["resource", "flex"]
    start_month: int
    years: Literal[1, 3]
    amount: float

    def is_active(self, month: int) -> bool:
        return self.start_month <= month < self.start_month + 12 * self.years

    @property
    def discount(self) -> float:
        return (RESOURCE_CUD if self.kind == "resource" else FLEX_CUD)[self.years]

    def monthly_fee(self) -> float:
        """使っても使わなくても払う月額(割引後)."""
        list_per_hour = self.amount * NODE_PRICE_USD_H if self.kind == "resource" else self.amount
        return list_per_hour * (1 - self.discount) * MONTH_HOURS

    def total_obligation(self) -> float:
        """解約不能な支払総額。稟議にはこの額を載せる."""
        return self.monthly_fee() * 12 * self.years


def sud_ratio(utilization: float) -> float:
    """稼働率 u のノード1本分が払う額を「フル月オンデマンド」に対する比率で返す.

    Args:
        utilization: 月の稼働率(0.0〜1.0)。

    Returns:
        例: 1.0 → 0.80(最大20%引き)、0.5 → 0.4669。
    """
    ratio, left = 0.0, utilization
    for band_rate in N2_SUD_BANDS:
        used = min(left, 0.25)
        ratio += used * band_rate
        left -= used
        if left <= 0:
            break
    return ratio


def _blocks(profile: Profile):
    for day_type, days in (("normal", NORMAL_DAYS), ("sale", SALE_DAYS)):
        for hours, nodes, autopilot in profile[day_type]:
            yield hours * days, nodes, autopilot


def month_cost(profile: Profile, commits: list[Commitment], month: int) -> dict[str, float]:
    """1か月の請求額と CUD の利用率を返す.

    充当順: リソースCUD → flex(Autopilot に先に充当 [仮定])→ 残りの N2 に SUD。
    SUD は「使用量をまとめて割引が最大になるよう組み合わせる」[公式] ため、
    残りの N2 使用を稼働率の高い層から積み上げ、層ごとに段階割引を掛ける。
    """
    active = [c for c in commits if c.is_active(month)]
    res_nodes = sum(c.amount for c in active if c.kind == "resource")
    flex_usd = sum(c.amount for c in active if c.kind == "flex")
    fee = sum(c.monthly_fee() for c in active)

    autopilot_on_demand = res_used = flex_used = 0.0
    leftover: list[tuple[float, float]] = []   # (時間, SUD 対象として残る N2 ノード数)
    for hours, nodes, autopilot in _blocks(profile):
        by_res = min(nodes, res_nodes)
        flex_ap = min(flex_usd, autopilot)
        flex_n2 = min(flex_usd - flex_ap, (nodes - by_res) * NODE_PRICE_USD_H)
        res_used += by_res * hours
        flex_used += (flex_ap + flex_n2) * hours
        autopilot_on_demand += (autopilot - flex_ap) * hours
        leftover.append((hours, nodes - by_res - flex_n2 / NODE_PRICE_USD_H))

    n2_after_sud, level, step = 0.0, 0.0, 0.01
    top = max(n for _, n in leftover)
    while level < top - 1e-9:   # 層(0.01ノード幅)ごとに稼働率を出して SUD を掛ける
        width = min(step, top - level)
        hours_on = sum(h for h, n in leftover if n > level + 1e-9)
        n2_after_sud += width * NODE_PRICE_USD_H * MONTH_HOURS * sud_ratio(hours_on / MONTH_HOURS)
        level += width

    return {
        "total": fee + autopilot_on_demand + n2_after_sud,
        "fee": fee,
        "res_util": res_used / (res_nodes * MONTH_HOURS) if res_nodes else float("nan"),
        "flex_util": flex_used / (flex_usd * MONTH_HOURS) if flex_usd else float("nan"),
    }


def profile_for(month: int, scenario: Literal["S1", "S2"]) -> Profile:
    if month <= 3:
        return PHASE0
    if scenario == "S2" and month >= MIGRATION_MONTH:
        return PHASE2
    return PHASE1


def evaluate(commits: list[Commitment], scenario: Literal["S1", "S2"]) -> tuple[float, float, list[dict]]:
    """36か月の合計額・現在価値・月次明細を返す."""
    rows = [month_cost(profile_for(m, scenario), commits, m) for m in range(1, HORIZON_MONTHS + 1)]
    monthly_rate = (1 + ANNUAL_DISCOUNT_RATE) ** (1 / 12) - 1
    present_value = sum(r["total"] / (1 + monthly_rate) ** m for m, r in enumerate(rows, 1))
    return sum(r["total"] for r in rows), present_value, rows


OPTIONS: dict[str, list[Commitment]] = {
    "O0 コミットなし": [],
    "O1 Bad 3年res24台": [Commitment("resource", 1, 3, 24)],
    "O2 3年res16台": [Commitment("resource", 1, 3, 16)],
    "O3 1年res7台@M4": [Commitment("resource", 4, 1, 7)],
    "O4 3年res2+3年flex4.25": [Commitment("resource", 1, 3, 2), Commitment("flex", 1, 3, 4.25)],
    "G  段階購入(M1:res2+flex2.25 / M13:flex1.75)": [
        Commitment("resource", 1, 3, 2),      # システム用2台: どちらのシナリオでも残る
        Commitment("flex", 1, 3, 2.25),       # 移行しても消えない床(Standard でも Autopilot でも使う)
        Commitment("flex", MIGRATION_MONTH, 3, 1.75),  # 昼の層は移行・SaaS化の判断後に買う
    ],
}


if __name__ == "__main__":
    list_price = sum(h * n * NODE_PRICE_USD_H for h, n, _ in _blocks(PHASE0))
    now = month_cost(PHASE0, [], 1)["total"]
    print(f"現状: 定価 ${list_price:,.0f}/月 → SUD後の請求 ${now:,.0f}/月(SUD −${list_price - now:,.0f})")
    print(f"Badの主張: 定価×55% = −${list_price * 0.55:,.0f}/月, 3年で −${list_price * 0.55 * 36:,.0f}")
    print()
    base = {s: evaluate([], s) for s in ("S1", "S2")}
    print(f"{'案':36s}{'S1差':>10s}{'S2差':>10s}{'期待差':>10s}{'期待PV差':>10s}{'M1稟議額':>11s}")
    for name, commits in OPTIONS.items():
        r1, r2 = evaluate(commits, "S1"), evaluate(commits, "S2")
        d1, d2 = r1[0] - base["S1"][0], r2[0] - base["S2"][0]
        dpv = (r1[1] + r2[1] - base["S1"][1] - base["S2"][1]) / 2
        oblig = sum(c.total_obligation() for c in commits if c.start_month == 1)
        print(f"{name:36s}{d1:+10,.0f}{d2:+10,.0f}{(d1 + d2) / 2:+10,.0f}{dpv:+10,.0f}{oblig:11,.0f}")
    print()
    for name in ("O1 Bad 3年res24台", "G  段階購入(M1:res2+flex2.25 / M13:flex1.75)"):
        for s in ("S1", "S2"):
            rows = evaluate(OPTIONS[name], s)[2]
            ref = base[s][2]
            cells = "  ".join(
                f"M{m}: ${rows[m-1]['total']:,.0f}(なし${ref[m-1]['total']:,.0f}) res{rows[m-1]['res_util']:.0%}"
                + (f"/flex{rows[m-1]['flex_util']:.0%}" if rows[m-1]['flex_util'] == rows[m-1]['flex_util'] else "")
                for m in (1, 4, 13, 36))
            print(f"{name[:2]} {s}  {cells}")
  1. 割引の基準を取り違えている(定価 × 55%) — 今の請求は定価 $5,835 ではなく SUD 後の $4,849。常時稼働の N2 はすでに20%引きなので、3年CUDの上乗せ効果は 1 − 0.45/0.80 = 43.75%(1年なら21%)。SUD は CUD でカバーされた使用には付かない(公式)
  2. ピーク(24台)で約束している — 24台目の稼働率は 12.3%、17台目より上は19.7%以下で、3年リソースの損益分岐48%を大きく下回る。今日だけ見ても削減は $909/月(主張の28%)。CUD は容量を予約しない割引契約で、足りない分はオンデマンドで動く
  3. 確定している削減(M3末の適正化・バッチ移行)を無視 — M4 以降は Bad 案が「なし」より 月 $678 高い。適正化だけで月 −$1,368 下がり、これはどの CUD 案の月額効果よりも大きい
  4. リソースベース CUD が移行先で使えない — 「リソースベース CUD は Autopilot Pod に適用されない」(公式)。S2 では M13 以降、約束の 8% しか使われず、月 $7,010(なしなら $3,654)を2年払い続ける
  5. 解約不能な支払義務が稟議に無い — 「使っても使わなくても毎月請求」「購入後は解約不可」(公式)。Bad 案の解約不能総額は $141,834(約2,128万円)
  6. シナリオ・期待値・時間価値が無い — 36か月で S1 +$19,652、S2 +$83,919、期待値 +$51,786(+777万円) の損。年8%の現在価値でも +$44,517
  7. 一括購入で監視と止め方が無い — 利用率・カバー率の監視も、次の判断日も無い。段階購入なら情報が出そろう 2027-09 に次の量を決められる

実行例(input → output)

入力は定数と OPTIONS の6案。Python 3.12 と 3.14 で同じ出力を確認済み。

$ python3 cud_decision.py      # 6案を 2シナリオ×36か月で試算して比較表を出す
現状: 定価 $5,835/月 → SUD後の請求 $4,849/月(SUD −$986)
Badの主張: 定価×55% = −$3,209/月, 3年で −$115,537

案                                          S1差       S2差       期待差     期待PV差      M1稟議額
O0 コミットなし                                   +0        +0        +0        -0          0
O1 Bad 3年res24台                        +19,652   +83,919   +51,786   +44,517    141,834
O2 3年res16台                            -24,755   +38,432    +6,839    +4,651     94,556
O3 1年res7台@M4                           -5,215      -837    -3,026    -2,907          0
O4 3年res2+3年flex4.25                   -35,987   -44,376   -40,182   -35,634     72,099
G  段階購入(M1:res2+flex2.25 / M13:flex1.75)   -31,939   -41,971   -36,955   -32,517     43,732

O1 S1  M1: $3,940(なし$4,849) res67%  M4: $4,159(なし$3,481) res45%  M13: $4,159(なし$3,481) res45%  M36: $4,159(なし$3,481) res45%
O1 S2  M1: $3,940(なし$4,849) res67%  M4: $4,159(なし$3,481) res45%  M13: $7,010(なし$3,654) res8%  M36: $7,010(なし$3,654) res8%
G  S1  M1: $4,167(なし$4,849) res100%/flex100%  M4: $2,736(なし$3,481) res100%/flex100%  M13: $2,514(なし$3,481) res100%/flex94%  M36: $2,514(なし$3,481) res100%/flex94%
G  S2  M1: $4,167(なし$4,849) res100%/flex100%  M4: $2,736(なし$3,481) res100%/flex100%  M13: $2,269(なし$3,654) res100%/flex93%  M36: $2,269(なし$3,654) res100%/flex93%

読み方(150円/$ で換算、導出。「差」は36か月の請求額の、コミットなしとの差。マイナスが削減):

案中身S1差S2差期待差M1の稟議額(解約不能)
O0コミットなし0000
O1(Bad)3年リソース 24台+295万円+1,259万円+777万円2,128万円
O23年リソース 16台(今日の曲線で最適)−371万円+576万円+103万円1,418万円
O31年リソース 7台(M4から)−78万円−13万円−45万円0(M4に購入)
O43年リソース2台 + 3年flex $4.25/h(M1に一括)−540万円−666万円−603万円1,081万円
G(推奨)M1: 3年リソース2台 + 3年flex $2.25/h / M13: 3年flex $1.75/h 追加−479万円−630万円−554万円656万円

G の M13 追加分(解約不能総額 $24,822 ≒ 372万円)は 2027-09 の判断後に別稟議。M13 追加分は M48 まで続くが、36か月の外の12か月は表に入れていない。

推奨案と稟議の書き直し

買う日契約量根拠
2026-10(M1)3年リソースベース(N2・東京)2台システム用ノードは S1/S2 どちらでも残る。3年55%は flex 46% より深い
2026-10(M1)3年 Compute flexibleオンデマンド換算 $2.25/hAPI の最低負荷。Standard でも Autopilot でも使われ、両シナリオで利用率100%
2027-10(M13)3年 Compute flexible(追加)最大 $1.75/h昼の上乗せ分。レコメンド SaaS 化の判断(2027-09)が出てから買う
Before — 削減額だけ

件名: GKE ノード費 55% 削減のため 3年 CUD を購入したい

  • 削減額 $3,209/月、3年で約1,733万円
  • ピーク24台に合わせた
  • 費用が減るので予算申請は不要
After — 結論・総額・却下案・次の判断日

件名: GKE・Autopilot の計算費に対する CUD の段階購入(第1弾: 解約不能総額 656万円/3年)

  • 結論: N2 リソースベース CUD 2台(3年)と Compute flexible CUD オンデマンド換算 $2.25/h(3年)を購入したい。解約できない支払総額は $43,732(約656万円、毎月請求)
  • 効果: 第2弾まで含めた36か月の削減見込みは両シナリオで −479万〜−630万円(期待値 −554万円、現在価値 −488万円)。単価・為替は仮定値のため、購入前に SKU 単価で再計算する
  • 却下した案: ピーク24台の3年リソース CUD。移行なしでも +295万円、移行ありなら +1,259万円の損
  • 先にやること: 12月末の適正化とバッチ移行(CUD 無しで月 −20.5万円)
  • 次の判断日: 2027-09。第2弾の量はその時点の3か月の実測で決める

購入後の監視と止め方

指標定義頻度しきい値と行動
コミット利用率約束した額のうち実際の使用に充当された割合(Billing の CUD 分析レポート)週次2週連続 90% 未満 → 原因を調べ、次の段階購入を止める
カバー率対象の計算費のうち CUD で払った割合月次80% 超 → 次の購入は見送る(上の層は稼働率が低い)
層ごとの稼働率持続曲線の k 台目(または $x/h 目)の稼働率四半期3年flex の分岐 60%(Autopilot 部分は 54%)を超える層だけが次の候補
判断日2027-09 の移行・SaaS 判断1回結果を PHASE2 と確度に入れ直して再計算してから第2弾を稟議
止め方: 第1弾は解約できないので、止められるのは「次を買わないこと」だけ。これを稟議に明記する。

迷った案と採らなかった理由

案採らなかった理由前提が変わったら
O4: 今日 3年flex $4.25/h を一括モデル上は G より期待値で $3,227(約48万円) 得。ただし昼の上乗せ($2.0/h 分)は SaaS 化で消えうる。消えた場合、残り24か月で $18,911(約284万円) を使わずに払う。損益分岐となる「消える確率」は 3,227 ÷ (3,227 + 18,911) ≒ 15% 導出SaaS 化の可能性が15%未満と言える材料が出たら O4 を採る
O2: 今日の曲線で最適な16台S1 −371万円/S2 +576万円。移行すると大きく損をする。確定した適正化も入っていない移行が「無い」と確定したら、適正化後の曲線でやり直す(7台前後)
O3: 1年リソース 7台悪い方でも −13万円と安全だが、期待値 −45万円と効果が小さい移行判断がさらに1年延びるなら有力
1年flex を毎年更新N2 は常時稼働なら SUD で20%引き。1年flex(28%)の上乗せは約10%で、分岐稼働率が87%と高いAutopilot 比率が上がり SUD の無い支出が増えるほど有利
Spot VM/Spot Pod夜間バッチには有効だが、Spot Pod に flexible CUD は効かない(公式)。本問の主題は常時動く API の約束バッチ比率が増えたら CUD の前に Spot 化を検討

ポイント解説

  1. CUD は「割引」ではなく「解約できない先物の買い」 — 使用量が約束を下回ると、差は丸ごと損。評価は「約束額 − 約束しなかった場合の請求額」。証券の言葉では、将来の使用量を固定価格で先に買う取引で、下振れリスクは買い手が全部負う
  2. 損益分岐稼働率 = 約束の単価 ÷ 約束しなかった場合の単価 — SUD の無い支出なら 1 − 割引率(3年リソース45%、3年flex54%)。N2 のように SUD が付く支出は分岐点が上がる(3年リソース48%、1年flex87%)。持続曲線の各層をこの分岐点と比べる
  3. 「減らしてから買う」と「縛りの弱い契約で床を押さえる」 — 適正化(月 −$1,368)は CUD のどの案よりも月額効果が大きく、リスクもない。移行を控えているときは、割引の深さより移行しても使える契約の価値が勝つ
  4. 稟議には削減見込みと解約不能総額の両方 — 毎月請求なので P/L 上は普通の費用だが、決裁は「3年の支払を約束する契約」として行う

実務への応用

  • 自チームで最初にやること: Billing export(BigQuery)から N2 と Autopilot の時間別使用量を取り、持続曲線を描く。コンソールの CUD 購入推奨は過去の使用量だけを見ており、12月の適正化や来年の移行を知らない。推奨をそのまま買わず、ロードマップを入れた試算と並べる
  • 社内の購入ルールに落とす: 「確度90%以上の使用量まで」「3年は床のみ」「購入は四半期に1回、判断会議の翌週」を FinOps のルールとして文書化する。FinOps Framework でも Rate Optimization(確約割引)と Workload Optimization(使用量の最適化)は別の能力で、順序の取り決めが要る
  • 他のクラウド: AWS の Compute Savings Plans(移行に強い)と EC2 Instance Savings Plans(割引が深い)も同じ構図
  • 証券会社での経験の使いどころ: 段階購入は債券のラダー運用と同じ発想で、満期(追加・更新日)を情報が出る日に合わせる。O4 と G の差(約48万円)は「判断を1年待つ権利」の値段で、その権利が効くのは SaaS 化の可能性が15%以上のとき、と数字で説明できる

扱わなかった範囲(と理由)

  • クラスタ管理手数料・ネットワーク・ディスク — flexible CUD の対象外(公式)。CUD の判断に影響しないので除外
  • Cloud Run(banner-api) — flexible CUD の対象だが本稟議の範囲外。実務では全社の床を合算してから量を決める
  • SUD の厳密な計算 — SUD は「使用量をまとめて割引が最大になるよう組み合わせる」(公式)。本問は層ごとの段階割引で近似した
  • flex CUD の充当順 — Autopilot に先に充当する 仮定。逆順なら G の効果は S1 で少し下がる
  • 為替と価格改定 — 150円/$ 固定。約束額にもオンデマンド額にも同じ率が掛かるので、案の順位は為替では変わらない
  • 会計処理(新リース会計基準) — 2027年4月以後開始の事業年度から適用される企業会計基準第34号では「特定された資産」の有無でリースを判定する。CUD は特定のサーバーを使う権利ではない割引契約なので、リースに当たらない可能性が高いが、経理と監査法人に確認する論点として残した

一次資料(参照日 2026-09-25)

今日のまとめ

CUD は「使った分の割引」ではなく「約束した分を必ず払う、解約できない契約」。ピークではなく、どのシナリオでも必ず使う床を、移行しても使える契約で、減らした後に買う。稟議には削減見込みと並べて解約不能な支払総額を書く。

次のステップ

  • 発展問題: 2027-09、API 移行は「実施」、レコメンド SaaS 化は「見送り」と決まった。3か月の実測で Autopilot の昼の支出はオンデマンド換算 $6.1/h(稼働率83%)、夜は $4.05/h、深夜は $2.25/h だった。第2弾として買う flex の量と期間(1年/3年)を損益分岐稼働率で決めよ。Cloud Run(banner-api、床 $0.8/h)を同じ約束に含めるべきか
  • 参考: Committed use discounts、Compute flexible CUD、Sustained use discounts、持続曲線(load duration curve)、損益分岐稼働率、カバー率と利用率、Savings Plans、FinOps Rate Optimization、ラダー運用

自己評価(あとで記入)