アプリケーションがウェブリクエストなどの短期間のサービスを対象としており、中断を許容できる場合、Knative Service をスポットインスタンスで実行するように構成できます。これらのインスタンスは使用後に直ちに解放され、オンデマンドインスタンスと比較して大幅にコスト効率が向上します。Knative とスポットインスタンスを組み合わせることで、クラウドリソースのコストを最適化し、サービスの弾力性と応答性を維持したまま、高度にコスト効率の高いサーバーレスアーキテクチャを構築できます。
前提条件
基本概念
仕組み
Knative では、サーバーレスワークロードは主に Knative Service を通じて管理され、着信リクエストに基づいて Pod が自動的にスケーリングされます。スポットインスタンスを利用するには、特定の Pod アノテーションを設定するだけで済みます。仮想ノードは、Pod アノテーションに基づいて対応する Elastic Container Instance (ECI) のリソース仕様を自動的にプロビジョニングします。また、仮想ノードはスポットインスタンスの自動的な置き換えも提供するため、利用がさらに自動化されます。

Knative とスポットインスタンスを組み合わせるメリットは以下のとおりです:
-
サーバーレスシナリオに最適:短期間のウェブリクエストなど、必要に応じてリソースを動的に使用し、処理完了後に即座に解放するタスクに適しており、長期的なリソース割り当てを回避できます。
-
グレースフルシャットダウンとの自然な連携:このプロセスではアプリケーションがグレースフルシャットダウンをサポートする必要がありますが、Knative は各 Pod に
queue-proxyサイドカーコンテナを挿入することでこれを支援します。Pod が終了される際、queue-proxyコンテナはまずすべてのアクティブなリクエストの完了を待ってから、アプリケーションコンテナをシャットダウンします。 -
コスト効率が高い:コスト意識の高い Knative ユーザーにとって、スポットインスタンスの利用は大幅なコスト削減を実現します。
構成と例
スポットインスタンスの構成
以下のアノテーションは、ECI Pod を作成する際にのみ有効です。既存の ECI Pod に対してこれらのアノテーションを追加または変更しても、効果はありません。
Knative Service の Pod テンプレートに、以下のアノテーションを追加してスポットインスタンスを構成します。
|
アノテーション |
例の値 |
必須 |
説明 |
|
k8s.aliyun.com/eci-spot-strategy |
SpotAsPriceGo |
はい |
スポットインスタンスの入札戦略です。有効な値は以下のとおりです:
|
|
k8s.aliyun.com/eci-spot-price-limit |
"0.5" |
いいえ |
スポットインスタンスの時間単位の最大価格です。小数点以下は最大 3 桁まで指定可能です。 このアノテーションは、 |
|
k8s.aliyun.com/eci-spot-duration |
"1" |
いいえ |
スポットインスタンスの保護期間(単位:時間)です。デフォルト値は 1 です。値を 0 に設定すると、保護期間が無効になります。 |
|
k8s.aliyun.com/eci-spot-fallback |
"true" |
いいえ |
スポット在庫が不足した場合に、自動的にオンデマンドインスタンスを作成するかどうかを指定します。これにより、インスタンス作成の成功を保証できます。デフォルト値は |
例 1:SpotWithPriceLimit 戦略の使用
以下の YAML 例では、ecs.c6 インスタンスタイプのスポットインスタンスを作成します。
-
作成時に、指定されたインスタンスタイプおよび価格上限を満たす在庫が存在しない場合、作成は失敗します。
-
作成後、インスタンスは保証された 1 時間の保護期間中実行されます。この期間が終了すると、市場価格が入札価格を上回った場合や、指定インスタンスタイプの在庫が不足した場合に、スポットインスタンスが再割り当てされます。
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: helloworld-go
spec:
template:
metadata:
labels:
alibabacloud.com/eci: "true"
annotations:
k8s.aliyun.com/eci-use-specs : "ecs.c6.large" # ECS インスタンスタイプを指定します。
k8s.aliyun.com/eci-spot-strategy: "SpotWithPriceLimit" # カスタム価格上限を設定する戦略を使用します。
k8s.aliyun.com/eci-spot-price-limit: "0.25" # 最大時間単位価格を設定します。
spec:
containers:
- env:
- name: TARGET
value: "Knative"
image: registry.cn-hangzhou.aliyuncs.com/knative-sample/helloworld-go:73fbdd56
例 2:オンデマンドインスタンスへの自動フォールバックの有効化
以下の YAML 例では、ecs.c6 インスタンスタイプのスポットインスタンスを作成します。
-
作成時に、指定されたインスタンスタイプおよび価格上限を満たす在庫が存在する場合、スポットインスタンスが作成されます。このインスタンスは保証された 1 時間の保護期間中実行されます。この期間が終了すると、市場価格が入札価格を上回った場合や、指定インスタンスタイプの在庫が不足した場合に、スポットインスタンスが再割り当てされます。
-
作成時に、指定されたインスタンスタイプおよび価格上限を満たす在庫が存在しない場合、代わりにオンデマンドインスタンスが作成されます。このインスタンスはシステムによって自動的に再割り当てされることはありません。インスタンス作成後、
kubectl describe podコマンドを実行して Pod の Events を確認できます。SpotDegradedEvent が表示された場合、Pod はオンデマンドインスタンスへダウングレードされています。
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: helloworld-go
spec:
template:
metadata:
labels:
alibabacloud.com/eci: "true"
annotations:
k8s.aliyun.com/eci-use-specs : "ecs.c6.large" # ECS インスタンスタイプを指定します。
k8s.aliyun.com/eci-spot-strategy: "SpotWithPriceLimit" # カスタム価格上限を設定する戦略を使用します。
k8s.aliyun.com/eci-spot-price-limit: "0.05" # 最大時間単位価格を設定します。
k8s.aliyun.com/eci-spot-fallback: "true" # スポット在庫が不足した場合に、自動的にオンデマンドインスタンスへフォールバックします。
spec:
containers:
- env:
- name: TARGET
value: "Knative"
image: registry.cn-hangzhou.aliyuncs.com/knative-sample/helloworld-go:73fbdd56
ステップ 1:スポットインスタンスの構成
計算リソースのコストを最小限に抑えるために、Knative Service に k8s.aliyun.com/eci-spot-strategy アノテーションを追加できます。この構成により、オンデマンドインスタンスと比較して低価格で提供される ECI スポットインスタンスの利用が優先されます。
ただし、市場価格が入札価格を上回った場合や在庫が不足した場合にスポットインスタンスが再割り当てされ、サービス中断が発生する可能性があります。業務継続性を維持するため、k8s.aliyun.com/eci-spot-fallback: "true" アノテーションも併せて追加できます。この設定により、スポットインスタンスがリソース不足により利用不可となった場合、Knative Service は自動的にオンデマンドインスタンスへフォールバックし、サービスの安定性と信頼性を確保します。このアプローチは、コスト削減と高可用性の両立を実現します。
ACK コンソールにログインします。左側のナビゲーションウィンドウで、クラスターリスト をクリックします。
クラスターリスト ページで、クラスター名をクリックします。左側のナビゲーションウィンドウで、 をクリックします。
-
[Knative] ページで、[サービス管理] タブをクリックします。[名前空間] ドロップダウンリストから [デフォルト] を選択し、[テンプレートで作成] をクリックします。[サンプルテンプレート] ドロップダウンリストで、[カスタム] を選択します。次のサンプルコードをエディターに貼り付けて、[作成する] をクリックして、
helloworld-goという名前の Knative サービスを作成します。apiVersion: serving.knative.dev/v1 kind: Service metadata: name: helloworld-go spec: template: metadata: labels: alibabacloud.com/eci: "true" annotations: k8s.aliyun.com/eci-use-specs : "ecs.c6.large" # ECS インスタンスタイプを指定します。 k8s.aliyun.com/eci-spot-strategy: "SpotAsPriceGo" # 市場価格に従う戦略を使用します。 k8s.aliyun.com/eci-spot-duration: "1" # 保護期間を設定します。デフォルトは 1 時間です。インスタンス作成時に異なる期間を指定できます。 k8s.aliyun.com/eci-spot-fallback: "true" # スポット在庫が不足した場合に、自動的にオンデマンドインスタンスへフォールバックします。 spec: containers: - env: - name: TARGET value: "Knative" image: registry-vpc.{REGION-ID}.aliyuncs.com/knative-samples/helloworld-go:160e4dc8 # {REGION-ID} をご利用のクラスターが展開されているリージョン ID(例:cn-hangzhou)に置き換えてください。上記の YAML 例では、ecs.c6 インスタンスタイプのスポットインスタンスを作成します。
-
作成時に、指定インスタンスタイプのスポット在庫が不足している場合、代わりにオンデマンドインスタンスが作成されます。
-
作成後、インスタンスは保証された 1 時間の保護期間中実行されます。この期間中は、市場価格が入札価格を上回ったとしても、インスタンスは再割り当てされません。保護期間終了後、市場価格が入札価格を上回った場合や在庫が不足した場合に、Alibaba Cloud によりスポットインスタンスが自動的に再割り当てされる可能性があります。コントローラーが再割り当てられた Pod を置き換える際、
k8s.aliyun.com/eci-spot-fallback: "true"設定により、スポット在庫が不足していた場合には新しいオンデマンドインスタンスが作成され、サービス可用性が維持されます。
-
(任意)ステップ 2:スポットインスタンスのグレースフルシャットダウンの構成
使用制限
Pod の条件を用いたプリエンプティブルインスタンス中断通知および Eviction API を用いたプリエンプティブルインスタンスの強制終了を有効にするには、ack-virtual-node をバージョン 2.11.0 以降に更新する必要があります。ack-virtual-node の詳細については、「ack-virtual-node」をご参照ください。
プリエンプティブルインスタンス中断通知
Alibaba Cloud は、プリエンプティブルインスタンスの中断の約 3 分前 に、イベント として SpotToBeReleased を送信し、Pod の条件における ContainerInstanceExpired の値を true に変更することで、ユーザーに通知します。
以下の図は、その通知の例です。
期限切れのスポットインスタンスに対するグレースフルハンドリングの構成
ECI スポットインスタンスの再割り当てによる業務障害を最小限に抑えるため、仮想ノードは構成可能なグレースフルシャットダウン機能を提供します。スポット Pod にアノテーション k8s.aliyun.com/eci-spot-release-strategy: api-evict を追加できます。仮想ノードが SpotToBeReleased Event を受信すると、Eviction API を呼び出してスポットインスタンスを強制終了します。API 経由の強制終了は、お客様が設定した PodDisruptionBudgets および terminationGracePeriodSeconds を尊重します。Eviction オブジェクトを API 経由で作成することは、ポリシー制御された Pod の DELETE 操作を実行することと同等です。
API 呼び出し:仮想ノードが SpotToBeReleased イベントを受信すると、Eviction API を呼び出します。
PDB の確認:API サーバーが、強制終了対象の Pod に設定された PDB を確認します。
強制終了の実行:API サーバーが強制終了要求を検証した後、以下の手順で Pod を強制終了します:
Pod は削除タイムスタンプを更新し、API サーバーが終了対象の Pod を認識できるようにします。また、お客様が設定した猶予期間が付与されます。
Pod が実行されている仮想ノードの kubelet が Pod を認識し、グレースフルシャットダウンを開始します。
kubelet が Pod を終了する際、クラスターのコントロールプレーンは、Pod を関連する Endpoints および Endpointslices から切り離します。この時点で、Pod コントローラーはその Pod を有効なものとして認識しなくなります。
猶予期間が終了すると、kubelet が Pod を強制終了します。
kubelet がシステムに Pod の削除を通知します。
API サーバーが Pod を削除します。
-
Knative 環境では、Knative Service によって管理される各 Pod には
queue-proxyサイドカーコンテナが含まれています。Pod が削除される際、queue-proxyはすべての進行中のリクエストの完了を待ってから、アプリケーションコンテナを停止します。このプロセスにより、スケールダウンや更新がスムーズに行われます。
プリエンプティブルインスタンスのリリース
プリエンプティブルインスタンスが作成された後、保護期間中は通常どおり実行されます。保護期間が終了すると、市場価格が入札価格を上回った場合や在庫リソースが不足した場合に、プリエンプティブルインスタンスがリリースされます。プリエンプティブルインスタンスのリリース状況を把握するには、以下の操作を行います:
SpotToBeReleased イベント
プリエンプティブルインスタンスがリリースされる約 3 分前に、SpotToBeReleased イベントが生成されます。
重要Elastic Container Instance は、このイベントを Kubernetes イベントの一覧に送信します。この 3 分間の猶予期間中に、プリエンプティブルインスタンスのリリースによる業務への影響を防ぐための措置を講じることができます。詳細については、「グレースフル終了」をご参照ください。
kubectl describeコマンドを実行して、プリエンプティブルインスタンスの詳細を表示します。コマンド出力の Events セクションに SpotToBeReleased イベントが表示されます。例:Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning SpotToBeReleased 3m32s kubelet, eci Spot ECI will be released in 3 minuteskubectl get eventsコマンドを実行して、イベント情報を表示します。コマンド出力に SpotToBeReleased イベントが表示されます。例:LAST SEEN TYPE REASON OBJECT MESSAGE 3m39s Warning SpotToBeReleased pod/pi-frmr8 Spot ECI will be released in 3 minutes
リリース後のプリエンプティブルインスタンスのステータス
プリエンプティブルインスタンスがリリースされた後、インスタンス情報は引き続き保持されます。インスタンスステータスは Failed に変更され、失敗原因は BidFailed となります。
kubectl get podコマンドを実行して、インスタンス情報を表示します。コマンド出力に表示されるインスタンスステータスが BidFailed に変更されます。例:NAME READY STATUS RESTARTS AGE pi-frmr8 1/1 BidFailed 0 3h5mkubectl describeコマンドを実行して、プリエンプティブルインスタンスの詳細を表示します。その後、コマンド出力内のインスタンスステータスの詳細を確認します。例:Status: Failed Reason: BidFailed Message: The pod is spot instance, and have been released at 2020-04-08T12:36Z
関連ドキュメント
アプリケーションがコールドスタート遅延に敏感な場合、リザーブドインスタンス機能の利用を検討してください。これにより、コストと起動時間のバランスを取るために、低スペックのバースト可能パフォーマンスインスタンスを維持できます。詳細については、「リザーブドインスタンスの構成」をご参照ください。