PerfectScale
ノードアフィニティ完全ガイド例・活用シーン・実践のヒント
このページはEnglish、Deutsch、Español、Français、Italiano、Portuguêsでもご覧いただけます。
About Josh Palmer
Head of Content
I'm Josh Palmer, Head of Content at DoiT, where I split my time across multiple business units including DoiT Cloud Intelligence, PerfectScale (Kubernetes cost optimization), and SELECT (Snowflake, Databricks, and BigQuery cost optimization). Before DoiT, I spent four and a half years at OnBoard building content for a board intelligence platform used by 6,000+ organizations, and before that, two years as Content Marketing Manager at Zylo, a SaaS management platform.
My personal page要約 ノードアフィニティを使うと、ノードラベルに基づいてPodを実行できるノードを制限できます。ハードルール(requiredDuringSchedulingIgnoredDuringExecution)とソフトルール(preferredDuringSchedulingIgnoredDuringExecution)の2種類があり、nodeSelectorよりも表現力に優れています。GPU/SSDノードの指定、特定ゾーンへのワークロード配置、本番環境と開発環境の分離などによく使われます。ノードラベルを標準化し、配置が必須でない限りソフトルールを優先し、アフィニティをオートスケーリングやワークロードのサイジングと整合させることで、PodがPendingのまま滞留するのを防ぎましょう。
この記事の内容
Kubernetesのノードアフィニティとは
Kubernetesのノードアフィニティは、ノードに付与されたラベルに基づいて、Podをスケジュールできるノードを制限するためのルールの集合です。nodeSelectorよりも表現力が高く、複雑なスケジューリングロジックを記述できます。ソフトルールとハードルールの両方をサポートしており、SSDやGPUといった特定のラベル付きハードウェアにPodを配置できます。
この機能は、ワークロードごとにハードウェア要件や配置場所の要件が異なるマルチテナント、ハイブリッド、あるいは異種混在のKubernetesクラスタで特に威力を発揮します。ノードアフィニティによってワークロードを最適な特性を持つノードにマッチさせることで、リソース使用率の最適化、機密性の高いワークロードの分離、アプリケーション性能の向上が可能になります。
ノードアフィニティの主な種類
- ハードルール(requiredDuringSchedulingIgnoredDuringExecution) スケジューラーは条件に一致するノードを必ず見つけてPodを配置しなければなりません。見つからない場合、PodはPending状態のままになります。
- ソフトルール(preferredDuringSchedulingIgnoredDuringExecution) スケジューラーは条件に一致するノードへの配置を試みますが、該当するノードがない場合でも、Podは他のノードにスケジュールされます。
使用例(YAML)
spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: disktype operator: In values: - ssd本記事は、Kubernetesスケジューリングに関するシリーズ記事の一部です。
Kubernetesにおけるノードアフィニティの仕組み
ノードアフィニティを支える主要な技術要素を紹介します。
ノードラベル
ノードラベルは、Kubernetesのノードに付与されるキーと値のペアで、ノードの属性を表します。ラベルは任意に設定でき、インスタンスタイプ、リージョン、アベイラビリティゾーン、あるいはワークロードのスケジューリングに関わるカスタムメタデータなどを表現できます。たとえば、SSDストレージやGPUアクセラレーションを備えたノードを識別するために、disktype=ssdやgpu=trueといったラベルを付与します。
ラベルは、ノードをクラスタに追加する際、またはインフラの変化に応じて動的に、クラスタ管理者や自動化スクリプトによって設定されます。アフィニティルールはこれらのラベルを頼りにPodの配置先ノードを選択するため、一貫性があり意味の明確なラベル付けが、ノードアフィニティを効果的に機能させる鍵となります。適切なラベル付けにより、スケジューラーが配置ポリシーを正しく解釈し、確実に適用できるようになります。
ノードアフィニティの演算子
ノードアフィニティのルールでは、Podがノードラベルとどのようにマッチするかを演算子で定義します。よく使われる演算子はIn、NotIn、Exists、DoesNotExistです。InとNotInは特定のラベルに対して許容する値・許容しない値を指定でき、ExistsとDoesNotExistは値にかかわらずラベルキーの有無をチェックします。
これらの演算子により、複雑なスケジューリング要件を柔軟に表現できます。たとえば、environment=productionのノードでのみPodを実行させたり、dedicated=backupのノードを避けたりできます。演算子とラベルセレクターを組み合わせることで、ワークロードの要件や組織のポリシーに合わせてPodの配置を細かく調整できます。
スケジューラーの動作
Kubernetesのスケジューラーは、Podの配置先を決定する際にノードアフィニティのルールを評価します。Pod仕様に定義されたアフィニティ条件と、利用可能なノードのラベルを照合し、必須のアフィニティルールを満たすノードがあれば、そのノードがPodのスケジューリング対象になります。満たすノードがなければ、適切なノードが利用可能になるまでPodはスケジュールされないままになります。
ノードアフィニティには、必須(ハード)と優先(ソフト)の2種類があります。必須ルールはPodをスケジュールするために必ず満たされる必要がありますが、優先ルールはスケジューラーの選択に影響を与えるだけで、優先ノードがない場合でもスケジューリングを妨げません。この区別により、厳格な配置戦略と柔軟な配置戦略の両方が可能になり、運用上のニーズとリソースの可用性のバランスを取ることができます。
ノードアフィニティのYAML構文ハードルールとソフトルール
1. RequiredDuringSchedulingIgnoredDuringExecution
requiredDuringSchedulingIgnoredDuringExecutionは、Podをノードにスケジュールする前に必ず満たすべきハードなノードアフィニティルールを定義します。スケジューラーは、指定されたすべての条件にラベルが一致するノードのみを対象とします。一致するノードがない場合、適切なノードが現れるまでPodはPending状態のままになります。
このタイプのアフィニティは、インフラ要件が厳格なワークロードで一般的に使われます。たとえば、機械学習アプリケーションはGPU搭載ノードを必要とする場合があり、コンプライアンス要件の厳しいワークロードは特定のリージョンやアベイラビリティゾーンでのみ実行する必要がある場合があります。
IgnoredDuringExecutionの部分は、スケジューリング後にノードラベルが変更されてもKubernetesがPodを退避させないことを意味します。ノードラベルが後から削除・変更されても、別の仕組みが再スケジューリングをトリガーしない限り、実行中のPodはそのノードで動作し続けます。
コード例
affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: disktype operator: In values: - ssdこの例では、Podはdisktype=ssdのラベルが付いたノードでのみ実行できます。
2. PreferredDuringSchedulingIgnoredDuringExecution
preferredDuringSchedulingIgnoredDuringExecutionは、必須ではないもののスケジューリングの判断に影響を与えるソフトなアフィニティルールを定義します。スケジューラーは優先条件に一致するノードへのPod配置を試みますが、必要に応じて他のノードにもスケジュールできます。
優先アフィニティルールは重み付けの仕組みを使います。各優先条件には1〜100の重み(weight)を設定します。重みの大きい条件に一致するノードは、スケジューリング時により高いスコアを得るため、選択される可能性が高くなります。
このアプローチは、配置の優先条件が性能やコスト効率の向上につながるものの、必須ではない場合に有効です。たとえば、遅延を抑えるためにSSD搭載ノードや特定のゾーンでのワークロード実行を優先しつつ、リソース不足時には他の場所へのスケジューリングを許容できます。
コード例
affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 50 preference: matchExpressions: - key: disktype operator: In values: - ssdこの例では、Kubernetesはdisktype=ssdのラベルが付いたノードを優先しますが、SSD搭載ノードがない場合でもPodは他のノードで実行できます。
ノードアフィニティの主なユースケース
GPUワークロードをGPUノードで実行する
ノードアフィニティは、KubernetesクラスタでGPUワークロードを実行する際に使われます。GPU対応ノードにgpu=trueなどのキーでラベルを付けることで、GPUリソースを必要とするPodが互換性のあるハードウェアにのみスケジュールされるようにできます。これにより、GPUに依存するワークロードのリソース競合を防げます。
重要度の低いシナリオでCPUノードへのフォールバックが許容できる場合は、ソフトアフィニティを使用できます。
データベースをSSDノードにスケジュールする
データベースは高いI/O性能を必要とすることが多く、SSD搭載ノードはそれを提供できます。ノードにdisktype=ssdのラベルを付け、データベースPodに必須のノードアフィニティを設定することで、ステートフルなワークロードに高いストレージ性能と低遅延を確保できます。
新しいSSDノードが追加されラベル付けされると、データベースPodはそのノードへのスケジューリング対象になります。
ワークロードを特定のアベイラビリティゾーンに留める
ワークロードを特定のアベイラビリティゾーンで実行することで、遅延の低減、耐障害性の向上、規制要件への対応が可能になります。ノードにzone=us-west1-bのようなゾーン識別子のラベルを付け、Pod仕様でノードアフィニティを指定することで、ゾーンをまたいだPodの分散を制御できます。
優先アフィニティを使えば、スケジューラーを目的のゾーンへ誘導しつつ、リソースが逼迫している場合には他のゾーンへのフォールバックを許容できます。
本番ワークロードと開発ワークロードを分離する
共有クラスタで本番環境と開発環境を分離することは、ノードアフィニティの一般的なユースケースです。ノードにenv=prodやenv=devのラベルを付けることで、開発ワークロードが本番ノードで実行されること(およびその逆)を防ぐ配置ポリシーを適用できます。
必須ノードアフィニティでは厳格な分離を強制でき、優先アフィニティではリソースが限られた状況での柔軟性を確保できます。
ノードアフィニティ vs ノードセレクター vs Podアフィニティ
ノードアフィニティ、ノードセレクター、PodアフィニティはいずれもKubernetesのスケジューリング機構ですが、それぞれ解決する配置の課題が異なり、柔軟性のレベルも異なります。
ノードセレクターは最もシンプルな選択肢です。特定のラベルを持つノードでのみPodを実行できるようにします。disktype=ssdのような完全一致のキーと値を使うため、設定は簡単です。ただし、nodeSelectorは単純な等価一致しかサポートせず、複数の値や除外ルールといった高度な条件は表現できません。
ノードアフィニティは、In、NotIn、Exists、DoesNotExistといった高度なマッチング演算子をサポートすることで、nodeSelectorの機能を拡張します。必須と優先の両方のスケジューリングルールにも対応しており、管理者はPodの配置をより細かく制御できます。ノードアフィニティは通常、特定のハードウェア、リージョン、運用上の役割を持つノードにワークロードを配置する必要がある場合に使われます。
Podアフィニティは、ノードラベルではなくPod同士の関係に着目する点で異なります。特定のラベルを持つ他のPodの近く(通常は同じノードやアベイラビリティゾーン内)にPodをスケジュールできます。これは、密結合したサービス間のネットワーク遅延を減らすのに有効です。Kubernetesは、可用性と耐障害性を高めるためにPodを分散配置するPodアンチアフィニティもサポートしています。
主な違いを以下の表にまとめます。
| 機能 | ノードセレクター | ノードアフィニティ | Podアフィニティ |
|---|---|---|---|
| 対象 | ノードラベル | ノードラベル | 他のPod |
| 複雑さ | シンプル | 高度 | 高度 |
| サポートされる演算子 | 等価一致のみ | 複数の演算子 | ラベルセレクター |
| ハード/ソフトルール | 非対応 | 対応 | 対応 |
| 主なユースケース | 基本的なノード選択 | 柔軟なノード配置 | Podの同居または分散 |
ノードアフィニティを効果的に活用するためのヒント
1. アフィニティルールを書く前にノードラベルを標準化する
ノードアフィニティはノードラベルに依存するため、ラベル付けに一貫性がないと、スケジューリングの失敗や予測不能なPod配置につながります。アフィニティポリシーを作成する前に、明確なラベル付け戦略を定義しましょう。環境、ハードウェアタイプ、リージョン、ワークロードの役割、ストレージクラスなどのラベルには、一貫した命名規則を使用します。
たとえば、env=prod、disktype=ssd、workload=batchといったラベルに統一します。gpu=trueとaccelerator=gpuのように、同じ概念を表す複数のラベルを作ることは避けましょう。
可能な限りラベル管理を自動化しましょう。クラウドプロバイダーやクラスタプロビジョニングツールの多くは、インスタンスタイプ、ゾーン、ノードプールに対する自動ラベル付けをサポートしています。自動化により手動設定のミスが減り、新しいノードが既存のアフィニティポリシーと確実に整合するようになります。
2. 配置が必須でない限りソフトルールを優先する
ハードアフィニティルールは、一致するノードが利用できない場合にワークロードをスケジュール不能にする可能性があります。requiredDuringSchedulingIgnoredDuringExecutionを多用すると、スケーリングイベント、メンテナンスウィンドウ、ノード障害の際にクラスタの柔軟性が損なわれるおそれがあります。
優先アフィニティルールは、より回復力のあるスケジューリング動作を実現します。Kubernetesが理想的なノードを優先しつつ、必要に応じて他の場所にワークロードを配置できるためです。
ハードアフィニティは、GPUに依存するアプリケーション、ライセンス上の制約があるワークロード、コンプライアンス要件の厳しいシステム、特定のハードウェア機能を必要とするアプリケーションなど、配置が必須の場合にのみ使用しましょう。
3. ノードアフィニティとノードオートスケーリングを整合させる
ノードアフィニティはクラスタのオートスケーリングポリシーと整合している必要があります。ワークロードが特定のラベルを持つノードを必要とする場合、オートスケーラーが一致するノードグループをプロビジョニングできなければなりません。そうでないと、オートスケーリングが有効でもPodがPending状態のまま滞留する可能性があります。
たとえば、GPUワークロードはGPUインスタンス専用のノードプールを、ストレージ集約型のワークロードはSSD搭載のノードグループを対象にすべきです。
オートスケーラーの上限が想定されるワークロードの成長に対応できるかも確認しましょう。クォータ制限や設定上の制約によりオートスケーラーが一致するノードを追加作成できない場合、アフィニティルールがデプロイをブロックする可能性があります。
4. アフィニティをワークロードのライトサイジングと組み合わせる
ノードアフィニティは、ワークロードが適切にサイジングされているときに最も効果を発揮します。CPUやメモリのリクエストが過剰にプロビジョニングされていると、アフィニティルールに一致するノードがあってもスケジューリングの選択肢が制限されることがあります。
たとえば、厳格なアフィニティ要件と過剰なメモリリクエストを持つPodは、一致するノードが存在するにもかかわらずスケジュールされないままになる場合があります。
アフィニティポリシーと合わせて、ワークロードのリソースリクエストとリミットも見直しましょう。監視ツールやKubernetesのメトリクスを使えば、リクエストした量より一貫して少ないリソースしか消費していないワークロードを特定できます。
5. ワークロードの変化に合わせてアフィニティポリシーを見直す
インフラやアプリケーションの要件は時間とともに変化するため、ノードアフィニティのポリシーは定期的に見直すべきです。かつては意味のあったラベルも、クラスタのアップグレード、移行、アーキテクチャの変更によって古くなることがあります。
定期的なレビューは、不要な制約、使われていないラベル、クラスタの効率を下げるスケジューリングポリシーの特定に役立ちます。
運用レビューにはプラットフォームチームとアプリケーションチームの両方が参加し、不必要なスケジューリングの複雑さを増やすことなく、アフィニティルールがワークロードの要件に合致し続けているかを確認しましょう。
PerfectScaleでノード配置とリソース効率を最適化
ノードアフィニティを使えばワークロードの実行場所を制御できますが、リソースのリクエストとリミットが不適切だと、適切に配置されたPodであってもキャパシティを浪費したり、不要なノードスケーリングを引き起こしたりします。過剰にプロビジョニングされたコンテナはオートスケーラーに必要以上のノードを起動させ、過少にプロビジョニングされたコンテナは、アフィニティルールで厳選したまさにそのノード上でOOM killや退避を引き起こし、非効率なビンパッキングはラベル付きノードの使用率を低下させます。PerfectScaleは、ワークロードを自律的にライトサイジングし、ノードレベルの深い可視性を提供することでKubernetesの効率を高め、アフィニティポリシーで配置されるPodが、最初から効率を最大限に高める構成のノードで稼働するようにします。
PerfectScaleの主な機能
- 自律的なワークロードのライトサイジング ワークロードを継続的に分析し、実際の使用量に基づいてCPUとメモリのリクエストおよびリミットを適正化することで、アフィニティルールでスケジュールされたPodがリソースを効率的に使えるようにします。
- ノードレベルの可視化と最適化 ノードとノードプール全体を俯瞰的に可視化し、ノードアフィニティやtaintを実際のワークロードのスケジューリングパターンと照らして検証し、各ワークロードに最適なノードタイプの選定を支援します。
- プロアクティブな設定修正 CPU Request Not Set、Memory Request Not Set、Memory Limit Not Setといった、退避、ノードのオーバーコミット、丁寧にラベル付けしたノード上での非効率なスケジューリングの原因となる設定ミスを特定します。
- オートスケーリングの効率化 KarpenterやCluster Autoscalerなどのオートスケーラーが適切なノードタイプとサイズをプロビジョニングできるようワークロード設定を微調整し、アフィニティに基づく配置を予測可能かつコスト効率の高い状態に保ちます。
アフィニティによるスケジューリングを、効率的で適切にサイジングされたノードで確実に実現しませんか?PerfectScaleの詳細はこちら。
よくある質問
ハードとソフトのノードアフィニティの違いは何ですか
ハードルール(requiredDuringSchedulingIgnoredDuringExecution)は必ず満たされる必要があり、満たされない場合PodはPendingのままになります。ソフトルール(preferredDuringSchedulingIgnoredDuringExecution)は優先条件であり、スケジューラーは可能な限り尊重しようとしますが、必要に応じてPodを他の場所に配置します。
ノードアフィニティとnodeSelectorの違いは何ですか
nodeSelectorは単純な完全一致のラベルルールのみをサポートします。ノードアフィニティは、より豊富な演算子(In、NotIn、Exists、DoesNotExist)に加え、必須と優先の両方のスケジューリングロジックをサポートします。
ノードアフィニティとPodアフィニティの違いは何ですか ノードアフィニティはPodをノードラベルとマッチさせます。Podアフィニティ(およびアンチアフィニティ)はPodを他のPodの配置とマッチさせるもので、通常は関連するワークロードの同居や分散に使われます。
ノードアフィニティを設定したらPodがPendingのまま動きません。なぜですか
多くの場合、ハード(required)ルールに一致するノードが存在しないことが原因です。ノードラベルを確認し、オートスケーラーが一致するノードをプロビジョニングできるか検証し、Podのリソースリクエストが一致するノードに対して過大でないかを確認しましょう。
ソフトルールではなくハードルールを使うべきなのはどんなときですか 配置が本当に必須の場合のみです。GPUに依存するワークロード、ライセンス上の制約、コンプライアンスやデータレジデンシーの要件などが該当します。それ以外の場合は、スケジューリングの柔軟性を保つためにソフトルールを優先しましょう。
ノードのラベルを変更すると、すでに実行中のPodに影響しますか いいえ。ルールは「IgnoredDuringExecution」であるため、スケジュール後にノードのラベルが変更されても、実行中のPodは退避されません。