サービス概要

AWS Instance Schedulerとは、EC2、EC2 Auto Scalingグループ、RDSインスタンスなど、さまざまなAWSサービスの開始と停止を自動化するAWSソリューションです。
必要に応じてリソースを停止および開始できるため、運用コストの削減に役立ちます。リソースタグとLambdaを利用して、定義したスケジュールに基づいてインスタンスを自動的に停止および起動し、複数のAWSリージョンにデプロイできます。

利点

  • クロスアカウントインスタンスのスケジューリング
  • マルチアカウント制御が可能
  • Systems Managerのメンテナンスウィンドウを使用してスケジュールまたは期間を設定
  • CloudFormationテンプレートが提供されているため、簡単にデプロイ可能
  • 日を跨ぐスケジュール、曜日指定、毎月第一月曜日といった柔軟なスケジュール設定が分単位で可能
  • CloudFormationのパラメータや DynamoDB に保存されているパラメータ変更で設定変更が可能
  • リソースタグにより対象を指定するため、複数のEC2、RDSに簡単にスケジュール可能

目的・やりたいこと

検証環境において、EC2ランニングコストは無視できない費用であり、作成したEC2が常時稼働してしまっているのもコスト増の要因です。
以前に、使っていないEC2を自動的に落とす方法も考えたこともありますが、この「使っていない」の定義が非常に難しく(CPU使用率?メモリ使用率?ログインしているかどうか?)、断念した経緯がありました。理想的には完全に使っていない状態のEC2を落としたいのですが、今回は検証環境などの常時稼働不要なサーバを夜間・土日停止することにしました。

時間
9:00-21:00
21:00-9:00

対象となる技術

  1. 設定可能なスケジューリング間隔で EventBridge ルールをデプロイします。このスケジューリング間隔は、ソリューションの実行頻度を定義し、インスタンスのスケジュールを設定するためのアクションを実行します。
  2. 各スケジューリング間隔は、Lambda オーケストレーション関数を呼び出します。これにより、スケジュール設定が必要な AWS アカウント、リージョン、サービスのリストが決定されます。
  3. スケジューリングと期間のコレクションは、スケジューリング動作を制御するために、DynamoDB 設定テーブルに保存されます。

参考URL

注意事項

  • 下記の概要図のように複数のサービスを動かしているため、仮に小規模展開(2つのアカウントと2つのリージョン)する場合のコストは、月額約13.15ドルかかる。したがって、EC2の起動をやめた場合の月額削減コストが13.15ドル未満の場合は、返って導入ランニング費用の方が高くなってしまうので注意
    コスト – AWS のインスタンス スケジューラ
  • 日本の祝日には対応していないので、祝日が平日の場合は平日通りの運用となってしまう

概要図

https://d1.awsstatic.com/Developer%20Marketing/jp/magazine/2021/img_instance-scheduler_01.ae9c9dd7e9b19b35105f748ee442525d5f051967.png より)

EventBridge – ユーザーが定義した間隔で Lambda 関数を呼び出す
KMS – SNSトピックとDynamoDBテーブルのサーバーサイド暗号化を行うためのカスタマーマスタキー(CMK)を作成
SNS – Lambda関数が次の呼び出し前にすべてのインスタンスを処理できない場合、エラーをCloudWatch Logsに記録し、SNSトピックに通知

作業の流れ

事前作業

1.https://aws.amazon.com/jp/solutions/ にアクセス
2.一番下にある「すべてのソリューションを参照」
3.コンテンツタイプで「AWSソリューション」を選択
4.自力で探してもすぐ見つかるが、「Scheduler」で検索すると一発

5.クリックするとCloudFormation テンプレートを実行するためのAWS Instance Schedulerのランディングページ にアクセスします。
6.「AWS コンソールで起動する」を選択すると、CloudFormation が起動します。

手順

CloudFormation スタックの作成

基本的にはこちらの動画 AWS ソリューションを動かしてみよう – Instance Scheduler on AWS 編 の通りにやっていけばOK
1.CloudFormaitionはバージニア北部リージョンで起動してしまうため、東京リージョンに変更しておきましょう。
2.デフォルトのまま次へ
3.スタック名は適当に「nozaki-InstanceScheduler」
残りはこのように設定

4.スタックオプションの設定はデフォルトのまま次へ
5.「AWS CloudFormationによってIAMリソースがカスタム名で作成される場合があることを承認します。」にチェックを入れて[送信]
6.スタックがCREATE_COMPLETEになっていることを確認

スケジュール設定

1.DynamoDBのテーブルを見ると、「nozaki-InstanceScheduler-」で始まっている3つのテーブルが出来上がっています。

2.「項目を探索」を押し、「nozaki-InstanceScheduler-ConfigTable-7K95KICV2QKJ」の中身を見ると、typeがconfig、schedule、periodに分かれています。
そのうち「office-hours」を編集し、

endtimeを「20:00」に変更

3.次にscheduleの「seattle-office-hours」を編集し、属性を以下のように設定

4.タグ付け
以上で設定は完了なので、最後にインスタンスをこの営業時間スケジュールの対象とするためのタグ付けを行います。逆に営業時間スケジュールの対象にしたくない場合は、タグ付けしないことで回避できます。

https://youtu.be/oLeIx4clzlw?t=717 より)

試しに、nozaki-bastionインスタンスに「Schedule=jp-office-hours」のタグを付けてみます。(「s」cheduleではなく、大文字のSなので注意。自分はそこで1回ハマりました)

動作確認

6/24 23時に停止しておきました。

6/27 9:40、無事起動していることを確認し、InstanceScheduler-LastActionタグもこのように付けられています。(UTCで0時なのでJSTだと9時)

ちなみに6/30(日)のお昼頃に見てみると、無事停止していました。

6/28(金)21時に停止になってまだそのままってことですね。

CloudWatchでメトリクス > すべてのメトリクス > nozaki-InstanceScheduler:InstanceScheduler > Schedule,SchedulingInterval,Service で見ると、ご覧のようにちゃんと週末は停止されていることがわかりますね。

タグエディターによるタグ付け

といってもこのように既存のインスタンス全てに一つ一つにタグを追加して行くと大変なので、複数のリソースにタグを追加する方法としてタグエディターを使います。

1.以下の条件で東京リージョンのEC2インスタンスを検索

2.すると、ずらっと出てきました。

3.これらを全選択して[選択したリソースのタグを管理する]

4.Scheduleというタグが見つかるので、jp-office-hoursと入れて適用します。

5.EC2に戻って任意のインスタンスのタグを見てみると、Schedule=jp-office-hours がバッチリ入ってました。これで今後このインスタンスにもスケジューリングが適用されるようになります。

新規のインスタンへのタグ付けはどうするか?

これで既存のインスタンスにScheduleタグを全適用できましたが、では新規のインスタンスにも都度手動でタグ付けしていくのは大変過ぎます。
そこで、以前 [技術検証] AWSリソース作成時におけるタグ自動付与機能の実装 で行ったタグ自動付与の以下のコードに、

    # 作成されたインスタンスへのタグ付け
    ec2 = boto3.client('ec2')
    ec2.create_tags(
        Resources=[instanceId,],
        Tags=[
            {'Key': 'Owner', 'Value': userName},
            {'Key': 'CreationDate', 'Value': creationDate}
        ]
    )

「{‘Key’: ‘Schedule’, ‘Value’: ‘jp-office-hours’}」を追加してみます。
ここで新規にEC2インスタンスを起動してみると、

Scheduleタグが自動付与されています!
これで新規に作成するEC2に対しても、このスケジューリング運用によるコスト削減が可能になりました。

停止だけさせたい場合

でもこれだと、しばらく使わないからとユーザーが自分で停止させたものまで翌9時に自動起動されてしまいます。そういう場合、普段停止だけさせて使いたいときだけユーザー自身に起動して使ってもらうようにしたい。
そこで、DynamoDBテーブルから「begintime:9:00」というフィールドを削除してみました。

これによって7/1 9時に自動起動されていないことを確認
また、昼に手動で起動させてそのままにしておいたインスタンスが、21時過ぎに見たらしっかり停止していることを確認

一時的に使いたいだけの検証EC2の場合は、停止忘れ防止にもなるのでこの停止だけのスケジューリングの方が良さそうです。

所要時間

2時間

ユースケース

開発環境などの常時稼働不要なサーバを夜間・土日停止して少しでもEC2稼働のコストを削減したい場合