Kubernetes 向け FinOps: 適切なサイジング、スポット インスタンス、コスト削減
本番環境で Kubernetes を使用している組織の 68% は、20 ~ 40% 多くの費用を費やしています 必要以上にコストがかかります (CNCF コスト調査 2026)。 Kubernetes が非効率だからではなく、 寛大で簡単なプロビジョニングには、運用上の規律が必要です。の 平均 CPU 使用率が 15 ~ 20%、メモリが 30 ~ 40% の結果とクラスター: リソースが支払われました でも使わないでください。
Kubernetes 向け FinOps そして測定、最適化、管理の実践 クラスター支出。この記事ではその使い方を見ていきます クベコスト のために 名前空間のコストの可視性。 VPA サイズの適正化に役立ちます 自動リクエスト、その方法 カーペンター ノードのビンパッキングを最適化します スポット インスタンスと、コストを維持するために組織レベルでどのポリシーを実装するか 時間の経過とともに制御されます。
何を学ぶか
- 名前空間/チームコストを可視化するために Kubecost をインストールして構成します
- オフ モードの VPA: 中断することなく自動的に適切なサイジングが推奨される
- Karpenter: ノードの最適なビンパッキングのための統合
- Karpenter を使用して AWS/GCP/Azure 上のインスタンスを特定し、管理を中断します
- チームの予算作成ツールとしての ResourceQuota
- Prometheus に無駄とコストの異常を警告する
- チーム向けのチャージバック システムを構築する方法
- ベンチマーク: 各手法で達成可能な実際の節約
Kubernetes がオーバープロビジョニングされる傾向がある理由
最適化する前に、問題の原因を理解する必要があります。
- 保守的な要求: チームは「安全のために」リクエストを高く設定します (例: 0.1 を使用するアプリの場合は 1 CPU)。リクエストによって必要なノードの数が決まります
- 制限 = リクエスト: 多くの CI/CD テンプレートはリクエストに等しい制限を設定し、体系的なオーバープロビジョニングを作成します
- 空の名前空間: 年中無休で稼働する「Hello World」ポッドを備えた開発名前空間
- 特大の結び目: 非効率的なビンパッキングを伴う大規模なクラウド インスタンス (32 vCPU ノード上の 2 vCPU ポッド)
- チームに可視性がない: チームがコストを認識していなければ、最適化するインセンティブがありません。
Kubecost: 名前空間コストの可視化
クベコスト これは、Kubernetes エコシステムで最も使用されている FinOps ツールです。 Prometheus からメトリクスを収集し、クラウド インスタンスの価格を取得します (AWS、GCP、Azure) 名前空間、展開、サービス アカウント、ラベルに割り当てられたコストを計算します。
Kubecost のインストール
# Installa Kubecost con Helm
helm repo add kubecost https://kubecost.github.io/cost-analyzer/
helm repo update
helm install kubecost kubecost/cost-analyzer \
--namespace kubecost \
--create-namespace \
--set kubecostToken="your-token-here" \
--set prometheus.enabled=true \
--set grafana.enabled=true \
--set global.prometheus.enabled=false \
--set global.prometheus.fqdn="http://prometheus.monitoring.svc:9090"
# Port-forward per accedere alla UI
kubectl port-forward svc/kubecost-cost-analyzer 9090:9090 -n kubecost &
# Apri: http://localhost:9090
# Alternativa open-source senza token: OpenCost
helm install opencost opencost/opencost \
--namespace opencost \
--create-namespace
チームのチャージバックを構成する
# Kubecost usa i label Kubernetes per il cost allocation
# Configura label standard per tutti i workload:
# Nel values.yaml di ogni applicazione (Helm):
podLabels:
team: "team-alpha"
cost-center: "CC-2024-ENG"
environment: "production"
product: "checkout-service"
# Kubecost mostra automaticamente i costi aggregati per questi label.
# Es: costo totale team-alpha nel mese = CPU + Memoria + Storage + GPU + Networking
# API Kubecost per report automatici (da inviare via email settimanale):
curl "http://kubecost:9090/model/allocation?window=7d&aggregate=label:team&accumulate=true" \
| jq '.data[0] | to_entries[] | {team: .key, cost: .value.totalCost}'
自動適正化のための VPA
Il 垂直ポッド オートスケーラー (VPA) 過去の CPU 消費量を分析し、
ポッドのメモリを管理し、最適なリクエストを計算します。モード中 Off (推奨
自動適用なし)は、サイズ調整のための最も安全なツールです。
中断のリスクなしで正確な数値を取得できます。
# Installa VPA
git clone https://github.com/kubernetes/autoscaler.git
cd autoscaler/vertical-pod-autoscaler
./hack/vpa-up.sh
# Oppure con Helm
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
helm install vpa fairwinds-stable/vpa \
--namespace vpa \
--create-namespace
---
# vpa-recommendation.yaml - modalita Off: solo raccomandazioni
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: api-service-vpa
namespace: team-alpha
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: api-service
updatePolicy:
updateMode: "Off" # non applica automaticamente, solo raccomanda
resourcePolicy:
containerPolicies:
- containerName: api
minAllowed:
cpu: 50m
memory: 64Mi
maxAllowed:
cpu: "4"
memory: 8Gi
# Leggi le raccomandazioni dopo 24-48 ore:
kubectl describe vpa api-service-vpa -n team-alpha
# Output:
# Container Recommendations:
# Container Name: api
# Lower Bound:
# Cpu: 120m
# Memory: 256Mi
# Target: <-- usa questi valori nelle requests
# Cpu: 250m
# Memory: 512Mi
# Upper Bound:
# Cpu: 800m
# Memory: 1500Mi
# Uncapped Target:
# Cpu: 230m
# Memory: 480Mi
一括での適切なサイジング分析のためのスクリプト
# Trova tutti i Deployment con requests > 2x il consumo reale
kubectl get vpa -A -o json | jq -r '
.items[] |
.metadata.namespace + "/" + .metadata.name + ": " +
(.status.recommendation.containerRecommendations[]? |
"target CPU=" + .target.cpu + " Mem=" + .target.memory)
'
# Script bash per generare report di rightsizing
#!/bin/bash
echo "=== Rightsizing Recommendations ==="
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
echo "--- Namespace: $ns ---"
kubectl get vpa -n "$ns" -o custom-columns=\
"NAME:.metadata.name,\
TARGET-CPU:.status.recommendation.containerRecommendations[0].target.cpu,\
TARGET-MEM:.status.recommendation.containerRecommendations[0].target.memory" \
2>/dev/null
done
Karpenter: 統合とスポット インスタンス
Karpenter は 2 つの方向からコストを最適化します。 スポットインスタンス のために ノードあたりのコストを 60 ~ 70% 削減します。 ノードを統合する 削除する 十分に活用されていないもの(ビンパッキング)。
スポット + 統合を備えたノードプール
# karpenter-cost-optimized.yaml
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: cost-optimized
spec:
template:
spec:
nodeClassRef:
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
name: default
requirements:
# Tipi di istanza ottimali per bin-packing (diverse size)
- key: node.kubernetes.io/instance-type
operator: In
values:
- m7i.xlarge # 4 vCPU, 16GB ~$0.20/h on-demand, ~$0.05/h spot
- m7i.2xlarge # 8 vCPU, 32GB
- m7i.4xlarge # 16 vCPU, 64GB
- m7i.8xlarge # 32 vCPU, 128GB
- c7i.2xlarge # CPU-optimized per workload compute-intensive
- r7i.2xlarge # Memory-optimized per carichi con alta RAM
# Mix spot e on-demand con peso
- key: karpenter.sh/capacity-type
operator: In
values:
- spot # priorita spot (economico)
- on-demand # fallback on-demand
disruption:
consolidationPolicy: WhenUnderutilized
consolidateAfter: 1m # consolida subito i nodi sottoutilizzati
limits:
cpu: "1000" # max 1000 vCPU totali
memory: "4000Gi" # max 4TB RAM totale
---
# Configurazione spot interruption handler
# Necessario per gestire le interruzioni spot (AWS invia 2 min di preavviso)
helm install aws-node-termination-handler \
eks/aws-node-termination-handler \
--namespace kube-system \
--set enableSqsTerminationDraining=true \
--set queueURL=https://sqs.eu-west-1.amazonaws.com/123456789/NodeTerminationHandler
Karpenter による貯蓄分析
# Verifica quale percentuale dei nodi sono spot
kubectl get nodes -o json | jq '
[.items[] |
{type: .metadata.labels["karpenter.sh/capacity-type"],
instance: .metadata.labels["node.kubernetes.io/instance-type"]}
] |
group_by(.type) |
map({type: .[0].type, count: length})'
# Output esempio:
# [{"type": "on-demand", "count": 3}, {"type": "spot", "count": 12}]
# 80% dei nodi sono spot -> risparmio medio 65% = -$2400/mese
# Kubecost: visualizza costo spot vs on-demand storicamente
# Vai in Cost Allocation > Filter by node type
名前空間の予算: FinOps ツールとしての ResourceQuota
ResourceQuotas は技術的な分離のためだけではなく、ツールでもあります 金融ガバナンスのこと。予算に基づいて割り当てを割り当てることで、 チームに最適化を促すインセンティブ:
# budget-quota-team.yaml
# Calcola le quote basandoti sul budget mensile del team
# Budget: 500 EUR/mese (circa 1500 CPU-hours a 0.033 EUR/CPU-hour)
# Assumendo utilizzo medio 50%: requests max = 2000 CPU-hours / 720 ore = 2.8 vCPU mean
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-alpha-budget-quota
namespace: team-alpha
annotations:
finops/monthly-budget-eur: "500"
finops/last-reviewed: "2026-01-15"
finops/owner: "alice@company.com"
spec:
hard:
# Basato su budget EUR/mese
requests.cpu: "6" # ~500 EUR/mese a tasso medio spot
requests.memory: "12Gi" # proporzionale
requests.storage: "200Gi"
---
# Alert quando il team si avvicina al budget
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: finops-budget-alerts
namespace: monitoring
spec:
groups:
- name: finops
rules:
- alert: TeamBudgetUsageHigh
expr: |
kubecost_namespace_allocation_cpu_cost_hourly * 24 * 30 +
kubecost_namespace_allocation_memory_cost_hourly * 24 * 30 > 400
for: 1h
labels:
severity: warning
annotations:
summary: "Team {{ $labels.namespace }}: costo mensile proiettato > 400 EUR"
さまざまなワークロードに応じた節約戦略
| ワークロードの種類 | 戦略 | 期待される節約額 |
|---|---|---|
| Web API(ステートレス) | スポット + HPA + 適正化 VPA | 50-65% |
| ML バッチジョブ | スポット + チェックポイント + ゼロへのスケール | 60-70% |
| データベース (ステートフル) | オンデマンド予約 + 適切なサイジング | 20-30% |
| CI/CD ランナー | スポット + ゼロスケール (KEDA) | 70-80% |
| 重要なサービスを年中無休で提供 | リザーブドインスタンス + 適切なサイズ設定 | 30-40% |
KEDA + スポットによる CI/CD ジョブの最適化
# Runners CI/CD sono idle la maggior parte del tempo:
# scala a 0 quando non ci sono job, usa spot
# KEDA ScaledJob per runner GitHub Actions
apiVersion: keda.sh/v1alpha1
kind: ScaledJob
metadata:
name: github-actions-runner
namespace: actions-runners
spec:
jobTargetRef:
template:
spec:
containers:
- name: runner
image: summerwind/actions-runner:latest
resources:
limits:
cpu: "2"
memory: "4Gi"
nodeSelector:
karpenter.sh/capacity-type: spot # usa spot per runners
tolerations:
- key: "spot"
operator: "Exists"
effect: "NoSchedule"
pollingInterval: 30
minReplicaCount: 0 # scala a 0 quando nessun job
maxReplicaCount: 20 # massimo 20 runner paralleli
triggers:
- type: github-runner
metadata:
owner: "myorg"
repos: "myrepo"
targetWorkflowQueueLength: "1"
Grafana を使用した FinOps ダッシュボード
# PromQL queries per dashboard FinOps Kubernetes
# Costo orario totale del cluster
sum(
kube_pod_container_resource_requests{resource="cpu"} * 0.033 +
kube_pod_container_resource_requests{resource="memory"} / 1073741824 * 0.004
) by (namespace)
# Efficienza CPU per namespace (utilizzo reale / requested)
sum(rate(container_cpu_usage_seconds_total[5m])) by (namespace) /
sum(kube_pod_container_resource_requests{resource="cpu"}) by (namespace) * 100
# Pod con requests molto piu alte del consumo reale (spreco > 70%)
(
kube_pod_container_resource_requests{resource="cpu"} -
rate(container_cpu_usage_seconds_total[24h])
) / kube_pod_container_resource_requests{resource="cpu"} > 0.7
# Importa il dashboard Grafana Kubecost: ID 11270
Kubernetes の FinOps ベスト プラクティス
毎月の FinOps チェックリスト
- VPA の推奨事項を確認します。 VPA の推奨事項を分析し、上位 10 の廃棄物に適正サイズを適用します
- アイドル状態のノードを確認します。 24 時間にわたって CPU とメモリの使用率が 10% 未満のノードは終了する必要があります (これは Karpenter によって自動的に行われます)。
- スポットカバレッジを確認します。 目標は、スポット インスタンス上の非ステートフル ノードの 70 ~ 80% です。
- チャージバックレポート: Kubecost API → 電子メールまたは Slack 経由でチームごとの月次コスト レポートを送信
- ResourceQuota を確認します。 デフォルトではなく、ビジネス上の正当な理由がある場合にのみクォータを増やす
- 開発環境向けにゼロまでスケール: 開発環境は営業時間外にシャットダウンする必要があります (コストが 65% 削減)
結論と次のステップ
FinOps for Kubernetes は 1 回限りの最適化ではなく、継続的なプロセスです。 可視性 (Kubecost)、インテリジェントな推奨事項 (VPA)、効率的なプロビジョニングが必要 (コマーシャルを持つ大工) と組織ガバナンス (予算としての ResourceQuota)。実装する これらすべてのテクニックを組み合わせることで、組織は通常、 最初の 3 ~ 6 か月間の Kubernetes クラウド料金の 35 ~ 55%。
次のステップは、FinOps Kubernetes を開発サイクルに統合することです。開発者は、 本番環境に統合する前に、導入の推定コストを確認する必要があります。 コストに適用される「シフトレフト」アプローチ。







