本記事はBIPROGY / UAL社内AWSコミュニティ「BIPROGY AWS Ambassador」の
定期投稿企画第3回目の記事です。他の定期投稿企画の記事は、
#BIPROGY_AWS_Ambassadorタグ または Organizationページをご覧ください。
目次
- はじめに
- やりたいこと
- 全体アーキテクチャ
- Lambda関数の実装
- 関数①:EC2インスタンスへタグを自動で付与する関数
- 関数②:EC2インスタンスの自動停止
- Amazon EventBridgeの設定
- 実際の動作・結果
- まとめ
1. はじめに
突然ですが、最近ある悩みが生まれました。。。
というのも、AWSサービスへの理解を深めるため、自分のアカウントでハンズオンを実施しているのですが、その時にEC2インスタンスの停止をし忘れてしまうことです。
「作業が終わったらEC2インスタンスを停止させる!」ということを常に意識しているものの、どうしても忘れてしまうときがあります。
そこで!「EC2インスタンスを停止させたい時刻に停止させる仕組み」を、AWSのサービスを組み合わせて実現すればよいのではないかと考えました。また、私が作成したEC2インスタンスのみに対し、この仕組みを実装させれば、他の人が作成したリソースへの影響もないと思ったので、その仕組みも作成することにしました。
2. やりたいこと
簡単にまとめると以下になります。
- EC2インスタンスを停止させたい時刻に、自動で停止させたい
- 自分以外が管理するEC2インスタンスが混在する環境なので、自分が作成したEC2インスタンスだけ対象にしたい
3. 全体アーキテクチャ
今回の構成は下記になります。
構成のポイントは以下の2点です。
1つ目は、EC2インスタンスを作成する際、「EC2インスタンスへタグを付与する関数(以後、Lambda関数①)」を利用してリソースへタグを付与させている点です。このタグは「停止させたい時刻(日本時間)」になります。
2つめは、「EC2インスタンスを自動停止する関数(以後、Lambda関数②)」で付与されたタグを読み込み、タグに記載されている時刻になったらEC2インスタンスを停止させるという仕組みです。
処理概要
アーキテクチャ図内の処理の流れは以下になります。
- 1,2:EC2インスタンス作成時、CloudTrailでRunInstancesイベントを検知
- 3,4:EventBridgeルールでLambda関数①を呼び出す
- 5:Lambda関数①が「自分が作成したEC2インスタンス」に停止時刻タグを自動で付与
- 6:EventBridgeスケジューラでLambda関数②を定期実行
- 7:Lambda関数②がタグを確認し、指定時刻になったらEC2インスタンスを停止
4. Lambda関数の実装
2つのLambda関数は、それぞれPythonで実装しました。
関数①:EC2インスタンスへタグを自動で付与する関数
まずは、Lambda関数①になります。
import boto3
def lambda_handler(event, context):
# 特定ユーザの判定
target_user = "<自分のIAMユーザー名>"
# イベント内のユーザ情報を取得してチェック
try:
user_key = event['detail']['userIdentity']['userName']
except KeyError:
print("ユーザ情報が取得できませんでした")
return
if user_key != target_user:
print(f"ユーザ{user_name}は対象外のため処理をスキップします")
return
ec2 = boto3.client('ec2')
instance_ids = [event['detail']['responseElements']['instancesSet']['items'][0]['instanceId']]
# タグを2つ付与
tags = [
{'Key': 'AutoShutdown', 'Value': 'true'},
{'Key': 'StopTime', 'Value': '18:15'} # 例:日本時間で指定
]
ec2.create_tags(Resources=instance_ids, Tags=tags)
上から2行目~5行目のコードでCloudTrailのイベント履歴にある「RunInstance」イベントを検知した時、実行したIAMユーザー名と3行目のパラメータを比較します。ここで、自分が作成したリソースかどうかの判定を行います。
もし、パラメータが異なった場合、CloudWath Logsに10行目の文言(対象外のため処理をスキップします)が出力されます。
そして一致した場合、後半の12行目~18行目のコードでEC2インスタンスを停止させたい時刻のタグを付与します。
(日本時間18時15分に停止させるため、コード内では「18:15」という値を記載しています。)
関数②:EC2インスタンスの自動停止を行う関数
次に、Lambda関数②になります。
import boto3
from datetime import datetime, timedelta, timezone
ec2 = boto3.resource('ec2')
client = boto3.client('ec2')
def lambda_handler(event, context):
now = datetime.now(timezone(timedelta(hours=9))).strftime('%H:%M')
stopped_instances = []
filters = [
{'Name': 'tag:AutoShutdown', 'Values': ['true']}
]
for instance in ec2.instances.filter(Filters=filters):
if instance.state['Name'] == 'running':
for tag in instance.tags:
if tag['Key'] == 'StopTime' and tag['Value'] == now:
client.stop_instances(InstanceIds=[instance.id])
stopped_instances.append(instance.id)
return {'stopped': stopped_instances}
ここではLambda関数②が実行された時刻(「5.2:Amazon EventBridgeの「スケジュール」」で設定)とLambda関数①によってEC2インスタンスのタグに付与された時刻を照らし合わせ、一致した場合EC2インスタンスを停止させる仕組みを実装しています。
5.Amazon EventBridgeの設定
今回、Amazon EventBridgeの設定で、主に以下の2つを設定しました。
1:Amazon EventBridgeの「ルール」
1つ目はAmazon EventBridgeのルールです。
これは、EC2インスタンスが起動された際にCloud Trailから「Run Instance」イベントを検知し、Lambda関数①を呼び出すためのものです。
このルールを定義することで、EC2インスタンスが起動すると同時にタグが自動で付与される仕組みが作成されます。
Amazon EventBridge内の「イベントパターン」タブ内には「event.json」が記載されています。
{
"source": ["aws.ec2"],
"detail-type": ["AWS API Call via CloudTrail"],
"detail": {
"eventSource": ["ec2.amazonaws.com"],
"eventName": ["RunInstances"]
}
}
そして、ターゲットとしてLambda関数①を指定します。
2:Amazon EventBridgeの「スケジュール」
2つ目は、Amazon EventBridgeの「スケジュール」です。
これは、定期的にLambda関数②を呼び出し、EC2インスタンスのタグに設定されている時刻と、関数呼び出しの時刻が一致した場合に、EC2インスタンスを停止させるためのものです。
今回は、cron式で「0/15」ということで、毎時0分から15分毎に関数を呼び出すよう指定しました(この設定は任意で指定できます)。
マネージメントコンソールからは下の図のように確認することが出来ます。
「スケジュール」タブの隣にある「ターゲット」タブには、Lambda関数②を指定します。
このように設定することで、Lambda関数②が15分おきに実行されます。
EventBridgeでcron式を使ってスケジュールを設定する際、初回の実行タイミングには少し注意が必要です。
例えば、以下のような挙動になります。
・cron式「0/15」の場合(毎時0分から15分毎)
初回の実行は、設定した時刻に最も近い15分刻みのタイミング(xx:00、xx:15、xx:30、xx:45)のいずれかで開始されます。
・cron式「0/10」の場合(毎時0分から10分毎)
初回の実行は、、設定した時刻に最も近い10分刻みのタイミング(xx:00、xx:10、xx:20、xx:30、xx:40、xx:50) のいずれかで開始されます。
この仕様は、EventBridgeが内部的に一定間隔でスケジュールを評価しているためです。詳しい設定方法については下記公式リンクをご参考ください。
URL:Using cron and rate expressions to schedule rules in Amazon EventBridge
Amazon EventBridgeの設定は以上です。
6.実際の動作と結果
実際に、「EC2インスタンスへのタグ付与→タグをもとに自動停止」の動作確認をしました。
まずは、EC2インスタンスへのタグの付与です。
CloudWath Logsに格納されたログを確認すると、Lambda関数①の開始と終了が正常に行われたことを確認できます。
また、他の人がEC2インスタンスを作成した場合は下記のように、開始と終了のログの間にLambda関数①で定義した文言(赤枠部分)が出力されます。
次に、タグをもとにしたEC2インスタンスの自動停止です。
同VPC内のEC2インスタンスから、Lambda関数①によってタグ(18:15)を付与したEC2インスタンス(IP:172.31.14.230)へPingを打ち続けたところ、、18時15分を少し過ぎたあたりから応答がなくなり(停止処理が正常に動作)、1分後には宛先ホストに到達できないエラーが出力されました。
付与したタグをもとに、Lambda関数②によってEC2インスタンスが、自動で停止されたことが確認できました。
7.まとめ
以上、AWS Lambda関数とEventBridgeを利用して、EC2インスタンスの自動停止を実現する仕組みを構築してみました!
今回はタグを利用したアプローチでしたが、他のAWSのサービスでの実現や、「時刻」ではなく「CPU使用率」をトリガーとし、利用頻度の低いEC2インスタンス停止させてみる、などまだまだ改良の余地はたくさんあると思っています。
実際にAWSのサービスを触りながら、AWSの知識をどんどんインプット、アウトプットしていきたいと思います!
最後までお読み頂きありがとうございました!
We Are Hiring!



