深夜2時に鳴り響くクラウド請求アラート
深夜2時、PagerDutyのアラートがけたたましく鳴り響きます。今回はDBダウンでもネットワーク障害でもありません。AWSからの予算超過アラートでした。EKSクラスタの今月の請求額が、わずか5日間で1,800ドルも急増していたのです。慌ててAWS Cost Explorerを確認しても、EC2ワーカーノード全体の合算金額が表示されるだけ。AWSやGCPは実行中のVM単位でしか課金しません。クラスタ内部でどのネームスペース、どのマイクロサービス、あるいはどのチームが密かに「費用を燃やし続けている」のかまでは教えてくれないのです。
従来のGrafanaダッシュボードで見えるのはハードウェアのリソース使用状況だけでした。「Pod AがCPUを8コア消費し、Pod Bが16GBのRAMを消費している」ことは把握できても、Pod Aが1時間あたり何ドル消費しているのかは誰にも答えられません。この課題を解決するには、稼働中のコンテナメトリクスに実際のインフラ料金表を紐付ける必要があります。そこで真価を発揮するのがOpenCostです。
OpenCostはPrometheusとどのように連携するのか?
OpenCostはCNCF Sandboxプロジェクトであり、Kubecostの裏側を支えるコスト計算エンジンそのものです。その主なミッションは、Kubernetesのコストをリアルタイムに計測・配分することにあります。
価格算出とコスト内訳の仕組み
ワーカーノード上で動作する各Podは、基盤となるハードウェアリソースを消費します。OpenCostはPodのリクエスト値および実際のリソース使用量を取得し、AWS、GCP、AzureのVM価格表、または独自定義したオンプレミスの価格表と直接照合します。
- CPU & RAM Cost: コンテナが要求したリソース(requests)のノード総容量に対する割合を算出し、そのインスタンスタイプの1時間あたりのレンタル料金を掛け合わせます(例: AWS us-east-1のc5.2xlargeは0.34ドル/時間)。
- Storage Cost: StorageClass(GP3、io2など)およびPersistent Volume Claim(PVC)の実際の容量に基づいて直接算出します。
- Network Cost: インターネット向けの下り通信(egress)、アベイラビリティゾーン間(cross-zone)、またはリージョン間(cross-region)のデータ転送量を計測します。
強力なタッグ:OpenCostとPrometheus
OpenCostはゼロから独自のエクスポーターを開発するのではなく、既存のPrometheusを最大限に活用します。クラスタ内のcAdvisorやkube-state-metricsからデータを入力として収集し、計算エンジンとして機能します。定期的にリソースメトリクスを照会してVM単価を掛け合わせ、コストメトリクス(node_cpu_hourly_costやopencost_allocation_cpu_cost_hourlyなど)として出力します。これをPrometheusが再度スクレイプし、Grafanaに可視化します。
KubernetesにOpenCostをデプロイする手順
この記事では、クラスタにPrometheus Operator(kube-prometheus-stack)が導入済みであることを前提としています。連携作業は10分もかからずに完了します。
ステップ1:Namespaceの作成とPrometheusエンドポイントの確認
まずは、OpenCost用のリソースを分離するために専用のネームスペースを作成します。
kubectl create namespace opencost
次に、Prometheusの内部Serviceアドレスを確認します。kube-prometheus-stackを使用している場合、通常は以下の形式になります。
http://prometheus-operated.monitoring.svc.cluster.local:9090
標準的なPrometheus構成の場合は、http://prometheus-k8s.monitoring.svc.cluster.local:9090などがエンドポイントになります。
ステップ2:Helmを使用したOpenCostのインストール
OpenCostの公式リポジトリを追加します。
helm repo add opencost https://opencost.github.io/opencost-helm-chart
helm repo update
設定ファイル values-opencost.yaml を作成します。PrometheusのService名と利用中のクラウドプロバイダーが正しく設定されていることを確認してください。
opencost:
prometheus:
internal:
serviceName: "prometheus-operated"
namespaceName: "monitoring"
port: 9090
exporter:
defaultClusterId: "production-k8s-cluster"
cloudProvider: "AWS" # 環境に合わせてGCPまたはAzureに変更
ui:
enabled: true
serviceMonitor:
enabled: true
namespace: opencost
additionalLabels:
release: kube-prometheus-stack
クラスタにインストールコマンドを実行します。
helm install opencost opencost/opencost \
--namespace opencost \
-f values-opencost.yaml
ステップ3:Podの状態とログの確認
Podが正常に起動し、Prometheusとスムーズに通信できていることを確認します。
kubectl get pods -n opencost
# ログを確認してメトリクス取得の流れをチェック
kubectl logs -n opencost -l app.kubernetes.io/name=opencost -c opencost --tail=50
ログに Querying Prometheus at http://prometheus-operated... が出力され、クラウド価格表のダウンロード成功通知が表示されていれば、正常に動作しています。
ステップ4:OpenCost UIへのアクセス
Ingressの複雑な設定を行わなくても、ポートフォワードを使用すればすぐにダッシュボードを確認できます。
kubectl port-forward --namespace opencost service/opencost-ui 9090:9090
ブラウザで http://localhost:9090 を開きます。目的に応じて柔軟にコストをフィルタリングできます。
- Namespace: データチームが1日あたり45ドル消費しているのか、Core APIチームが12ドル消費しているのかが一目でわかります。
- Controller / Deployment: 各マイクロサービス単体のコストを詳細に把握できます。
- Cost Allocation Window: 1時間単位、日次、または直近30日間の請求推移を確認できます。
ステップ5:コストアラート用のPromQLクエリの作成
OpenCostは標準的なメトリクス形式でデータを出力するため、Alertmanagerを介して直接アラートを作成したり、Grafana上にパネルを構築したりできます。
Namespaceごとの1時間あたりの合計コストを算出:
sum(opencost_allocation_cpu_cost_hourly + opencost_allocation_ram_cost_hourly) by (namespace)
Podが過剰にリソースを要求したものの使い切れていない、無駄なCPUコスト(アイドルコスト)を算出:
sum(opencost_allocation_cpu_idle_cost_hourly) by (namespace)
この指標は極めて有用です。ビジネス的な価値を一切生み出していないアイドル状態のCPUに、いくら支払っているのかを明確に突き止められます。
まとめ
月末の請求書を開く瞬間に冷や汗を流すのはもう終わりにしましょう。OpenCostとPrometheusを組み合わせることで、Kubernetesのあらゆる費用をリアルタイムかつ透明に可視化できます。どのコンテナがリソースを無駄遣いしているのかを正確に把握できれば、requests/limitsの適正化や20〜30%のインフラコスト削減は驚くほど容易になります。

