EKS の worker ノードにスポットインスタンスを使ってコストを下げる

Posted on

eksctl の v0.1.34 から EKS の worker ノード (nodegroup) にスポットインスタンスを指定できるようになりました。

eksctl の nodegroup は Auto Scaling Group で管理されており、スポットインスタンスの指定にも Auto Scaling Group に統合された EC2 Fleet の機能が使われています。

freee では production 以外の worker ノードにスポットインスタンスを活用しています。 m5.large などの一般的なインスタンスタイプだと、価格変動もそれほどなく、オンデマンドインスタンスに比べて 70% 程度のコスト削減になります。

また、1 世代前のインスタンスタイプを混ぜることで希望するキャパシティを安定的に確保できています。 2 世代前のインスタンスタイプだと性能差が大きく、またコストパフォーマンスも良くないのでお勧めしません。インスタンスタイプに多様性を持たせるなら、同じ世代の別のインスタンスファミリーを混ぜると良いです。たとえば m5.large を使っている場合は m4.large や r5.large を混ぜています。

production でまだ使っていない理由は、スポットインスタンスの中断通知を受けて worker ノードを drain する処理が検証できていないからです。インスタンスメタデータを監視するような DaemonSet を配置すれば実現できると思うので、引き続き検証してみようと思います。

onDemandBaseCapacity と onDemandPercentageAboveBaseCapacity の関係

YAML の定義は eksctl のドキュメントに詳しく載っているので割愛します。ここでは onDemandBaseCapacityonDemandPercentageAboveBaseCapacity の関係について書きます。スポットインスタンスの台数はこの 2 つのパラメータから割り出されますが、ちゃんと理解していなかったのでハマりました。

  • onDemandBaseCapacity: オンデマンドで起動するベース台数。デフォルト値は 0
  • onDemandPercentageAboveBaseCapacity: ベースを超えるオンデマンドの割合。デフォルト値は 100 で、0 から 100 の値を取る(単位はパーセント)

文字だけだとわかりずらいので具体例を挙げます。

nodeGroups:
  - name: nodegroup-1
    minSize: 10
    maxSize: 20
    instancesDistribution:
      maxPrice: 0.04
      instanceTypes:
        - m4.large
        - m5.large
      onDemandBaseCapacity: 4
      onDemandPercentageAboveBaseCapacity: 50
      spotInstancePools: 2

この場合 minSize: 10 なので、オンデマンドでまず 4 台起動し (onDemandBaseCapacity: 4)、残り 6 台のうちオンデマンドとスポットが 3 台ずつ起動します (onDemandPercentageAboveBaseCapacity: 50)。 Cluster Autoscaler で台数が増えたときは、11 台目はオンデマンド、12 台目はスポットといった感じで、オンデマンドの割合が 50% を下回らないようにスケールアウトしていきます。スケールインするときも同じロジックで動くので、まずはスポットインスタンスから terminate されていきます。

スポットインスタンスだけ使いたい場合は、onDemandBaseCapacityonDemandPercentageAboveBaseCapacity を 0 にすれば OK です。

2 つのパラメータを指定すると直感的に把握しづらくなるので、通常は onDemandBaseCapacity を 0 にして onDemandPercentageAboveBaseCapacity でオンデマンドとスポットの割合を指定するのが良いでしょう。

まとめ

コンテナ技術と Kubernetes のおかげで、個々のノードを意識する必要がなく VM ベースのときよりも手軽にスポットインスタンスを活用できます。ユーザーに影響がない環境であれば積極的にスポットインスタンスを活用しましょう。