🔥

FargateSpotを使って利用料を70%削減した時のノウハウ

2023/02/28に公開

備考

この記事は Qiita にて投稿した記事を少し記載を加えたものです.

はじめに

今回業務にて利用している AWS のサービスの 1 つ「Fargate」を利用した際の課題とその解決策について記します.

そもそも Fargate とは

公式ドキュメント:
https://aws.amazon.com/jp/fargate/

コンテナ向けサーバーレスコンピューティングの一種であり,Docker のイメージファイルを作るだけで簡単にデプロイできる便利なサービスです.

今回の課題

料金

料金表

vcpu メモリ(GB) 料金(円/月)
0.25 0.5 1,521 円
0.5 1.0 3,042 円
1.0 2.0 6,084 円
2.0 4.0 12,168 円

(2023 年 2 月 28 日現在で月に 732 時間動作させた場合)
(データ転送料+為替レートにより前後します)

現在の業務ではかなりの数 Fargate を同時稼動にて動かしているので通常のFargateを動かすと高コストになってしまいます.このコストそのものが課題になりました.

課題解決策

FargateSpot

AWS Fargate Spot の発表 – Fargate とスポットインスタンスの統合
AWS Fargate キャパシティープロバイダー

簡単に説明すると,価格が 70%割引になる Fargate です.

実際に利用してみる

まず Fargate を利用するクラスターを作り,作成したクラスターを選択します.
右上にクラスターの更新というボタンがあるので押します.
fargatespot_1.png
クラスターの更新を押すとキャパシティープロパイダー戦略という項目があるので追加し,FARGATE_SPOTを選択します.
fargatespot_2.png
そして実行したいタスクをクラスター内にて利用することでFargateSpotを利用することが出来ます.
fargatespot_3.png

弱点

FargateSpot は連続稼働を保証しておらず,ある日突然タスクが終了するリスクを抱えています.

Fargate Spot が空きキャパシティを確保できるかぎり、ユーザーは指定したタスクを起動することができます。

弱点をカバーする方法

タスク終了前に 終了を通知する signal が送られるのでタスク内で正常に終了させる処理、もしくは再起動させる処理を行う必要があります.

スポットの中断により Fargate Spot キャパシティーを使用するタスクが停止すると、
タスクが停止する前に 2 分間の警告が送信されます。
警告は、タスク状態変更イベントとして Amazon EventBridge に送信され、
実行中のタスクに SIGTERM シグナルが送信されます。

実際にタスク終了を検知するソースコードの例を下記に記載します.

ソースコード例

Python
import signal
import sys
import time
import random
import pprint


# 何かしらの処理を行い最終的に出力する変数
# 配列・辞書等...
response_data = []


def signal_receive_process(sig, frame):
    """SIGTERMシグナルを受け取った際に行う処理を書く"""
    print("SIGTERM!!")
    # 正常終了時の処理を行う
    task_finish_process()

    # タスクを終わらせる
    sys.exit(0)


def task_finish_process():
    """タスクが終了する際に行う処理を書く"""
    # 今回は単に表示させるだけ
    pprint.pprint(response_data[0:20])


def main():
    """何かしらの処理(web・machine_running etc...)を書く"""
    # SIGTERMを検知する
    signal.signal(signal.SIGTERM, signal_receive_process)

    for idx in range(100):
        print(idx)
        # 何かしらの処理を行う
        append_data = idx * random.random()
        # データを格納する
        response_data.append(append_data)

        time.sleep(1)

    # 正常終了時の処理を行う
    task_finish_process()


if __name__ == '__main__':
    main()
TypeScript
const response_data: Array<number> = [];
const task_finish_process = () => {
  // 今回は単純に表示させるだけ
  console.log(response_data);
};

const main = () => {
  /* 何かしらの処理をかく */
  process.on("SIGTERM", () => {
    console.log("SIGTERM!!");

    // 正常処理時の動作を行う
    task_finish_process();

    process.exit(0);
  });

  for (let idx = 0; idx < 100; idx++) {
    console.log(idx);
    // 何かしらの処理を行う
    const append_data = idx * Math.random();
    // データを格納する
    response_data.push(append_data);
  }

  // 正常終了時の処理を行う
  task_finish_process();
};

main();

まとめ

突然発生する終了処理をきちんと考える必要はありますが,FargateSpotを使えば通常のFargateを利用するより料金を70%削減することができます.

株式会社マインディア テックブログ

Discussion