※ 本記事は、Rishi Johari, Partha Srinivasanによる”Reduce your Kubernetes costs with preemptible nodes“を翻訳したものです。
2023年6月16日
Oracle Cloud Infrastructure (OCI)のプリエンプティブル・インスタンスを使用すると、定期的なワークロードと短期間のワークロードを低コストで実行できます。トレードオフとして、OCIは、容量が他の場所で必要になったときにこれらのインスタンスを再利用できます。Oracle Container Engine for Kubernetes (OKE)では、Kubernetesクラスタでのプリエンプティブル・インスタンスの使用がサポートされるようになりました。そのため、プリエンプティブル・ワーカー・ノードを使用して、フォルト・トレラントなコンテナ化されたワークロードをクラスタ上で実行できます。
プリエンプティブル・インスタンスとは?
プリエンプティブル仮想マシン(VM)は、シェイプやリージョンに関係なく、オンデマンドVMインスタンスの価格を50%割引するスポット・インスタンスと同等です。日次ビルド、自動テスト、抽出、変換、ロード(ETL)およびバッチ・ジョブ、ビッグ・データ分析など、フォルト・トレラントで中断可能なワークロードは、可用性保証が低いこれらの低コストのインスタンスを利用できます。
プリエンプティブルVMは、OCIで使用可能な予備のコンピュート容量を利用します。通常は、お客様が一時的に使用状況をスケール・ダウンしたり、ラムアップ・フェーズでスケール・ダウンする短期間で利用できます。このスケーラビリティにより、OCIは顧客に短期またはバースト可能なニーズを満たすためにこの容量を提供できます。オンデマンドVMインスタンスとプリエンプティブルVMインスタンスの唯一の違いは、OCIは、容量を戻す必要があるときに、2分間の通知でプリエンプティブルVMインスタンスを中断できることです。
幸いなことに、簡単な変更により、最新のクラウド・ネイティブ・アプリケーションは耐障害性と、中断に対する自己回復性を備えている可能性があります。この便宜的プリエンプティブル・コンピュート容量により、他の方法では不可能な高度に最適化されたワークロードを実行できます。このような利点により、中断は多くのワークロードで許容できるトレードオフになります。
プリエンプティブル・インスタンスは、すべてのOCI VMシェイプ(専用VMを除く)で提供され、すべてのリージョンで使用できます。詳細は、プリエンプティブル・インスタンスに関するドキュメントを参照してください。
OKEおよびプリエンプティブル・ノード
OKEにより、エンタープライズ・グレードのKubernetesの運用が大規模に簡素化されます。Kubernetesインフラストラクチャの複雑さを管理するために必要な時間、コストおよび労力を削減します。これにより、Kubernetesクラスタをデプロイし、自動スケーリング、アップグレードおよびセキュリティ・パッチ適用により、コントロール・プレーンとワーカー・ノードの両方に対して信頼性の高い操作を実現できます。Kubernetesは一時的なインフラストラクチャを処理するように設計されており、Kubernetes SchedulingはKubernetesコントロール・プレーンのコア・コンポーネントの1つであるため、耐障害性のあるワークロードの実行にぴったりです。使用可能なワーカー・ノードにワークロードが割り当てられます。ノードが削除されると、使用可能な別のワーカー・ノードにポッドが再スケジュールされます。
OKEは、OCIノード終了ハンドラをクラスタ内のプリエンプティブル・インスタンスごとに自動的にデプロイするため、自動化を構築して自分でデプロイする必要はありません。終了ハンドラは、プリエンプティブル・インスタンスごとにデーモンセットとして実行され、インスタンスMetadataサービス(IMDS)を2秒ごとにポーリングしてプリエンプティブル・ノード上のプリエンプション・イベントを検出します。プリエンプション・イベントが検出された場合、ノードはプリエンプション・イベントが作成された時点から2分後に終了します。
その後、OCIノード終了ハンドラは、OKEコードンおよびドレイン機能を使用してKubernetes APIサーバーと通信し、プリエンプティブル・ノードをコード化して、kube-schedulerがそのノードに新しいポッドを配置できないようにします。次に、プリエンプティブル・ノードをドレインしてポッドを安全に削除し、ポッドのコンテナが適切に終了し、必要なクリーンアップを実行します。

プリエンプティブル・ノードを使用するようにポッドをスケジュールするにはどうすればよいですか?
プリエンプティブル・ノードは、Kubernetesラベルと、ワークロードのポッド配置を制御するためのタントの両方を使用して自動的に作成されます。Kubernetesラベルを使用すると、ノード・アフィニティを使用でき、ノード・ラベルに基づいてポッドをスケジュールできるノードを制約できます。そのため、ノード・アフィニティはノード・セットにそれらを引き付けるポッドの特性ですが、タインは反対です。ノードがポッドのセットをリペルできます。タインは、ポッドが特定のノード・タイプで実行されるようにスケジュールされていないことを確認します。ノード・タイプでスケジュールできるのは、タインに一致する許容範囲を持つポッドのみです。OKEクラスタで実行されるクリティカル・ポッド(CoreDNSなど)には、プリエンプティブル・ノード・タインの照合許容範囲が自動的に設定され、ノード上でスケジュールできるようになります。
次のコマンドは、プリエンプティブル・ノードにKubernetesラベルを追加します:
oci.oraclecloud.com/oke-is-preemptible=true
次のコマンドは、Kubernetes taintをプリエンプティブル・ノードに追加します:
oci.oraclecloud.com/oke-is-preemptible
オンデマンド・ノードをバックアップとしてプリエンプティブル・ノードで実行
チュートリアルでは、プリエンプティブル・ノードに対するプリファレンスを持つポッドをデプロイします。プリエンプティブル・インスタンスが使用できない場合は、通常のノードまたはオンデマンド・ノードをバックアップとして使用します。このチュートリアルには、管理対象ノードを含む2つのノード・プールがあります。1つのノード・プールにオンデマンド容量の管理対象ノードがあり、もう1つのノード・プールにはプリエンプティブル容量の管理対象ノードがあります。
このチュートリアルでは、OKEクラスタを作成する必要があります。OKEクラスタの作成を開始するには、クイック作成ワークフローの「コンソールを使用したデフォルト設定でのクラスタの作成」を参照してください。クラスタの作成時に、すべてのデフォルトを保持しますが、ノード数は3から1に減らします。
-
VM標準1.1の1のノード・プールを作成します。「プリエンプティブル容量」を選択します。前提条件ステップから作成したOKEクラスタを使用して、別のノード・プールを作成します。

-
プリエンプティブル容量を持つ別のノード・プールを作成します。デフォルト設定は維持しますが、次のフィールドを変更します。:
-
可用性ドメインを選択します。
-
クイック作成ワークフローから作成したワーカー・ノード・サブネットを選択します。
-
プリエンプティブル容量を選択します。「再利用されると、アタッチされたボリュームを完全に削除します。」を選択したままにできます。
-
シェイプVM.Standard2.1を選択します。
-
ノードの数を3から1に減らします。


-
- 「追加」をクリックして、プリエンプティブル・インスタンスのノード・プールを作成します。完了すると、クラスタ内にそれぞれ1つのノードを持つ2つのノード・プールが表示されます。

-
OCI Cloud Shellを使用してクラスタにアクセスします。「クラスタの詳細」で「クラスタへのアクセス」をクリックし、「クラウド・シェルの起動」を選択します。
-
提供されているOCI CLIコマンドをクラウド・シェルで実行し、kubeconfigを作成してクラスタにアクセスします。

-
次のコマンドを使用して、Kubernetesクラスタ内のプリエンプティブル・インスタンスに対する優先スケジューリングを持つポッドを作成します:
vi preemptibleworkload.yaml次に、マニフェスト・ファイルに次の情報を入力します。このマニフェストは、重みが100のプリエンプティブル・インスタンスでポッドをスケジュールするための強力なプリファレンスを作成します。詳細は、「ノードへのポッドの割当て」を参照してください。
apiVersion: v1 kind: Pod metadata: name: preemptible-node-affinity spec: affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 preference: matchExpressions: - key: oci.oraclecloud.com/oke-is-preemptible operator: In values: - "true" containers: - name: with-node-affinity image: registry.k8s.io/pause:2.0 tolerations: - key: oci.oraclecloud.com/oke-is-preemptible operator: Exists effect: "NoSchedule -
次のコマンドを使用して、マニフェスト・ファイルをデプロイします。:
kubectl create -f preemptibleworkload.yaml -
プリエンプティブル・インスタンスのプライベートIPアドレスにOCIコンピュート・インスタンス・コンソールの確認を通知すると、プリエンプティブル・インスタンスにスケジュールされたポッドが表示されるようになりました。次のコマンドを実行して確認できます:
kubectl describe pod preemptible-node-affinity | grep default-scheduler出力内で、プリエンプティブル・インスタンスで実行されているポッドを確認できます。

ノード・アフィニティを使用する際は、使用可能な場合にのみ、ポッドをプリエンプティブル・インスタンスで実行するように設定できます。ポッドは、常にオンデマンド・ノードをバックアップとして実行できます。
単一のKubernetesクラスタで多様なワークロードを実行
顧客のユース・ケースの中には、単一のOKEクラスタで実行される様々なワークロードがあるものがあります。顧客は、複数のクラスタを作成するのではなく、このオプションを選択することで、複数のKubernetesクラスタを管理する業務上の負担を軽減できます。この場合、同じクラスタでステートフル・ワークロードを使用してフォルト・トレラントなワークロードを実行することを選択できます。
このシナリオでは、フォルト・トレラントなワークロードをプリエンプティブル・インスタンスでのみ実行し、ステートフル・ワークロードではノード可用性を保証する必要があるため、オンデマンド・インスタンスでのみ実行できます。そのため、フォルト・トレラントなワークロードのポッド仕様には、プリエンプティブル・インスタンスでのみ実行されるように、許容範囲とKubernetesラベルの両方が必要です。
ポッド仕様は、次の例のようになります。:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
nodeSelector:
oci.oraclecloud.com/oke-is-preemptible: "true"
tolerations:
- key: oci.oraclecloud.com/oke-is-preemptible
operator: Exists
effect: "NoSchedule"
同じクラスタでオンデマンド容量を実行しているノードにスケジュールする必要があるポッドを実行する場合、プリエンプティブル・ティントの許容範囲なしでポッド仕様を設定できます。次のコード・ブロックに示すように、ポッドをフレキシブル・インスタンスなどの特定のオンデマンド容量インスタンス・タイプに配置する場合にのみ、nodeSelectorが必要です:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
nodeSelector:
node.kubernetes.io/instance-type: "VM.Standard.E3.Flex"
まとめ
プリエンプティブル・インスタンスは、クラウド・インフラストラクチャのフットプリントが拡大するにつれて、コストを削減するための予測可能な節約を提供します。この容量タイプを使用することのトレードオフは、OCIはいつでもインスタンスを再利用できることです。つまり、フォルト・トレラントなワークロードのみが、プリエンプティブル・インスタンスでの実行に適しています。Kubernetesは、一時的なインフラストラクチャを処理するように設計されており、Container Engine for Kubernetesを使用してフォルト・トレラントなワークロードを実行し、コストを節約できるため、これらのインスタンスの自然な適合に役立ちます。
このブログ投稿およびOracle Cloud Infrastructureの概念の詳細は、次のリソースを参照してください:
