Cloud Intelligence™
多くのGKEクラスタでまだ使われていない機能、カスタムComputeClasses
このページはEnglish、Deutsch、Español、Français、Italiano、Portuguêsでもご覧いただけます。
About Chimbu Chinnadurai
Senior Cloud Architect II
I've probably debugged a Kubernetes issue in more time zones than I care to count. Based in London, I help engineering teams across EMEA get their clusters to behave — and actually understand why they misbehaved in the first place.
I write, speak, and guest on podcasts about all things cloud-native. Away from the terminal: I enjoy cooking almost as much as simplifying overly complex systems.
My personal page私が実施するGKEクラスタレビューでは、ほぼ毎回同じパターンを目にします。単一のマシンタイプに紐づいた静的ノードプールが延々と並んでいるのです。汎用ワークロード用の n2-standard-8 プール、メモリを大量に消費するサービス用の n2-highmem-16 プール、昨年のコスト削減施策で誰かが作成したSpotプール、そして場合によってはGPUプール。ワークロードは、長年にわたって積み上げられてきた nodeSelector、taint、toleration、ノードアフィニティルールを通じてノードにスケジュールされています。
何かが変化するまでは、この構成でも回ります。そして崩れるきっかけは、たいてい次の3つのいずれかです。
ゾーンの在庫切れ: 選択したマシンシリーズがゾーン内で不足します。Cluster Autoscalerは指定された特定のプールしかスケールできないため、同じゾーンで別のマシンファミリーに空きがあっても、Podは
Pendingのまま止まります。Spotプリエンプションの罠: 大規模なSpotプリエンプションが発生すると、ワークロードはオンデマンドのフォールバックプールに溢れます。容量が回復しても、ワークロードを能動的に戻す仕組みはないため、見込んでいたコスト削減は請求書に一向に現れません。
マシン世代のアップグレード: N2からN4やC4への移行は、数週間がかりの運用作業になります。新しいプールのプロビジョニング、数十のリポジトリにまたがるHelmの値の更新、古いノードのドレイン、そして古いラベルをハードコードしたマニフェストがないことを祈る——という具合です。
GKEには、この3つすべてに対する答えがすでに用意されています。カスタムComputeClassesです。私が話をするお客様は、この機能を知らないか、Autopilot専用だと思い込んでいるかのどちらかです。実際にはそうではありません。カスタムComputeClassesはGKE 1.30.3-gke.1451000以降、AutopilotとStandardの両モードで利用でき、対象となるすべてのクラスタでデフォルトで有効になっています。
カスタムComputeClassとは
ComputeClassは、ワークロードが優先するノードプロファイルを優先度順に指定するKubernetesカスタムリソース(computeclasses.cloud.google.com)です。Googleのドキュメントが説明するとおり、自動スケーリングイベント時にGKEが使用するノード属性のプロファイルを提供するものです。
従来のノードプール: まずインフラを宣言し、その上にワークロードを誘導します。
ComputeClasses: 目指す状態を宣言し(「まずN4 Spotを試す。利用できなければC4 Spot。それもだめならN4オンデマンドにフォールバック」)、オートスケーラーが適切なノードを自動的にプロビジョニングします。
これにより責務が分離されます。プラットフォームチームがハードウェアプロファイルを定義し、アプリケーション開発者は名前でプロファイルを選ぶだけです。
実運用で何が解決されるのか
- 在庫切れが自動フォールバックになる: 優先度の高いルールがクォータやゾーンの空き状況で失敗した場合、GKEは即座にリスト内の次のルールを試みます。
- フォールバック容量が居座らない: アクティブマイグレーションを有効にすると、優先する容量が回復した時点でGKEがワークロードを優先度の高いノードへ戻し、コスト削減を自動的に取り戻します。
- アップグレードはプラットフォーム側で完結: ワークロードをN2からN4へ移したり、C4を試したりする作業は、ComputeClassマニフェストを1つ更新するだけです。アプリケーションチームがセレクタに触れる必要はありません。
このほかにも細かな利点があります。どのCompute Engine予約を先に消費するかを一元的に決められるほか、各クラスが低使用率ノードをどれだけ積極的に統合するかを調整でき、ネームスペースやクラスタ全体にデフォルトクラスを設定して、セレクタを書かなくても妥当なハードウェアが各チームに割り当てられるようにできます。
主要な設定項目
spec.priorities の下で、各ルールは主となるハードウェアターゲットを定義します。machineFamily(例:n4)、machineType(例:n4-standard-32)、gpu または tpu です。Standardクラスタでは、ルールから nodepools で既存のノードプールを指定することもできます。ルールには spot、minCores、minMemoryGb、ブートディスク設定、ローカルSSD、セカンダリブートディスク、予約、ゾーンといったフラグを指定できます。
whenUnsatisfiable: すべての優先度ティアが失敗した場合の挙動を制御します。ScaleUpAnywayはクラスタのデフォルト構成でノードを作成し、DoNotScaleUpは一致するノードを作成できるまでPodをPendingのままにします。GKE 1.33以降のデフォルトはDoNotScaleUpです(それ以前はScaleUpAnyway)。バージョンの異なるクラスタで同じマニフェストを共有する際の思わぬ挙動を避けるため、明示的に設定しておきましょう。autoscalingPolicy:consolidationDelayMinutes、CPUとメモリのconsolidationThreshold、GPU専用のgpuConsolidationThresholdで、スケールダウンの感度を設定します。activeMigration: アクティブマイグレーションには2つのスイッチがあります。optimizeRulePriority: trueは、容量が空き次第、Podを優先度の高いノードへ能動的に戻します。ensureAllDaemonSetPodsRunning: trueは、必要なDaemonSet Podをすべて実行するには小さすぎるノードを、より大きいノードに置き換えます。
nodePoolAutoCreation.enabled: true: 優先度を満たすために、GKEがノードプールを作成・削除できるようにします。GKE1.33.3-gke.1136000以降では、このためにクラスタレベルのノード自動プロビジョニングを有効にしておく必要はなくなりました。
既存のプールもそのまま使えます。手動作成したプールに cloud.google.com/compute-class ラベルと対応する NoSchedule taintを追加すればそのプールはクラスに組み込まれるため、段階的に導入できます。
また、ネームスペースにラベルを付けてComputeClassをデフォルトで適用したり、default という名前のクラスをデプロイしてクラスタでこの機能を有効にすることで、クラスタ全体に適用したりもできます。さらにGKEには組み込みComputeClassesが用意されており、その1つである autopilot を使えば、Standardクラスタでも特定のPodをAutopilotのコンテナ最適化コンピューティングプラットフォームで実行できます。
まず試したい2つのパターン
パターン1: 静的Spotプールを耐障害性のあるフォールバックチェーンに置き換える
以下は、N4 Spotを最優先とし、C4 Spotにフォールバックし、安全弁としてN4オンデマンドを使う汎用コンピュートクラスです。低使用率ノードを5分後に統合し、Spot容量が回復するとPodをチェーンの上位へ戻します:
apiVersion: cloud.google.com/v1kind: ComputeClassmetadata: name: general-cost-optimizedspec: nodePoolAutoCreation: enabled: true priorities: - machineFamily: n4 spot: true minCores: 4 - machineFamily: c4 spot: true minCores: 4 - machineFamily: n4 spot: false activeMigration: optimizeRulePriority: true autoscalingPolicy: consolidationDelayMinutes: 5 consolidationThreshold: 70 whenUnsatisfiable: DoNotScaleUpoptimizeRulePriority: true を設定すると、容量が回復した時点でGKEはPodを優先するSpotルールへ戻し、その後フォールバックノードを削除します。
ワークロード側は、ノードセレクタ1つでこのクラスを利用します:
apiVersion: apps/v1kind: Deploymentmetadata: name: checkout-apispec: replicas: 3 selector: matchLabels: app: checkout-api template: metadata: labels: app: checkout-api spec: nodeSelector: cloud.google.com/compute-class: general-cost-optimized containers: - name: api image: registry.k8s.io/pause resources: requests: cpu: "1" memory: "2Gi"ここには cloud.google.com/gke-spot セレクタも、tolerationも、マシンファミリーのアフィニティもありません。これは意図的なものです。GKEは、ComputeClassを選択しつつ、対応するComputeClassフィールドを持つシステムラベル(cloud.google.com/gke-spot、cloud.google.com/machine-family、node.kubernetes.io/instance-type など)も選択するPodを拒否します。こうした指定はクラス側で行うべきものだからです。既存ワークロードを移行する場合は、まずマニフェストとHelmチャートからこれらのラベルを検索してください。
パターン2: 既存のカスタムプールの上にクラスを重ねる
特殊用途のプール、事前ウォームアップ済みのプール、予約で確保されたプールを持つStandardクラスタを運用している場合、それらを削除する必要はありません。既存プールを優先的に使い、それらがスケールできない場合にのみ新しいプールを作成するようクラスを設定します:
apiVersion: cloud.google.com/v1kind: ComputeClassmetadata: name: hybrid-fallback-classspec: nodePoolAutoCreation: enabled: true priorities: - nodepools: [core-workload-pool] - machineFamily: n4 - machineFamily: c4クラスが認識できるよう、既存プールにラベルとtaintを付与します:
gcloud container node-pools update core-workload-pool \ --cluster=example-cluster \ --node-labels="cloud.google.com/compute-class=hybrid-fallback-class"
gcloud container node-pools update core-workload-pool \ --cluster=example-cluster \ --node-taints="cloud.google.com/compute-class=hybrid-fallback-class:NoSchedule"なお、--node-labels と --node-taints はプール上のすべてのラベルとtaintを置き換えるため、これらのコマンドを実行する際は既存のものも含めてください。
ベストプラクティスガイドも同じ順序を推奨しています。手動作成したプールを最優先にし、自動作成プールをフォールバックにする、という構成です。
Cloud bill shouldn't be a mystery
One platform for AI and Cloud optimization.
注目すべき最近の追加機能
この機能は直近数回のGKEマイナーバージョンで急速に進化しています。1年前にComputeClassesを検討して見送った方のために、特に取り上げたい変更点を挙げます。
重み付き優先度スコア (1.35.2-gke.1842000+)
リストの順序だけに頼るのではなく、ルールに1から1000までの明示的な priorityScore を定義できます。オールオアナッシングの仕組みで、クラス内のすべてのルールにスコアを付けるか、まったく付けないかのどちらかです。最大3つのルールが同じスコアを共有でき、GKEは同点のルールをまとめて評価し、Cluster Autoscalerがその中から選択します。
apiVersion: cloud.google.com/v1kind: ComputeClassmetadata: name: priority-rule-score-classspec: nodePoolAutoCreation: enabled: true priorities: - machineFamily: e2 spot: true priorityScore: 30 - machineFamily: n2 spot: true priorityScore: 20 - machineFamily: t2d spot: true priorityScore: 20 - machineFamily: n1 spot: true priorityScore: 10 whenUnsatisfiable: ScaleUpAnywayこの例では、N2とT2DのSpotは同等に優れた第2候補として扱われます。グループ化されたルールは自動スケーリングのレイテンシを増やす可能性があります。GKEが実行すべきシミュレーションが増えるため、範囲の狭い machineType ルールよりも範囲の広い machineFamily ルールのほうが影響は大きくなります。
ストレージの自動選択 (1.35.3-gke.1290000+)
マシン世代の混在には、以前はストレージのリスクが伴いました。各シリーズがサポートするディスクタイプが異なるためです(例えばN4はHyperdiskをサポートし、N2は標準PDに依存します)。現在ではディスクタイプを自動選択する StorageClass を使用でき、Podがどのマシンタイプに配置されても動作するディスクタイプをGKEが作成します。これにより、動的プロビジョニングを使うワークロードにとって、複数世代にまたがるフォールバックチェーンがはるかに安全になります。既存のディスクについては、クラス内のすべてのマシンシリーズがサポートするディスクタイプが引き続き必要です。
カスタムマシンシェイプ (1.33.2-gke.1111000+)
CPUとメモリの比率が定義済みシェイプに合わないワークロード向けに、n4-custom-8-20480 のようなカスタムシェイプを machineType に直接定義できます。
machineFamilyルールでのブートディスク設定 (1.34.1-gke.1431000+)
特定の machineType ルールだけでなく、柔軟な machineFamily ルールにも storage.bootDiskType と storage.bootDiskSize を定義できます:
priorities:- machineFamily: n4 spot: true minCores: 16 minMemoryGb: 64 storage: bootDiskType: hyperdisk-balanced bootDiskSize: 100クラス内でのラベルとtaint (1.33.2〜1.34.1)
優先度ルールごとに nodeLabels と taints を宣言するか(ラベルは1.33.2-gke.1111000から、taintは1.33.4-gke.1350000から)、nodePoolConfig の下でグローバルに宣言できます(1.34.1-gke.3084002から)。ルールレベルとグローバルの値を重複させることはできません。これにより、ラベリングと分離の設定を、ハードウェアの選択と同じオブジェクトで管理できます。
システムワークロード向けのデフォルトクラス (1.33.1-gke.1788000+)
cloud.google.com/default-compute-class-non-daemonset ラベルを使うと、DaemonSet以外のPodにのみ適用されるデフォルトクラスをネームスペースに設定できます。GKEはこれを利用して、kube-systemやgmp-systemなどのネームスペースのシステムPodをユーザーのワークロードとは分離して実行します。このときDaemonSet Podにはクラスセレクタは付与されません。
カスタムデフォルトとAutopilotコンピューティングの併用 (1.34.1-gke.1829001+)
Autopilotクラスタでカスタムクラスをクラスタのデフォルトに設定すると、PodはデフォルトではAutopilotのコンテナ最適化プラットフォーム上で実行されなくなります。現在では、特定のPodに cloud.google.com/compute-class: autopilot ノードセレクタを追加することで、そのPodだけをAutopilotコンピューティングプラットフォームで実行できます。
その他の小さな追加機能
priorityDefaults(1.32.1-gke.1729000)を使えば、共通の値をルールごとに繰り返す代わりに一度だけ設定できます。nodeSystemConfig はkubeletとsysctlのチューニングをクラス内に取り込みます。コンパクトプレースメントとワークロードポリシーは、1.33.2-gke.1335000 以降のAutopilotで利用できます。
本番運用での注意点とエッジケース
ComputeClassesには制約があります。それは本番環境ではなく、設計レビューの段階で見つけておくべきものです。
kube-schedulerは優先度ルールを認識しない: ComputeClassesが影響するのは自動スケーリングであり、kube-schedulerはこれを考慮しません。フォールバックノードにすでに空きがある場合、新しいPodは優先ノードよりも先にそこへ配置されることがあります。
activeMigration.optimizeRulePriorityを有効にすればフォールバックノードは徐々に置き換えられ、consolidationThresholdを厳しめにすれば低使用率のフォールバックノードはより早くドレインされます。変更は将来の動作にのみ反映される: ComputeClassを編集しても、稼働中のノードは変わりません。メンテナンスウィンドウ中に既存ノードをcordonおよびdrainして、新しいルールの下で置き換えられるようにしてください。
ステートフルワークロードにはアクティブマイグレーションを使わない: アクティブマイグレーションはPodを退避させますが、データは移動しません。ベストプラクティスガイドは、ステートフルワークロードが使用するクラスでは無効にするよう述べています。こうしたワークロードは専用のクラスに入れ、ディスクタイプの自動選択を使うか、使用するディスクタイプをすべてのマシンシリーズがサポートするようクラスを限定してください。
ネームスペースのデフォルトは既存Podを移行しない: GKEがクラスセレクタを注入するのは、ネームスペースにラベルを付けた後に作成されたPodのみで、すでに稼働中のPodはそのまま残ります。デフォルトを設定した後はネームスペース内のワークロードを再起動し、再作成されたPodにセレクタが付与され、アクティブマイグレーションの対象になるようにしてください。クラスタレベルのデフォルトであれば、既存Podを直接移行できます。
Podのチャーンが激しい場合は注意: Podの作成・削除レートが非常に高いクラスタでは、上位ルールのバックオフが切れる前にCluster Autoscalerが下位ルールを評価できず、Podが
Pendingのままになることがあります。このエッジケースに遭遇した場合は、統合の頻度を下げるか、アクティブマイグレーションを無効にしてください。予約のフォールバック動作:
AnyBestEffortの場合、一致する予約に空きがないと、GKEは次のルールに進む前に同じルールでオンデマンドノードを試みます。予約容量が満杯のときにすぐ次のルールへ移りたい場合は、affinity: Specific(名前付き予約の場合)またはaffinity: AnyThenFailを使用してください。
そのほかの細かな制約
1つのワークロードが選択できるComputeClassは1つだけで、手動作成した各ノードプールが所属できるクラスも1つだけです。Autopilotでは bootDiskType は pd-balanced のみをサポートします。クラス名を gke や autopilot で始めることはできません。前述の機能の多くは比較的新しいパッチバージョンを必要とするため、設計に組み込む前にリリースチャンネルを確認してください。
まとめ
クラスタがまだマシンタイプに固定されたノードプールで動いているなら、まずはステートレスなネームスペースを1つ選んで始めましょう。Spot優先のフォールバックチェーンを設定し、Podがフォールバックルールに配置される頻度と、アクティブマイグレーションがPodを戻しているかどうかを観察してください。
留意点として、ComputeClassが決めるのは作成するノードの種類であり、ノードのサイズはPodのリソースリクエストに依存します。machineFamily ルールの場合、Cluster Autoscalerは保留中Podのリクエスト合計に基づいてマシンサイズを選びます。リクエストが過大だと、マシンは大きくなり、ビンパッキングは悪化し、フォールバックのフットプリントも膨らみます。
ここでライトサイジングが効果を発揮します。PerfectScaleはワークロードのリクエストを継続的にライトサイジングするため、ComputeClassesが作成するノードはPodの実際の使用量に合ったものになります。Node Recommendations機能を使えば、優先度ルールに組み込むべき最もコスト効率の高いマシンファミリーを選べます。クラスタの支出を監査していて、こうしたフォールバック構成が実際にどう機能するか知りたい方は、ぜひデモを予約してください。