概要
割引ではなく、解約できない約束
約束した分は使わなくても毎月払う。評価は「約束額 − 約束しなかった場合の請求額」。
今払っている値段と比べる
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.4 | 16台 | 14台 | 10台 |
| セール日(月2回×3日) | 6.0 | 24台 | 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)
件名: 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万円)の削減になります。セール時にノードが足りなくなるのが怖いので、ピークに合わせました。来週中に購入手続きをしたいので承認をお願いします。(費用が減る話なので、予算申請は不要と考えています)
ヒント(段階的開示)
ヒント1 — 方向性
ヒント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 台目が月の何%動いているか」。緑の破線(3年リソース 48%)より低い台を約束すると、約束しないより高くつく。Bad は24台すべてを約束している。右: 移行ありのシナリオでの月額。Bad は M4 以降「なし」より高く、M13 以降は約2倍になる。
使用量を層に分け、層ごとに契約を選ぶ。長く深い契約(3年リソース)はどのシナリオでも残る2台だけ。移行しても使える量は flexible。消えうる層は判断日の後に買う。
模範解答
黄色 = 設計意図のコメント、緑 = Bad の問題番号を直した箇所、赤 = 比較のために残した Bad 案。
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 はどこにも出てこない
# ⑦ 次の判断日・監視指標なし
# 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}")
- 割引の基準を取り違えている(定価 × 55%) — 今の請求は定価 $5,835 ではなく SUD 後の $4,849。常時稼働の N2 はすでに20%引きなので、3年CUDの上乗せ効果は 1 − 0.45/0.80 = 43.75%(1年なら21%)。SUD は CUD でカバーされた使用には付かない(公式)
- ピーク(24台)で約束している — 24台目の稼働率は 12.3%、17台目より上は19.7%以下で、3年リソースの損益分岐48%を大きく下回る。今日だけ見ても削減は $909/月(主張の28%)。CUD は容量を予約しない割引契約で、足りない分はオンデマンドで動く
- 確定している削減(M3末の適正化・バッチ移行)を無視 — M4 以降は Bad 案が「なし」より 月 $678 高い。適正化だけで月 −$1,368 下がり、これはどの CUD 案の月額効果よりも大きい
- リソースベース CUD が移行先で使えない — 「リソースベース CUD は Autopilot Pod に適用されない」(公式)。S2 では M13 以降、約束の 8% しか使われず、月 $7,010(なしなら $3,654)を2年払い続ける
- 解約不能な支払義務が稟議に無い — 「使っても使わなくても毎月請求」「購入後は解約不可」(公式)。Bad 案の解約不能総額は $141,834(約2,128万円)
- シナリオ・期待値・時間価値が無い — 36か月で S1 +$19,652、S2 +$83,919、期待値 +$51,786(+777万円) の損。年8%の現在価値でも +$44,517
- 一括購入で監視と止め方が無い — 利用率・カバー率の監視も、次の判断日も無い。段階購入なら情報が出そろう 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 | コミットなし | 0 | 0 | 0 | 0 |
| O1(Bad) | 3年リソース 24台 | +295万円 | +1,259万円 | +777万円 | 2,128万円 |
| O2 | 3年リソース 16台(今日の曲線で最適) | −371万円 | +576万円 | +103万円 | 1,418万円 |
| O3 | 1年リソース 7台(M4から) | −78万円 | −13万円 | −45万円 | 0(M4に購入) |
| O4 | 3年リソース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/h | API の最低負荷。Standard でも Autopilot でも使われ、両シナリオで利用率100% |
| 2027-10(M13) | 3年 Compute flexible(追加) | 最大 $1.75/h | 昼の上乗せ分。レコメンド SaaS 化の判断(2027-09)が出てから買う |
件名: GKE ノード費 55% 削減のため 3年 CUD を購入したい
- 削減額 $3,209/月、3年で約1,733万円
- ピーク24台に合わせた
- 費用が減るので予算申請は不要
件名: 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弾を稟議 |
迷った案と採らなかった理由
| 案 | 採らなかった理由 | 前提が変わったら |
|---|---|---|
| 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 化を検討 |
ポイント解説
- CUD は「割引」ではなく「解約できない先物の買い」 — 使用量が約束を下回ると、差は丸ごと損。評価は「約束額 − 約束しなかった場合の請求額」。証券の言葉では、将来の使用量を固定価格で先に買う取引で、下振れリスクは買い手が全部負う
- 損益分岐稼働率 = 約束の単価 ÷ 約束しなかった場合の単価 — SUD の無い支出なら 1 − 割引率(3年リソース45%、3年flex54%)。N2 のように SUD が付く支出は分岐点が上がる(3年リソース48%、1年flex87%)。持続曲線の各層をこの分岐点と比べる
- 「減らしてから買う」と「縛りの弱い契約で床を押さえる」 — 適正化(月 −$1,368)は CUD のどの案よりも月額効果が大きく、リスクもない。移行を控えているときは、割引の深さより移行しても使える契約の価値が勝つ
- 稟議には削減見込みと解約不能総額の両方 — 毎月請求なので 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)
- Google Cloud「Committed use discounts (CUDs) for Compute Engine」 — 原文: "You can't cancel a commitment after its purchase."
- Google Cloud「Committed use discounts | GKE」 — リソースベースは Standard のノードのみ、Autopilot は flexible(1年28%/3年46%)。Spot Pod・クラスタ管理手数料は対象外
- Google Cloud「Sustained use discounts」 — N2 は最大20%、区間ごとの料金比 100%/86.78%/73.3%/60%。CUD でカバー済みの使用には付かない
- Google Cloud「Compute flexible committed use discounts | Cloud Run」
- Google Cloud「VM instance pricing」 — N2 の1年 CUD 37% はここの CUD 列から広く引用される値(購入前に確認する前提で使用)
- FinOps Foundation「FinOps Framework」 — Rate Optimization と Workload Optimization
- 企業会計基準委員会「リースに関する会計基準」(企業会計基準第34号、2024年9月公表)
今日のまとめ
次のステップ
- 発展問題: 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、ラダー運用