事故を分類する順序
一言でいうと
Podが起動しないときに、最初に数えるべきものは、残っているリソースではなく候補ノードの数です。候補が0なら、残りのリソースは何の意味もありません。
なぜ順序が決まっているのか
まず、Podオブジェクトが存在するかどうかから切り分けます。ResourceQuota公式ドキュメントが説明するクォータ違反は、作成リクエストを拒否することがあります。このときは、PendingのPodではなく、Deployment・ReplicaSetのイベントのFailedCreateとAPIエラーを探す必要があります。LimitRange違反も、アドミッション段階の問題かもしれません。
Podがあるなら、Podのライフサイクルに沿って、条件とイベントを確認します。Pendingには、スケジューリング前だけでなく、イメージの準備のような待ちも含まれます。PodScheduled条件、nodeName、コンテナの待機理由を合わせて見ます。すべてのPendingを、同じ順序のリソース不足として解釈しないでください。
このラボの仮想のインシデントは、nodeSelectorに合う候補が0の場合です。該当の条件をイベントで確認したあと、候補の数を数えます。候補があっても、テイント、affinity、ボリューム、実際のrequest量のために、配置されないことがあります。ノード割り当てドキュメントの必須の条件と優先の条件を区別してください。
どう動くのか
分類の結果は数字である必要があります
「リソースが足りないようだ」は、分類ではありません。分類は、次の4つの値を書くことです。
| 項目 | どこから得られるか |
|---|---|
| セレクターのキーと値 | ワークロードのnodeSelector |
| レプリカ数 | Deploymentのspec.replicas |
| 必要な合計CPU | コンテナのrequest × レプリカ |
| 候補ノード数 | そのセレクターでノードを数えてみた値 |
この4つの値が書かれていれば、次の人は同じ場所から始められます。書かれていなければ、次の人は最初からやり直します。インシデント記録の価値は、文章ではなく、この数字にあります。
復旧と要件の削除は、別のことです
Podを起動させる最も速い方法は、nodeSelectorを消すことです。ほかの制約がなければ、配置される可能性があります。しかし、そのセレクターは、誰かが理由があって書いておいたものです。GPUが必要だったり、特定のストレージに付く必要があったり、規制上、特定のノードにだけ載せる必要があったりするのです。
要求の根拠と変更の承認を確認せずに制約を消すと、要件の削除になることがあります。そして、この違いは画面には現れません。PodはRunningで、アラートは消え、ダッシュボードは緑ランプです。問題は、数週間後に思いがけない形で戻ってきます。
復旧は、制約を満たす側です。ノードにプールのラベルを付けるか、そのプールにノードを入れるか、それができないなら、なぜできないのかを書き、ワークロード側の要求を変える判断を、人が下すことです。
ライトサイジングには方向があります
コストを減らせという要求を受けると、ノードを先に減らしたくなります。まず、代表的な期間の使用量・ピーク・失敗・レイテンシを収集し、requestの余裕と復旧用の容量を検討します。平均の使用量だけを見て下げると、負荷の急増を見逃します。requestの調整とノードの縮小は、戻せる条件を決めて、小さな範囲でテストします。scale-to-zeroも、起動の遅延とワークロードの要件によって可能な選択肢であり、常に停止だとか、常に節約だとか断定することはできません。
現場での姿
次は、ラボのための仮想の事例です。ノードを3台増やしても、Podが依然としてPendingです。新しいノードにプールのラベルを付けておらず、ワークロードはそのラベルを要求していました。容量のグラフは上がり、候補ノードは0台のままでした。ダッシュボードだけを見ていると、永遠に見えない種類のインシデントです。
もう1つは、ラベルを付けてすぐ、採点するように確認して、「動かない」と結論づけた場合です。スケジューラーは定期的にリトライするので、数秒は待つ必要があります。すぐに確認して判断すると、正しい対処を元に戻してしまいます。
次のラボですること
3つのテナントを作って、クォータとLimitRangeで分け、オーバーコミット率を自分で計算し、Pendingのインシデントを再現して分類し、制約を消さずに復旧し、プラットフォーム自身のレコーディングルールとアラートを作って上げます。