Kubernetesを2,500ノードにスケーリング

OpenAIは、ディープラーニング研究をサポートするために、D15v2とNC24のVMの組み合わせを使用して、Azure上でKubernetesインフラストラクチャを2,500ノード以上にスケーリングしました。このスケーリング作業では、状態ストレージ、Podスケジューリング、コンテナイメージの配布、ネットワーク設定における重大なボトルネックを克服する必要がありました。

etcdのパフォーマンスと安定性の最適化

Kubernetesの状態ストレージは、クラスターが500ノードおよび1,000ノードを超えて成長するにつれて、重大なレイテンシと容量の問題が発生しました。

書き込みレイテンシの削減

クラスターが500ノードを超えると、ネットワーク接続されたSSDでの高い書き込みレイテンシにより、kubectlのタイムアウトが発生しました。OpenAIは、etcdディレクトリをインスタンスに直接接続されたローカルの一時ディスク(SSD)に移動することでこれを解決し、書き込みレイテンシを2msから200usに削減しました。

APIサーバー負荷の管理

1,000ノード時に、kube-apiserversがetcdから毎秒500MB以上を読み取っていたため、高いコミットレイテンシが再発しました。これは、各ノードからAPIサーバーに対して頻繁にポーリングを行う監視プロセス(FluentdとDatadog)によるものでした。これらのプロセスのポーリング頻度を下げることで安定性が回復しました。

イベントとストレージクォータの分離

イベント作成の急増がメインクラスターの状態に影響しないように、OpenAIは--etcd-servers-overridesフラグを使用してKubernetesイベントを別のetcdクラスターに保存しました。さらに、--quota-backend-bytesフラグを使用してデフォルトの2GB etcdストレージ制限を増やし、etcdが書き込みを受け付けなくなった後にオートスケーラーがワーカーを終了させるカスケード障害を防ぎました。

Kubeマスターとスケジューリングの調整

OpenAIはKubernetesをバッチスケジューリングシステムとして使用し、アイドルノードのコストを最小限に抑えるためにカスタムオートスケーラーを採用しています。

ビンパッキングスケジューリングポリシー

未使用のノードを終了し、大きなPodを素早くスケジュールできるようにするため、OpenAIはデフォルトのロードスプレッディングポリシーを「MostRequestedPriority」ポリシーに置き換えました。これにより、Podを均等に広げるのではなく、より少ないノードにビンパッキングするよう促されます。

KubeDNSの信頼性

ビンパッキングポリシーにより、一部のマシンでKubeDNSが10以上のコピーで実行されるホットスポットが発生し、Azure VMの外部ドメイン検索制限(約200 QPS)を超えました。OpenAIは、KubeDNS Podが異なるホスト名に分散されるようにPodアンチアフィニティルールを実装することでこの問題を解決しました。

Dockerイメージプルの高速化

Dotaプロジェクトで使用される17GBのイメージなどの大規模なコンテナイメージにより、Podが長時間Pending状態のままになることがありました。

プルの並列化とタイムアウトチューニング

デフォルトでは、kubeletはイメージプルをシリアル化します(--serialize-image-pulls=true)。これにより、1つの大きなイメージが他のすべてのプルをブロックする可能性があります。OpenAIはこれをfalseに設定し、Dockerのストレージドライバーをoverlay2に変更しました。また、Dockerのルートをインスタンスに接続されたSSDに移動しました。

大きなイメージの抽出が遅いために発生するrpc error: code = 2 desc = net/http: request canceledエラーを防ぐため、彼らは--image-pull-progress-deadlineを30分に増やし、Dockerデーモンでmax-concurrent-downloadsを10に設定しました。

一般的なイメージのプリロード

ノードがNATを介してGoogle Container Registry(gcr.io)にアクセスする際に、IPごとのクォータ制限に達しないように、OpenAIはdocker image savedocker image loadを使用して、pod-infra-container-imageなどの一般的な内部イメージをワーカーマシンイメージに直接プリロードしています。

ネットワークとカーネルのチューニング

大規模な分散実験により、ネットワークスタックに関連するスループットの大幅な低下と接続問題が明らかになりました。

Flannelオーバーヘッドの克服

OpenAIは、Flannelを使用するPodのスループットが約2Gbit/sに制限されていることを観察しました。一方、ベアメタルマシン間では10-15Gbit/sです。高パフォーマンスワークロードでのこのオーバーヘッドを回避するため、ユーザーはPodに対してhostNetwork: trueおよびdnsPolicy: ClusterFirstWithHostNetを設定できます。

ARPキャッシュオーバーフローの解決

間欠的なDNS解決失敗と接続ハングは、大規模クラスターの各PodがARPエントリを消費するため、カーネルのARPキャッシュが空き容量を使い果たすことが原因でした。これは、dmesgに出力されるneighbor table overflow!メッセージで特定されました。OpenAIは、/etc/sysctl.confでのARPキャッシュしきい値を増加させることでこの問題を解決しました:

net.ipv4.neigh.default.gc_thresh1 = 80000
net.ipv4.neigh.default.gc_thresh2 = 90000
net.ipv4.neigh.default.gc_thresh3 = 100000

Sources

関連