何が実物で何が真似なのか
一言でいうと
このラボのPodには、本物のGPUも、本物のcontainerdも、GPU Operatorもありません。代わりに、TOMLパーサーと本物のKubernetesコントロールプレーンがあり、今回の障害で人を捕まえたものは、ほとんどすべてその2つで再現できます。
なぜ偽の環境でこれを行うのか
GPUの障害から実際に学ぶべきことを1つずつ数えると、こうなります。
- 2つの設定ファイルが同じテーブルでぶつかるかを判定する方法 → パーサーがあれば十分です
- ファイルではなく、読み込まれたものを見る点検スクリプトを書く方法 → シェルがあれば十分です
- リソースのアドバタイズがないと、Podがどこで止まるのか → スケジューラーが本物である必要があります
- タイムスライシングの設定で、スロット数とメモリを計算する方法 → 算数があれば十分です
- ロールアウトが1台のノードで止まった様子 → DaemonSetコントローラーが本物である必要があります
この一覧にnvidia-smiはありません。GPUデバイスに実際に触れないと学べないものは、ドライバーのビルドと実際のカーネル実行の性能ですが、その2つは今回の障害の原因ではありませんでした。原因はすべて、設定とオブジェクトにありました。
何が本当に検証され、何が模擬なのか
| ラボで行うこと | この環境での位置づけ |
|---|---|
| containerdの設定をTOMLで書いてパースする | 実物です。本物のパーサーが読みます |
| メイン設定とドロップインのテーブルの衝突を判定する | 実物です。計算がそのまま合います |
| 点検スクリプトの動作を検証する | 実物です。偽のcontainerdを立てて、2回実際に実行します |
| RuntimeClassの登録 | 実物です。本物のAPIサーバーが保存します |
| GPUリソースのアドバタイズとスケジューリング | 実物です。本物のスケジューラーが判定します |
| DaemonSetのローリングアップデートの停止 | 実物です。本物のコントローラーが止まります |
| ノードにGPUが実際に接続されていること | 模擬です。ノードのstatusに数字を書くだけです |
| コンテナの中でGPUを使うこと | ありません。コンテナが実行されません |
| containerdを再起動してハンドラーが登録されること | ありません。概念と点検スクリプトでだけ扱います |
特に最後の行を、はっきりさせておきます。SIGHUPではだめで再起動が必要だという事実は、このPodでは実証できません。そのためラボは、その代わりに、「再起動の有無にかかわらず、真実を教えてくれる点検スクリプト」を作らせます。現場でその知識が手を動かす形で現れる場所が、まさにそのスクリプトです。
現場でそのまま使えるもの
ラボで作る出力物のうち3つは、そのまま会社に持ち帰れます。
check-runtime.sh: ノードの起動後の点検や、CIのゲートに、そのまま設定します。判定の基準がファイルではなくdumpであることが核心で、その性質は環境とは無関係です。- スロットの計算表: タイムスライシングを有効にする前に、ユーザーに見せる表です。「枠は20個、保証されるメモリは0」という2行が、会話の半分を終わらせます。
- ロールアウト停止のレポート: どの欄を見て何を判断したのかが残ります。障害レポートの骨格はこれです。
本物のGPUノードで変わること
このラボが模擬のまま残した部分で、現場がどう違うのかを知っておくと、あとで実物の前に立ったときに慌てずに済みます。
ドライバーとカーネルは一緒に動きます。GPUドライバーはカーネルモジュールなので、カーネルのバージョンが変わると、再ビルドが必要です。そのため、ノードがカーネルを自動で更新する設定だと、再起動のあとにGPUが消えたままノードがReadyで上がってきます。Podはスケジュールされ、コンテナも起動するのに、デバイスだけがない状態なので、症状は「GPUが見つからない」というアプリケーションのエラーとしてしか現れません。ノードのラベルにドライバーのバージョンを付けて、それが消えたらスケジュールを止めるのが、標準的な防御です。
リソースのアドバタイズは、複数の層を通ります。デバイスプラグインがkubeletに登録し、kubeletがノードのstatusに載せ、スケジューラーがそれを見ます。どの層で途切れても、結果は同じく「PodがPending」です。そのため、調査は上から下へ下りていきます。ノードのstatusにリソースがあるか → なければkubeletのログ → デバイスプラグインのPodの状態 → そのPodがソケットディレクトリを正しくマウントしているか。この順序を決めておかないと、毎回違う場所から調べることになります。
GPUの共有方式は何通りもあります。タイムスライシングは順番に回して使うものなので、メモリが分離されず、1つのPodがメモリを使い切ると、残りも一緒に落ちます。MIGはハードウェアでそもそも分けるので、分離は確実ですが、分けられる組み合わせが決まっていて、変更するときはノードを空にする必要があります。「分離が必要ならMIG、利用率が目的ならタイムスライシング」というのが実務の基準線であり、この選択をユーザーに説明できる必要があります。
まとめると、このラボで身につけるのは、判定する順序と、根拠を残す方法です。この2つは、GPUが本物か模擬かにかかわらず、そのまま使えます。実物の前で新しく学ぶ必要があることは、上の3つの段落程度に絞られます。
次のラボですること
8つのステップで、障害を最初からもう一度たどります。前の4つのステップはノードの設定ファイルを扱い、後ろの4つのステップはクラスターのオブジェクトを扱います。最後の2つのステップは、これまでに作ったものを集めて、計算とレポートで締めくくります。