経緯
EC2インスタンスを、使用しない時間帯のみ止めてコスト削減をしたい。
Lambdaのみでの実装と、Instance Schedulerでの実装を行い、それぞれの複数インスタンス・複数スケジュール設定の場合やコスト、注意などをまとめる。
【参考】
Lambda のみで実装する
〇手動方式〇
1. IAM ポリシーと IAMロール作成
- ポリシーの作成。CloudWatch Logの書き込み、EC2書き込み権限保有(以下JSON)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": [
"ec2:Start*",
"ec2:Stop*"
],
"Resource": "*"
}
]
}
- 上記ポリシーをアタッチしたロールを作成
2. EC2 インスタンスを停止および起動する Lambda 関数の作成
- AWS Lambda コンソールで、「関数の作成」 クリック
- 「一から作成」クリック
- [基本的な情報] に次の事項を追加
- [関数名] に EC2 インスタンスを開始/停止させる関数の名前を入力
[ランタイム] : [python 3.8] を選択
[アクセス権限] : [デフォルトの実行ロールの変更] を展開
[実行ロール] : [既存のロールを使用する] を選択
1で作成したロールを登録
- 「関数の作成」
- 「コード」でlambda_functionに以下貼り付け
上の手順で開始させる関数と停止させる関数をそれぞれ作成し、以下を記述する
インスタンスの開始
import boto3
region = 'ap-northeast-1'
instances = ['InstanceID']
ec2 = boto3.client('ec2', region_name=region)
def lambda_handler(event, context):
ec2.start_instances(InstanceIds=instances)
print('started your instances: ' + str(instances))
インスタンスの停止
import boto3
region = 'ap-northeast-1'
instances = ['InstanceID']
ec2 = boto3.client('ec2', region_name=region)
def lambda_handler(event, context):
ec2.stop_instances(InstanceIds=instances)
print('stopped your instances: ' + str(instances))
3. CloudWatch Events(Eventblidge) のルールを作成
- Amazon CloudWatch (Eventblidge)コンソールを開く
- 左ナビゲーションペインの [イベント] の下にある [ルール] をクリック
- [ルールの作成] を選択
- [イベントソース] の [スケジュール] をクリック
- [Cron expression] に、Lambda にインスタンスを起動/停止させる時刻を表すスケジュール式を入力(UTC)
- [ターゲットの追加] をクリック
- [Lambda関数] でEC2 インスタンスを停止させる関数(Start,Stop)を選択
- [詳細の設定] を選択、名前など設定
- 「ルールの作成」
※StartとStopそれぞれ作成
設定した時間になり、スケジュール通り起動・停止していることを確認
〇テンプレートを使用〇
- AWS CloudFormation テンプレート を YAML ファイルとして保存
- AWS CloudFormationより、スタックを作成して上記のテンプレートを使用
- 名前や対象インスタンスID、スケジュールをパラメータに設定し、「作成」
- 以下のLambda関数とCloudwatchルールが作成
Lambda関数
・TestEC2Scheduler-StartEC2Instances-*
・TestEC2Scheduler-StopEC2Instances-*
CloudWatchルール
・TestEC2Scheduler-StartScheduledRule-*
・TestEC2Scheduler-StopScheduledRule- *
設定した時間になり、スケジュール通り起動・停止していることを確認
複数インスタンス・複数スケジュールでの設定
1 >Lambda、Eventblidgeを手動でスケジュールの数×2(StartとStop)作成
※自動起動停止したいインスタンスの指定は、Lambdaに直接書くか、対象を一覧CSVにしてLambdaで指定する。
2>CloudFormation テンプレートを使用してスケジュールの数だけスタックを作成(LambdaとEventblidgeはStartとStopが自動作成)
※インスタンスの指定は、スタックのパラメータ(Lambdaの環境変数)に登録するか、対象を一覧CSVにしてLambdaで指定する。
コスト
Amazon EventBridge の料金
カスタムイベント :百万件の公開済みカスタムイベントごとに 1.00USD
サードパーティー (SaaS) のイベント :百万件の公開済みイベントごとに 1.00USD
イベントからもう一つのバスへ :百万件の送信済みイベントごとに 1.00USD
AWS Lambda 料金
リクエスト:リクエスト100万件あたり0.20USD
実行時間:GB-秒あたり0.0000166667USD
注意
- Amazon EventBridgeでのスケジュール設定は、UTCで行われるためマイナス9時間で設定する。
Instance Schedulerで実装する
1. スタックの作成
- 「 AWSコンソールで起動する 」>サインイン(入り直す必要あり)、リージョンを東京へ変更
- 名前、Account Id、TimeZoneなどの パラメータ を設定
- 「スタックの作成」
2. スケジュール定義、ピリオド定義
- 「DynamoDB」<「テーブル」にて「InstanceScheduler-ConfigTable-*」クリック
- 「項目を表示」
- ピリオド定義 (type 属性が period) の office-hours のチェックボックスを選択し、「アクション」から「コピー」をクリック
- 下記設定し、「項目の作成」をクリック(例:月曜日の9:00~18:00のみ起動する設定)
フィールド名 | 値 |
---|---|
name | mon-start-9am |
begintime | 9:00 |
endtime | 18:00 |
description | Office hours on Monday |
weekdays[0] | mon |
- seattle-office-hours のチェックボックスを選択し、アクションから「コピー」をクリック
- 下記設定し、「項目の作成」をクリック
フィールド名 | 値 |
---|---|
name | mon-9am-18pm |
timezone | Asia/Tokyo |
description | Monday 9am to 18pm in Japan (JST) |
periods[0] | mon-start-9am |
3. インスタンスへのタグ付け
- マネジメントコンソールのインスタンス一覧画面 から対象のインスタンスを選択し、タグのタブから「タグを管理」をクリック
- 「タグを追加」をクリックし、キーに CloudFormationのInstance Scheduler tag name で指定した値 (初期値は Schedule)、値に適用するスケジュール定義の name の値 (今回は mon-9am-18pm) を入力
- 「保存」
4. リモートスタックの作成
- 「 リモートスタックの作成 」>サインイン(入り直す必要あり)、リージョンを東京へ変更
- InstanceSchedulerAccount、Namespace(1のNamespaceと同じになるように設定)などパラメータを設定
- 設定した時間になり、スケジュール通り起動・停止していることを確認
複数インスタンス・複数スケジュールでの設定
起動・停止したいスケジュールをDynamoDBのpiriodとscheduleで設定し、対象インスタンスにschedule名をタグ付けする。
問題なく起動・停止した場合はタグにScheduleMessageが作成され、実行時間が確認できる。
→スタック2つ、Lambda1つ、Eventblidge1つ、DynamoDBのScheduleとpiriodはスケジュールの数分作成すればよい。
ただ、どの対象インスタンスがどのスケジュールで設定されているか一覧で分からないため、別途管理する必要があるかも。
コスト
例:月額約 33.24 ドル Instance Schedulerの費用
※5 つのアカウント * 2 リージョン * 3 サービス (Amazon EC2/Amazon RDS/Aurora クラスター) * 2 つのスケジュール数 * 1 日あたりのスケジューラーあたりのアクションの最小数 2 * 各 Runbook の 4 つのステップの場合
→コストは起動停止対象のインスタンス数は関係せず、実行数の合計によって決まる。
注意
- 「2. スケジュール定義、ピリオド定義」の際、 config と schedule のTimeZoneを「Asia/Tokyo」にする。
- 3までの手順で実行するとオートメーションのステップ1でエラーとなる。「4. リモートスタックの作成」で別途スタックを立てることで、1つめのスタックのAutomationExecutionRoleのロールが作成され、正常に動作する。