Amazon Web Services ブログ
Amazon EKS が、マネージド型ノードグループでの EC2 スポットインスタンスのプロビジョニングと管理をサポート
この記事は、Amazon EKS now supports provisioning and managing EC2 Spot Instances in managed node groups を翻訳したものです。
Amazon Elastic Kubernetes Service (Amazon EKS) を使用すると、アップストリームのKubernetes を利用した、セキュアで可用性の高いKubernetes クラスターを AWS で簡単に実行できます。2019 年にマネージド型ノードグループがサポートされ、EKS はクラスターの基盤となる EC2 インスタンス(ワーカーノード)をプロビジョニングし、管理できるようになりました。これにより、新しいAMI がリリースされたときにノードをローリングアップデートしたり、Kubernetes バージョンを更新したりといった、運用のための作業が非常に簡単になりました。EKS のマネージド型ノードグループについて詳しく知るには、アナウンス時のブログ及びドキュメントをご参照ください。 AWS public containers roadmap にお客様より寄せられたご要望を受けて、EKS はマネージド型ノードグループをさらに使いやすくするために機能を強化してきました。例えば、カスタムAMI の指定、起動テンプレートの利用といった機能拡張を実施しました。同様に、お客様の関心が高かった機能の一つが、マネージド型ノードグループでスポットインスタンスを起動、管理できるようにするというものです。
Amazon EC2 スポットインスタンスを利用すると、EC2 が予備として確保しているキャパシティーを利用して、大幅な割引価格で EC2 インスタンスを実行できます。 EC2 がこの予備キャパシティーを必要とする際には、スポットインスタンスは 2 分前に通知を受けて中断されることがあります。スポットインスタンスを Kubernetes のワーカーノードとして使用するというのは様々な種類のワークロードで非常によく使われるパターンです。ステートレスなAPI エンドポイントやバッチ処理、ML のトレーニング、Apache Spark を使ったビッグデータ ETL、キュー処理アプリケーション、CI/CD パイプラインなどのワークロードでこのパターンが使われます。例えば、API 用のステートレスなサービスは、スポットインスタンスのワーカーノードと非常に相性の良いワークロードです。というのも、スポットインスタンスが中断する際にPod をGraceful に終了し、代わりに新しいPod を別のノードにスケジューリングすることが可能だからです。
本日より、お客様は EKS のマネージド型ノードグループでスポットインスタンスを使用できるようになります。中断耐性のあるアプリケーション用に、スポットインスタンスを使って大幅にコストを削減できます。スポットインスタンスをマネージド型ノードグループで利用することで、セルフマネージド型ノードでの利用に比べて運用の手間が大幅に少なくなります。また、スポットインスタンスのサポートに加えて、複数のインスタンスタイプをマネージド型ノードグループで指定することもできるようになりました。
この記事では、スポットインスタンスを使ったマネージド型ノードグループの概要を紹介し、スポットインスタンスを利用する上でのベストプラクティスを、マネージド型ノードグループが自動的に適用する仕組みを見ていきます。加えて、マネージド型ノードグループを使った EKS クラスターのセットアップ方法をチュートリアルでご紹介します。
スポットインスタンスに関するセルフマネージド型ノードとマネージド型ノードグループの違い
以前は、お客様は EKS クラスターでスポットインスタンスを実行する際、セルフマネージド型のワーカーノードを利用する必要がありました。これは、いくつかの “Undifferentiated Heavy Lifting” (差別化につながらない重労働)を行う必要がある、ということを意味します。例えば、EC2 Auto Scaling グループでのスポットインスタンス構成の構築とメンテナンス、スポットの中断に対応するためのツールのデプロイ、AMI の更新、ノードで稼働する kubelet の更新などです。これからは、パラメーターを一つ追加するだけでマネージド型ノードグループがスポットインスタンスを使うようになり、また、マネージド型ノードグループで使われる Auto Scaling グループに複数のインスタンスタイプを含めることもできるようになります。
マネージド型ノードグループでスポットインスタンスを利用する前に、いくつかのベストプラクティスを念頭に置いておきます。まず、スポットインスタンスは、必ずフォールトトレラントのアプリケーションに使用します。次に、スポットインスタンスで稼働するアプリケーションの可用性を高めるために、マネージド型ノードグループに複数のインスタンスタイプを含めるよう推奨します。最後に、可用性をさらに強化するために、ワークロードが全てのアベイラビリティーゾーン (AZ) で動作できるようにします。例えば、Pod が PersistentVolumeClaim
を介して EBS ボリュームを使用している場合は、代わりに Amazon Elastic File System のようなクロス AZ で利用できるストレージを検討してください。これにより、マルチ AZ でマネージド型ノードグループを実行できるようになります。
どのインスタンスタイプを利用するか決めるときは、同量の vCPU とメモリを持つ全てのインスタンスタイプを調べて、それらを同じノードグループにグループ化することができます。異なるインスタンスタイプでワークロードを動かすと、パフォーマンスにばらつきが出ることもありますが、このような柔軟性が、大幅なコスト削減の恩恵を受けながらも、要求されるキャパシティーをプロビジョニングして維持していくために重要になります。例えば、あるノードグループを、m5.xlarge、m4.xlarge、m5a.xlarge、m5d.xlarge、m5ad.xlarge、m5n.xlarge、および m5dn.xlarge で構成することが考えられます。これらのインスタンスタイプは、ほぼ同じ vCPU とメモリ容量を持っています。 EC2 Instance Selector は、コマンド一発で適切なインスタンスタイプを探すのを助けてくれるオープンソースのツールです(この記事のチュートリアルのセクションを参照してください)。
以下は、マネージド型ノードグループの構成例の一つです。
この構成例のクラスターには、オンデマンドのマネージド型ノードグループが一つ用意されています。これは、クラスター管理、および運用ツール用のノードグループです。このノードグループでは、お客様がデータストアや監視ツール、その他、中断が許容されず利用可能な状態を維持しておく必要があるようなアプリケーションを実行するための場所として使うことができます。
また、この構成例では、スポットインスタンスを利用する複数のマネージド型ノードグループがあり、それぞれのノードグループも似たようなサイズのインスタンスタイプが複数含まれている多様な構成になっています。これにより、複数のスポットのプールが活用できるようになっています。
スポットインスタンスを使用したマネージド型ノードグループの仕組み
この節では、EKS が EC2 Auto Scaling グループをスポットインスタンスのベストプラクティスに沿って構成するその内容と、スポットのワーカーノードのライフサイクルを管理する方法について説明します。以下は、デフォルトで適用される、変更不可の設定です。
- 割り当て戦略は、 capacity-optimized で設定されます。つまり、ノードグループが(Kubernetes Cluster Autoscaler がノードグループのサイズを増やす、手動でサイズを増やす、またはその他何らかの自動化により)スケールアウトするたびに、インスタンスが、利用可能な容量が最も多いプールから起動されるということです。これにより、ノードグループのスポットインスタンスが中断されにくくなり、アプリケーションの回復力を高めることができます。
- スポットの中断に対応するために、クラスターに自動化のツール(AWS Node Termination Handler など)をインストールする必要はありません。マネージド型ノードグループは、次の方法でスポットの中断に対処します。基盤となる EC2 Auto Scaling グループでは、Capacity Rebalancing がオプトインされています。つまり、スポットインスタンスが中断されるリスクが高まって、EC2 インスタンスのリバランスリコメンデーションのシグナルを受け取ると、新しいインスタンスの起動が試行されます。マネージド型ノードグループにインスタンスタイプが多く含まれているほど、EC2 Auto Scaling が代替のスポットインスタンスを起動できる可能性が高くなります。詳細については、ユーザーガイドを参照してください。
- スポットのマネージド型ノードグループが、アベイラビリティーゾーン間でインスタンス数を再調整するときは、オンデマンドのマネージド型ノードグループと同様、スケールインされるインスタンスで Pod が自動的にドレインされます。
- ノードには
eks.amazonaws.com/capacityType=SPOT
というラベルが付くので、ノードセレクターを使ってフォールトトレラントでステートレスなワークロードを簡単にスポットインスタンス上にスケジュールすることができます。もしくは、アフィニティ、アンチアフィニティのルールを指定することでもスケジューリングを調整できます。 - マネージド型ノードグループ(スポット、オンデマンドどちらでも)で使用される EC2 Auto Scaling グループは、Kubernetes Cluster Autoscaler の自動検出機能で利用できるよう、自動的にタグが付けられます。具体的には、
k8s.io/cluster-autoscaler/enabled=true
、k8s.io/cluster-autoscaler/<クラスター名>
というタグが付けられます。
チュートリアル: eksctl を使って EKS マネージド型ノードグループでスポットインスタンスをデプロイしオートスケールを設定する
このチュートリアルでは、新しいEKS クラスターと 2 つのマネージド型ノードグループを作成し、それぞれのノードグループをオンデマンドインスタンス、およびスポットインスタンスで構成します。また、Kubernetes Cluster Autoscaler をデプロイし、デモアプリケーションを実行して、スポットインスタンスをスケールアウトさせます。
このチュートリアルを完了するには、ローカルまたは AWS Cloud9 の環境に eksctl と kubectl がインストールされている必要があります。このチュートリアルは、AdministratorAccess ポリシーがアタッチされている AWS IAM ユーザーまたは IAM ロールで実行します。もしくは、eksctl の実行に必要な最低限のポリシーを確認してアタッチすることもできます。
クラスターとノードグループのデプロイ
まず、最初の方の図で見たように、オンデマンドインスタンスのマネージド型ノードグループを一つ備えるクラスターを起動します。このオンデマンドのノードグループには複数のインスタンスタイプを指定できます。ノードグループが利用する Auto Scaling グループは、あるインスタンスタイプが何らかの理由で起動できなかったとしても、リストにある別のインスタンスタイプを起動することができます。
eksctl create cluster --name=eks-spot-managed-node-groups --instance-types=m5.xlarge,m5a.xlarge,m5d.xlarge --managed --nodes=2 --asg-access --nodegroup-name on-demand-4vcpu-16gb
クラスターとマネージド型ノードグループの起動には約 15 分かかります。上記コマンドが EKS クラスターの準備ができたとメッセージを返したら、クラスターに接続できるかテストします。次のコマンドでノードが Ready ステータスになっているか確認してください。
kubectl get nodes
次に、別のマネージド型ノードグループをデプロイします。このノードグループでは、スポットインスタンスを利用することにします。この例では、スポットインスタンスで実行されるフォールトトレラントなワークロードにとって、4 つの vCPU と 16GB の RAM を備えたノードが適切だと想定します。 適切なインスタンスタイプを探すには、ec2-instance-selector が便利です。次の例では、前述の vCPU 数とメモリ容量、x86_64 CPU アーキテクチャのインスタンスタイプを表示しています。このノードグループには GPU が必要ないので、GPU 数は 0 に設定され、また、バースト可能なインスタンスタイプ(t2、t3)を除外しています。
ec2-instance-selector --vcpus=4 --memory=16 --cpu-architecture=x86_64 --gpus=0 --burst-support=false
上記コマンドの結果は以下のようになります。
m4.xlarge
m5.xlarge
m5a.xlarge
m5ad.xlarge
m5d.xlarge
m5dn.xlarge
m5n.xlarge
この結果を、以下のように eksctl create nodegroup
コマンドに渡して実行します。--spot
というフラグで、ノードグループにスポットインスタンスを実行するよう指定しています。この例では、--node-max 20
を同時に指定しているため、Cluster Autoscaler を使用して検証用のワークロードでこのノードグループをスケールアウトできます。
eksctl create nodegroup --cluster eks-spot-managed-node-groups --instance-types m5.xlarge,m4.xlarge,m5a.xlarge,m5d.xlarge,m5n.xlarge,m5ad.xlarge,m5dn.xlarge --managed --spot --name spot-4vcpu-16gb --asg-access --nodes-max 20
ノードグループの作成には約4分かかります。次のコマンドを実行して、スポットインスタンスで実行されている新しい2つのノードがクラスターに追加されたことを確認できます。
kubectl get nodes --selector=eks.amazonaws.com/capacityType=SPOT
EKS のコンソールでも、この追加されたノードグループを確認できます。コンソールの「コンピューティング」タブを見てみると、新しいインスタンスタイプが追加され、様々なインスタンスタイプで構成されていることが分かります。
Kubernetes Cluster Autoscaler のデプロイ
GitHub の公式リポジトリからマニフェストファイルを適用し、Cluster Autoscaler をインストールします。
kubectl apply -f https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml
次に、この Cluster Autoscaler の Deployment を開いて編集します。
kubectl edit deployment cluster-autoscaler -n kube-system
--node-group-auto-discovery
のある行を見つけ、<YOUR CLUSTERNAME>
という文字列を正しいクラスター名に変更します。この例では、eks-spot-managed-node-groups です。
また、image
行に記載されているバージョンが、クラスターのバージョンに合ったメジャーリリースであることを確認してください。例えば、EKS クラスターが Kubernetes バージョン 1.17 を実行している場合は、イメージのバージョンは v1.17.* である必要があります。ここをクリックして、Cluster Autoscaler のリリースを確認してください。
最後に、ログを確認して、Cluster Autoscaler が正常に起動したことを確認します。
kubectl -n kube-system logs -f deployment.apps/cluster-autoscaler
サンプルの nginx をデプロイする
nginx-spot-demo.yaml
というファイル名でファイルを作成し、以下のスニペットをコピーして保存します。(訳注: 以下のテキストボックスをスクロールし、YAMLスニペットの全量をコピーするようにしてください)
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-spot-demo
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
service: nginx
app: nginx
spec:
containers:
- image: nginx
name: nginx-spot-demo
resources:
limits:
cpu: 1000m
memory: 1024Mi
requests:
cpu: 1000m
memory: 1024Mi
nodeSelector:
eks.amazonaws.com/capacityType: SPOT
このマニフェストをクラスターに適用します。
kubectl apply -f nginx-spot-demo.yaml
デプロイが成功し、2 つの nginx-spot-demo の Pod がスポットインスタンスのワーカーノードにスケジュールされていることを確認します。具体的には、ラベルを指定して kubectl get
を実行し、スポットインスタンスのノードのみを表示します。そして、kubectl describe
を実行して、それらのノードで実行されている Pod を確認します。
kubectl get no -l eks.amazonaws.com/capacityType=SPOT
kubectl describe node <one of the nodes from the output of the previous command>
また、 kube-ops-view を使うと、どの Pod がどのノードにスケジュールされているか、視覚的に確認することもできます。
NGINX Deployment をスケールし、Cluster Autoscaler がスポットインスタンスで構成されたマネージド型ノードグループのサイズを増やすことを確認する
kubectl scale deployment nginx-spot-demo --replicas=20
Cluster Autoscaler のログを見てみると、Pending 状態の Pod があることを検知し、Auto Scaling グループをスケールアウトしていることが分かります。
以下のようなログが表示されるはずです。
scale_up.go:271] Pod default/nginx-spot-demo-7fbfcb596b-dbwfp is unschedulable
scale_up.go:271] Pod default/nginx-spot-demo-7fbfcb596b-7xs6d is unschedulable
scale_up.go:271] Pod default/nginx-spot-demo-7fbfcb596b-t8vww is unschedulable
scale_up.go:539] Final scale-up plan: [[{eks-cebaf87d-d2b3-c88f-4004-e467c43935d6 2->7 (max: 20)}]]
scale_up.go:700] Scale-up: setting group eks-cebaf87d-d2b3-c88f-4004-e467c43935d6 size
2〜3分以内に、Pending 状態だった全ての Pod が、マネージド型ノードグループのスポットインスタンスにスケジュールされます。
最後に、EC2 インスタンスの管理コンソールにアクセスして、ノードグループ名(spot-4vcpu-16gb)でフィルタリングしてみましょう。スポットインスタンスが異なるアベイラビリティーゾーンで起動していることが分かります。Capacity Optimized 割り当て戦略は最も利用可能な容量が多いスポットプールからインスタンスを選択するので、同じノードグループで異なるインスタンスタイプが起動されている場合があります。
クリーンアップ
このチュートリアルで作成したリソースを、以下の手順で削除します。
kubectl delete deployment nginx-spot-demo
eksctl delete nodegroup on-demand-4vcpu-16gb --cluster eks-spot-managed-node-groups
eksctl delete nodegroup spot-4vcpu-16gb --cluster eks-spot-managed-node-groups
eksctl delete cluster eks-spot-managed-node-groups
まとめ
EKS のマネージド型ノードグループでは、AWS CLI、AWS マネージメントコンソール、API / SDK、CloudFormation、Terraform、および eksctl(バージョン 0.33 以降)を利用してスポットインスタンスを起動できるようになりました。今回のリリースにより、Amazon EKS の使い勝手がさらに良くなり、セルフマネージド型ワーカーノードの管理コストを払うことなくスポットインスタンスを活用できるようになり、コスト、スケール、復元力に関して EKS クラスターを最適化できます。 EKS のマネージド型ノードグループを使用するために追加で掛かるコストはありません。プロビジョニングされた AWS リソースに対してのみ料金が発生します。
– プリンシパルソリューションアーキテクト Ran Sheinberg、シニアプロダクトマネージャー Deepthi Chelupati
翻訳は、ソリューションアーキテクトの林が担当しました。