はじめに:Kubernetesのコスト問題、正直シャレにならなくなってきた
2026年現在、Kubernetesはコンテナオーケストレーション市場の92%を占めていて、Fortune 100企業の77%が本番環境で使っています。もはや「使うかどうか」ではなく「どう運用するか」のフェーズですよね。
ただ、その普及に比例してクラウドコストの問題も深刻になっています。
FinOps Foundationの「State of FinOps 2026」レポートによると、組織のクラウド予算の平均32%が無駄になっていて、その総額は世界全体で年間2,000億ドル以上。正直、この数字を初めて見たときは二度見しました。中でもKubernetesワークロードは、その動的な性質とリソース管理の複雑さから、コスト最適化が特に難しい領域です。
もっと身近な話をすると、Kubernetesワークロードの65%は、要求されたCPU・メモリの半分以下しか使っていないというデータがあります。開発者が「落ちたら怖いから多めに」と設定する、あの"念のためバッファ"の積み重ねが、クラスタ全体では莫大なコスト浪費になっているわけです。
この記事では、AWS EKS・Azure AKS・GCP GKEにおけるKubernetesコストを最大70%削減するための実践的な戦略を、具体的なYAML設定やコマンド例とともに解説していきます。実際に筆者のチームで試して効果があった方法を中心にまとめたので、ぜひ参考にしてみてください。
戦略1:ライトサイジング — これが一番効く
なぜライトサイジングが最も効果的なのか
Kubernetesのスケジューラは、Podの実際の使用量ではなく「リソース要求(requests)」に基づいてスケジューリングします。ここがポイントです。requestsが過大に設定されていると、実際には余裕があるのにノードが「満杯」と判断されて、不要なノードがどんどん追加されてしまいます。
2026年の監査データによると、80〜90%のPodがCPU・メモリのrequestsを過大に設定しているとのこと。Podごとにわずか5〜15%のrequests削減でも、ビンパッキングの改善を通じてクラスタ全体で30〜60%のコスト削減につながります。これ、逆に言えば今すぐ手をつけるだけで大きな効果が出るということです。
Vertical Pod Autoscaler(VPA)でrequestsを自動最適化する
VPAは実際のリソース使用状況を監視して、適切なrequests/limitsを自動的に推奨・適用してくれるツールです。まずはインストールから。
# VPAのインストール(Helm)
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
helm repo update
helm install vpa fairwinds-stable/vpa \
--namespace vpa \
--create-namespace
次に、対象のDeploymentに対してVPAリソースを作成します。いきなりAutoモードにするのはちょっと怖いので、最初はOffモードで推奨値だけ確認するのがおすすめです。
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-app-vpa
namespace: production
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
updatePolicy:
updateMode: "Off" # まずは推奨値の確認から
resourcePolicy:
containerPolicies:
- containerName: my-app
minAllowed:
cpu: 50m
memory: 64Mi
maxAllowed:
cpu: 2000m
memory: 4Gi
controlledResources: ["cpu", "memory"]
推奨値の確認はこのコマンドで。
kubectl describe vpa my-app-vpa -n production
出力のRecommendationセクションに、Target(推奨値)、Lower Bound(最小推奨値)、Upper Bound(最大推奨値)が表示されます。この推奨値をもとにrequestsを調整すれば、過剰プロビジョニングを解消できます。実際にやってみると「こんなに余計にリソース確保してたのか…」と驚くはずです。
注意:VPAとHPAの併用には気をつけよう
VPAとHPA(Horizontal Pod Autoscaler)を同じリソースメトリクス(CPUなど)で同時に制御すると、お互いに競合することがあります。
2026年のベストプラクティスとしては、VPAを「Off」モードにして推奨値の取得だけに使い、スケーリングはHPAに任せるのが安全です。もう一つのアプローチとして、HPAではカスタムメトリクス(リクエスト数やキュー長など)を使い、VPAにCPU/メモリの最適化を担当させる方法もあります。
戦略2:Karpenterでノードプロビジョニングを賢くする
Cluster Autoscalerの限界
従来のCluster Autoscaler(CA)はAuto Scaling Group(ASG)経由でノードを管理しますが、正直いくつかの不満がありました。
- スケーリングに3〜4分かかる(ASGの起動時間がボトルネック)
- ノードグループごとにインスタンスタイプが固定される
- 大規模クラスタ(2,000ノード超)でメモリ使用量が1GiBを超える
- プロアクティブなコスト統合(Consolidation)機能がない
特にスケーリング速度の遅さは、トラフィックスパイク時に深刻な問題になります。
Karpenter:次世代のノードオートスケーラー
Karpenter(v1.5、2025年7月リリース)は、ASGを介さずEC2 APIと直接やり取りすることで、約45〜60秒でノードをオンラインにできます。この速度の違いは体感レベルで明らかです。さらに、数百のインスタンスタイプから最適なものを自動選択し、ノードの統合も自動で行ってくれます。
| 機能 | Cluster Autoscaler | Karpenter |
|---|---|---|
| スケーリング速度 | 3〜4分 | 45〜60秒 |
| ノード管理方式 | ASGベース | EC2 API直接 |
| インスタンス柔軟性 | ノードグループごとに固定 | 数百タイプから自動選択 |
| コスト統合 | なし(手動対応) | 自動(emptiness-first) |
| スポット中断対応 | 制限あり | ネイティブ対応 |
KarpenterのNodePool設定例(スポットインスタンス活用)
では、スポットインスタンスを活用したコスト最適化向けのNodePool設定を見てみましょう。
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: spot-workers
spec:
template:
metadata:
labels:
node-type: spot
cost-tier: economical
spec:
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
expireAfter: 168h # 7日で自動リサイクル
taints:
- key: spot
value: "true"
effect: NoSchedule
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ["spot"]
- key: node.kubernetes.io/instance-type
operator: In
values:
- m6i.large
- m6i.xlarge
- m6a.large
- m6a.xlarge
- m5.large
- m5.xlarge
- c6i.large
- c6i.xlarge
- r6i.large
- r5.large
- key: kubernetes.io/arch
operator: In
values: ["amd64"]
limits:
cpu: 500
memory: 1000Gi
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
EC2NodeClassの設定
NodePoolと合わせて、AWS固有のインフラ設定もEC2NodeClassで定義しておきます。
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
name: default
spec:
amiFamily: AL2023
amiSelectorTerms:
- alias: al2023@latest
role: "KarpenterNodeRole-my-cluster"
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: my-cluster
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: my-cluster
tags:
team: platform
environment: production
押さえておきたいポイント
- インスタンスの多様化が鍵:Spot-to-Spot統合を有効にするには、最低15種類のインスタンスタイプを指定するのが推奨です。少なすぎるとSpotの可用性が下がります
- Price Capacity Optimized(PCO)戦略:Karpenterはまず中断リスクが低いSpotプールを選び、次にその中で最安のものを選択してくれます
- 中断のネイティブ処理:Spot中断の2分前警告を検知して、自動的にcordon → drain → 新ノード起動まで一気にやってくれます。これが地味に助かる
- emptiness-first統合:v1.5で導入された機能で、空になったノードを積極的にリサイクルしてコストを削減します
戦略3:スポットインスタンスを戦略的に使い倒す
3大クラウドのスポット割引比較
まずは各クラウドのスポット事情を整理しておきましょう。
| プロバイダー | サービス名 | 最大割引率 | 中断通知 |
|---|---|---|---|
| AWS | EC2 Spot Instances | 最大90% | 2分前 |
| Azure | Spot VMs | 最大90% | 30秒前 |
| GCP | Spot VMs(旧Preemptible) | 最大91% | 30秒前 |
Azureの30秒は正直かなりシビアですね…。
スポットに向くワークロード・向かないワークロード
スポットインスタンスは万能ではありません。使い分けが大事です。
スポットに向くワークロード:
- ステートレスなWebサービス(水平スケーリングできるもの)
- CI/CDパイプライン
- バッチ処理・データ変換
- 開発・テスト環境
- MLトレーニングジョブ(チェックポイント機能付き)
スポットに向かないワークロード:
- ステートフルなデータベース
- 低レイテンシが必須のAPIゲートウェイ
- シングルレプリカのワークロード
基本的な考え方として、「突然落ちても数十秒以内に別のインスタンスで復旧できるか?」がスポット採用の判断基準になります。
EKSでのスポット活用:4層コスト構造
いきなり全部スポットにするのはリスクが高いので、以下のような4層構造がおすすめです。
- ベースライン(全体の60〜70%):Savings Plans / Reserved Instancesでカバー
- バッファ(15〜20%):オンデマンドインスタンス
- バースト対応(15〜20%):スポットインスタンス
- 開発・テスト環境:100%スポット(ここはケチって大丈夫)
Pod Disruption Budget(PDB)でスポット中断に備える
スポットを使うなら、PDBの設定は必須です。中断時にPodの可用性を維持するためのセーフティネットですね。
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-app-pdb
namespace: production
spec:
minAvailable: 2 # 常に最低2つのPodを維持
selector:
matchLabels:
app: my-app
さらに、Pod Topology Spread Constraintsを使ってPodを複数のAZ・ノードに分散させておくと、単一のスポット中断による影響を最小限に抑えられます。
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 6
template:
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: my-app
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: my-app
tolerations:
- key: spot
value: "true"
effect: NoSchedule
containers:
- name: my-app
image: my-app:latest
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: 500m
memory: 1Gi
戦略4:コスト可視化 — OpenCostとKubecostで「見える化」する
なぜコスト可視化が必要なのか
「見えないものは最適化できない」——FinOpsの基本中の基本です。
Kubernetesのコストが厄介なのは、ノード料金がNamespace・Deployment・Pod単位に自動で分割されないこと。結果、どのチームやアプリがいくら使っているのかがブラックボックスになりがちです。「うちのチームはそんなに使ってないはず」と全員が思っている状況、経験ありませんか?
OpenCost:無料で始められるオープンソースソリューション
OpenCostはCNCFのIncubatingプロジェクトで、Kubernetesコストのリアルタイム配分を提供してくれます。コンテナレベルの粒度でコストを可視化でき、AWS・Azure・GCPの課金APIとも連携可能です。
# OpenCostのインストール
helm repo add opencost https://opencost.github.io/opencost-helm-chart
helm repo update
helm install opencost opencost/opencost \
--namespace opencost \
--create-namespace
インストールしたら、APIを通じてNamespace単位のコストを確認してみましょう。
# Namespace別コストの取得(過去24時間)
kubectl port-forward -n opencost svc/opencost 9090:9090 &
curl -s "http://localhost:9090/allocation/compute?window=24h&aggregate=namespace" \
| jq '.data | to_entries | .[] | {
namespace: .key,
totalCost: .value.totalCost
}'
初めて実行すると、予想外のNamespaceが上位に来て驚くことが多いです。
Kubecost:エンタープライズ向けの高度な可視化
KubecostはOpenCostを基盤としつつ、割引(RI/Savings Plans/Spot)の反映やマルチクラスタ対応、コスト予測、異常検知といった高度な機能を備えています。
# Kubecostのインストール(無料版)
helm repo add kubecost https://kubecost.github.io/cost-analyzer/
helm repo update
helm install kubecost kubecost/cost-analyzer \
--namespace kubecost \
--create-namespace
両者の機能比較はこんな感じです。
| 機能 | OpenCost | Kubecost Free | Kubecost Enterprise |
|---|---|---|---|
| コスト配分(Pod/Namespace) | ○ | ○ | ○ |
| 割引・Spot価格の反映 | × | ○ | ○ |
| マルチクラスタ | × | × | ○ |
| コスト予測・異常検知 | × | △ | ○ |
| 最適化推奨 | × | ○ | ○ |
| ライセンス | Apache 2.0 | 無料 | 有料 |
個人的には、まずOpenCostで始めて、マルチクラスタ管理が必要になったタイミングでKubecostに移行するのがスムーズだと思います。
戦略5:Resource QuotaとLimitRangeでガバナンスを効かせる
Namespace単位のリソース制限
開発チームが無制限にリソースを要求できる環境では、コスト管理なんて不可能です。(これは断言できます。)Resource QuotaとLimitRangeを使って、組織的なガバナンスを導入しましょう。
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-a-quota
namespace: team-a
spec:
hard:
requests.cpu: "20"
requests.memory: 40Gi
limits.cpu: "40"
limits.memory: 80Gi
pods: "100"
persistentvolumeclaims: "20"
LimitRangeでデフォルト値を設定する
開発者がrequests/limitsを指定し忘れた場合に備えて、デフォルト値を設定しておくのも重要です。「requests未指定で巨大なノードが割り当てられてしまった」なんて事故、意外とよくあるんですよね。
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: team-a
spec:
limits:
- type: Container
default:
cpu: 250m
memory: 256Mi
defaultRequest:
cpu: 100m
memory: 128Mi
max:
cpu: 4000m
memory: 8Gi
min:
cpu: 50m
memory: 64Mi
戦略6:アイドルリソースのクリーンアップと自動スケジュール
開発・テスト環境の自動停止
開発環境やステージング環境を24時間動かし続ける必要、本当にありますか?
業務時間外にクラスタをスケールダウンするだけで、かなりのコスト削減になります。以下はCronJobとkubectlを使ったシンプルな自動スケジュールの例です。
apiVersion: batch/v1
kind: CronJob
metadata:
name: scale-down-dev
namespace: dev
spec:
schedule: "0 20 * * 1-5" # 平日20時にスケールダウン
jobTemplate:
spec:
template:
spec:
serviceAccountName: scaler
containers:
- name: kubectl
image: bitnami/kubectl:latest
command:
- /bin/sh
- -c
- |
kubectl scale deployment --all --replicas=0 -n dev
restartPolicy: OnFailure
---
apiVersion: batch/v1
kind: CronJob
metadata:
name: scale-up-dev
namespace: dev
spec:
schedule: "0 8 * * 1-5" # 平日8時にスケールアップ
jobTemplate:
spec:
template:
spec:
serviceAccountName: scaler
containers:
- name: kubectl
image: bitnami/kubectl:latest
command:
- /bin/sh
- -c
- |
kubectl scale deployment --all --replicas=2 -n dev
restartPolicy: OnFailure
これだけで、開発環境のコストを最大50%以上カットできます。導入のハードルも低いので、まだやっていないなら今日にでも設定してほしいくらいです。
孤立リソースの検出と削除
時間が経つにつれて、こういった「孤立リソース」が静かにコストを食い続けます。
- Pod削除後も残っているPersistentVolumeClaim(PVC)
- 使われなくなったLoadBalancerタイプのService
- 古いConfigMapやSecret
- 放置されたNamespace
定期的にチェックする習慣をつけましょう。以下のコマンドが便利です。
# PVCの使用状況を一覧表示(作成日順)
kubectl get pvc --all-namespaces --sort-by=.metadata.creationTimestamp
# LoadBalancerタイプのServiceを一覧表示
kubectl get svc --all-namespaces -o wide | grep LoadBalancer
# 長期間更新されていないNamespaceの確認
kubectl get namespaces --sort-by=.metadata.creationTimestamp
戦略7:ネットワークコストの最適化
見落としがちなネットワーク転送コスト
クラウドのネットワーク転送(Egress)コスト、意外と見落としていませんか? 特にAZ間・リージョン間の通信が多いマイクロサービスアーキテクチャでは、無視できない金額になります。
Topology Aware Routingの活用
Kubernetes v1.27以降で安定版となったTopology Aware Routingは、同じAZ内のPodへ優先的にトラフィックをルーティングしてくれます。設定もシンプルで、Serviceにアノテーションを追加するだけです。
apiVersion: v1
kind: Service
metadata:
name: my-service
annotations:
service.kubernetes.io/topology-mode: Auto
spec:
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
たったこれだけでAZ間転送コストを削減できます。やらない理由がないですよね。
VPCエンドポイントでEgressコストを削減
AWSの場合、S3・ECR・DynamoDBなどのサービスへのアクセスにVPCエンドポイントを設定すると、トラフィックがAWSネットワーク内に留まってEgressコストを回避できます。
# Terraform例:S3用VPCエンドポイント
resource "aws_vpc_endpoint" "s3" {
vpc_id = var.vpc_id
service_name = "com.amazonaws.ap-northeast-1.s3"
vpc_endpoint_type = "Gateway"
route_table_ids = var.route_table_ids
tags = {
Name = "s3-vpc-endpoint"
team = "platform"
}
}
マルチクラウド環境でのコスト最適化比較
AWS・Azure・GCPのKubernetesマネージドサービスには、それぞれ異なるコスト最適化の特色があります。
| 機能 | AWS EKS | Azure AKS | GCP GKE |
|---|---|---|---|
| コントロールプレーン料金 | $0.10/時間 | 無料(Standardティア) | 無料(Standardモード) |
| ノードオートスケーラー | Karpenter / CA | Karpenter(プレビュー)/ CA | GKE Autopilot / CA |
| スポット割引 | 最大90% | 最大90% | 最大91% |
| コミットメント割引 | Savings Plans(最大72%) | Reservations(最大65%) | CUD(最大70%) |
| 自動ライトサイジング | 手動 / サードパーティ | 手動 / サードパーティ | GKE Autopilotが自動 |
| コスト監視ネイティブ | Cost Explorer | Cost Management | Billing Reports |
特にGKE Autopilotは注目に値します。ノード管理をGoogleに完全に任せることで、ライトサイジングとビンパッキングの最適化を自動でやってくれるため、運用負荷とコスト両方の削減が期待できます。Kubernetesの運用に専任チームを割けない組織には特におすすめです。
コスト最適化チェックリスト
さて、ここまで読んでいただいた方に、すぐに実行できるアクションアイテムをまとめておきます。
- VPAを「Off」モードでデプロイし、全Deploymentの推奨値を確認する(まずはここから)
- requestsが実使用量の2倍以上のPodを特定し、ライトサイジングする
- EKSならKarpenterを導入し、スポットインスタンスとConsolidationを有効化する
- OpenCostまたはKubecostを導入し、Namespace・チーム別のコスト配分を可視化する
- Resource QuotaとLimitRangeを全Namespaceに設定する
- 開発・テスト環境に自動スケジュールを設定し、業務時間外はスケールダウンする
- 孤立PVC・未使用LoadBalancerを定期的に監査・削除する
- Topology Aware RoutingとVPCエンドポイントでネットワークコストを削減する
全部を一度にやる必要はありません。まずは戦略1のライトサイジングから始めて、効果を実感してから次のステップに進むのが現実的です。
よくある質問(FAQ)
Q1: Kubernetesのコスト最適化で最も効果が大きい施策は何ですか?
ライトサイジング(requests/limitsの適正化)です。Kubernetesワークロードの65%以上が要求リソースの半分以下しか使用しておらず、requestsを適正化するだけでクラスタ全体で30〜60%のコスト削減が見込めます。VPAを「Off」モードで導入して、まずは推奨値を確認するところから始めてみてください。
Q2: KarpenterとCluster Autoscalerのどちらを使うべきですか?
AWS EKSを使っているなら、2026年時点ではKarpenterが推奨です。ノードのプロビジョニングが約45〜60秒と高速で、数百のインスタンスタイプから最適なものを自動選択し、Consolidation機能でコストも自動最適化してくれます。ただし、オンプレミスとのハイブリッド環境や厳格なコンプライアンス要件がある場合は、Cluster Autoscalerの方が適していることもあります。
Q3: スポットインスタンスを本番環境で使っても大丈夫ですか?
条件付きですが、安全に使えます。ステートレスでレプリカ数が十分なワークロードであれば、Pod Disruption BudgetとTopology Spread Constraintsを適切に設定することで、スポット中断時もサービスの可用性を維持できます。ただし、シングルレプリカのワークロードやステートフルなサービスには使わないでください。
Q4: Kubernetes環境のコスト可視化はどのツールから始めるべきですか?
無料のOpenCostから始めるのがおすすめです。Helmで簡単にインストールできて、Namespace・Pod単位でのコスト配分を可視化できます。マルチクラスタ環境や割引の正確な反映が必要になった段階で、Kubecostへの移行を検討すればOKです。
Q5: GKE Autopilotは本当にコスト削減に効果がありますか?
特にKubernetesの運用経験が少ないチームには効果的です。ノード管理をGoogleに任せることで、ライトサイジングとビンパッキングが自動最適化されます。ただしPod単位の課金モデルなので、常に高い使用率を維持している環境ではStandardモードの方がお得な場合もあります。ワークロードの特性に応じて比較してみてください。