はじめに:誤ったリクエストとリミットの隠れたコスト
こんな状況を想像してみてください:あなたのチームが大規模なプロモーションキャンペーンを開始しました。マーケティングが期待した通りにトラフィックが急増しましたが、数分後に主力サービスがクラッシュしました。
ポッドが CrashLoopBackOff
状態になり、再起動が積み重なり、エンジニアが対応に追われています。原因は?単一のコンテナがメモリ制限に達し、OOMKill
がトリガーされたのです。
これはよくある話です。すべてのKubernetesエンジニアはリソース設定が重要だと知っていますが、手動で正確に設定することがいかに不可能かを理解している人はほとんどいません。
過剰にプロビジョニングすれば、お金を無駄にします。過少にプロビジョニングすれば、障害のリスクがあります。リスクは高いのに、ほとんどのチームが頼っているツールやプロセスでは、最適なポイントを見つけることがほぼ不可能です。
リクエストとリミットとは?
Kubernetesは、ポッド仕様で定義する2つの重要な値に基づいてワークロードをスケジュールします:
resources:
requests:
cpu: "500m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"
-
リクエスト: コンテナに保証されるCPUまたはメモリの量。スケジューラはこれらの数値を使用して、ポッドを配置する場所を決定します。
-
リミット: コンテナが実行時に消費できるハードキャップ。メモリリミットを超えると
OOMKill
がトリガーされます;CPUリミットを超えるとスロットリングが発生します。
主な動作の違い:
- リクエストはスケジューリングに影響します。
- リミットはランタイム実行の制限に影響します。
リクエストが高すぎると、ノードが「満杯」に見え、ビンパッキング効率の低下と不要なノードスケーリングにつながります。リミットが低すぎると、ワークロードがクラッシュします。
リソース設定における一般的な落とし穴
経験豊富なチームでさえ、これらの罠に陥りがちです:
1. 当て推量
開発者が任意の数値を設定するか、さらに悪いことに、デフォルト値をそのままにしています。これらの数値は何ヶ月も残り続け、静かに無駄やリスクを生み出します。
2. リクエストとリミットを同じ値に設定
request == limit
を設定することは安全に見えますが、バースト容量がなくなります。メモリスパイクが即座にOOMKillを引き起こします。
3. リミットなし
リミットのないコンテナは無制限にメモリを消費でき、一つの不良デプロイメントがノード全体の障害に変わる—ノイジーネイバー問題を引き起こします。
4. 過度に保守的な見積もり
障害に悩まされたSREは、しばしば過剰に割り当てます。300Miが必要なサービスに1Giのリクエストが割り当てられ、コストが3倍に膨れ上がります。
5. 動的環境での静的設定
リソースプロファイルはリリースごとに変化します。静的設定はすぐに時代遅れになります。
手動の適正化が失敗する理由
理論上、適正化は簡単に聞こえます:
「メトリクスを収集し、分析して、数値を調整するだけ」
しかし、Kubernetesを大規模に運用している人なら誰でも、これが幻想であることを知っています。なぜなのか分析してみましょう。
メトリクスは誤解を招く
メトリクスダッシュボードはしばしば平均値や95パーセンタイル値を表示します:
kubectl top pod
またはPrometheusクエリを使用して:
quantile_over_time(0.95, sum by(pod)(container_memory_usage_bytes)[5m])
しかし:
- 短時間のメモリスパイクはサンプリングデータに現れないことが多い。
- 見逃したスパイクが
OOMKill
をトリガーする原因になります。 - これを避けるため、チームは「念のため」過剰に割り当て、コストを膨らませます。
ワークロードは静止していない
現代のマイクロサービスは設計上、動的です:
- トラフィックは日々、週ごと、季節ごとに変動します。
- 機能リリースにより、メモリプロファイルが一晩で変化します。
- 昨日の「完璧な」数値が、明日の負債になります。
チューニングするサービスが多すぎる
100以上のサービスがあるクラスターでは、1サービスあたり30分かけるだけでも、チューニング作業に数日かかります。それをスプリントごとに繰り返すと、SREチームは消火活動に追われるだけになります。
ダッシュボードは何をすべきか教えてくれない
GrafanaやDatadogのダッシュボードは印象的に見えますが、核心的な質問に答えてくれません:
“リクエストとリミットをどのように設定すべきか?”
ほとんどのエンジニアは推測し、デプロイを実行し、うまくいくことを祈るだけです。
VPAは万能薬ではない
Vertical Pod Autoscaler (VPA) はこの問題を解決するために設計されましたが:
- 新しい値を適用するためにPodを再起動する必要があり、多くの本番システムでは受け入れられません。
- その推奨値は実際のトラフィック変化に遅れをとります。
- バースト的または予測不可能なワークロードでは、不正確な値が出ることがよくあります。
結論: 手動でのリソースサイジングは目隠しをしてダーツを投げるようなもの—時々的に当たることもありますが、それをするために膨大な時間とお金を無駄にします。
今後の展望
これに共感するなら、あなたは一人ではありません。業界データによると、KubernetesクラスターはしばしばCPUの10~25%、メモリの18~35%しか使用していません。
手動でのリソースサイジングは規模が大きくなると持続不可能です。将来は継続的な自動リソース最適化にあります。VPAのようなツールはその道を切り開きましたが、今私たちが必要としているのは以下のようなソリューションです:
- 変化するワークロードに継続的に適応する。
- 変更を適用する際のPod再起動をなくす。
- コストと信頼性の両方を最適化する。
💡 朗報: 今月、私たちはインテリジェントなWorkload Autoscalerをリリースします。これはPodを再起動せずに自動的にサイズを最適化し、クラスターを効率的かつ信頼性高く実行するのに役立ちます。
すでにアーリーアクセスベータを開始しており、試してみたい場合は、お気軽にお問い合わせください— あなたのSREチームはあなたに感謝するでしょう!