インフラ

【節約】ECSを自動起動・自動停止する!【コスト削減】

ecs-auto-start-and-stop

こんばんは!光です。

大手グローバル企業でWebエンジニアをやっています。

Webエンジニアを目指してプログラミングを勉強している初心者の方向けに情報を発信しています。

経歴や実績はこちら

システム開発のお仕事の依頼もお待ちしております。

お問い合わせページTwitterのDMからお気軽にお問い合わせください!

今回はこのような質問をいただきました。

ECSを自動起動・自動停止したい!

前回はEC2の自動起動・自動停止の方法について解説したので今回はECSの解説をします。

前回の記事はこちら!

ECSの場合はタスク数を0にすることによって停止します。

これはCloudWatch EventsだけではできないのでLambdaを使用します。

CloudWatch EventsからLambdaを発火する感じです。

今回はこちらの記事を参考にさせていただきました。

というかコードも設定もほぼこちらと同じなので、こちらの記事を見てわからないところがあればこっち見てもらえれば良いかも。

https://dev.classmethod.jp/articles/fargate-service-task-schedule-stop-start/

大変参考になりました。ありがとうございます!

環境
  • AWS
    • ECS
    • CloudWatch Events
    • Lambda

ECSのタスク数を操作するLambda関数を作る

まずはLambdaを用意しましょう。

Lambda→関数の作成と進んでください。

Lambdaの作成

1から作成で以下のように設定します。

  • 関数名:ecs-stop
  • ランタイム:Python 3.8
  • 実行ロール:基本的な Lambda アクセス権限で新しいロールを作成

入力が終わったら関数の作成を行います。

関数コードに以下のコードをコピペしてDeployします。

import boto3
from botocore.exceptions import ClientError
def lambda_handler(event, context):
    try:
        client = boto3.client('ecs')
        for cluster_name, service_name in [('sample-fargate-cluster', 'sample-fargate-service'),
                                          ('sample-fargate2-cluster', 'sample-fargate2-service')]:
            service_update_result = client.update_service(
                cluster = cluster_name,
                service = service_name,
                desiredCount = 0 # ここの数を増減させる
            )
            print(service_update_result)
    except ClientError as e:
        print("exceptin: %s" % e)

cluster_name, service_nameは自分が作成したECSの名前に変更してください。

デプロイする

ロールにECSを操作する権限を付与する

次に先ほど作成したロールに対してECSを操作する権限を付与します。

アクセス権限のタブから実行ロールの編集を行います。

実行ロールの編集

ページの一番下のほうにIAMコンソールでロールを表示するためのリンクがあるので、そこからIAMコンソールに遷移します。

IAMコンソールへ遷移

ポリシーの編集をクリックします。

ポリシーの編集

JSONタブに以下のコードをコピペします。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecs:DescribeServices",
                "ecs:UpdateService"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        }
    ]
}
ロールの設定

設定を保存したらLambdaからECSを操作できるようになっているはずです。

テストの実行

次にテストを実行してみましょう。

実行するとタスク数が0になり、停止することになるので注意してください。

止めたくない場合はdesiredCountを1以上に設定して変更されるの確認してみてください。

ecs-stopの詳細ページ右上のテストをクリックして新しいテストイベントの作成を行います。

イベント名にtestとだけ入力して作成します。

そしてtestが選択されている状態でテストをクリックすることでテストが実行されます。

成功と表示され、対象のECSのタスク数がdesiredCountで指定した値になっていれば問題ありません。

CloudWatch Eventsでスケジューリング

最後にトリガーの設定していきます。

まずはCloudWatchのルール→ルールの作成と進んでください。

ルールの作成

今回は平日の24時に停止するように設定してみます。

イベントソースはスケジュールのCron 式を選択し、クーロン式には 0 15 ? * MON-FRI * を入力します。

Cron 式はUTCで入力する必要があるので日本時間(JST)の場合は9時間前となります。

ターゲットはLambda関数を選択し、関数にecs-stopを設定します。

ルールの設定

そして設定の詳細へと進み、任意の名前と説明を入力してください。

有効化にチェックを入れると作成した時点で定期実行設定が有効化されます。

私は以下のように設定しました。

  • 名前:StopECS
  • 説明:平日の24時にECSを停止します。
  • 有効化:✔

これで24時に自動停止する設定は完了しました。

自動起動の設定

次に平日8時に自動起動するように設定してみましょう!

手順はほぼ同じでdesiredCountを1以上にしたLambdaを作成して、CloudWatch EventsのCron 式とターゲットの設定値を変えるだけです。

平日8時に設定する場合のCron 式は 0 23 ? * SUN-THU * となります。

自動起動時に利用するロールは自動停止時に作成したロールを使いまわしても問題ありません。

これで平日の8時に起動し、24時に停止する設定が完了しました。

不安な方はCron 式の設定を変えてみて動作確認してみてください!

あとがき

desiredCount、クラスター名、サービス名を引数として渡してあげれば1つの関数でもできそう。

でもLambdaにそんなに詳しくない&Pythonが書けないので2つ作っちゃいました。

使わないときは停止して無駄のないような運用をしたいですね。