
もくじ
API Gateway + Lambda開発のコツ
タイムアウト

処理時間の3倍程度をLambda設定のタイムアウトに設定する。
10秒を設定
ログ出し
ログがないとまともな開発はできない
- cloudWatchにIAMロールでCloudWatch Logsのアクセスができるロールを作成
- API Gatewayの設定でarnを指定する
- API Gatewayの設定でログを有効化させる
- CloudWatch Logsからログを見ながら開発する
最初はLambdaで直開発
Lambda側で動作確認できてから、API Gatewayで動かすと開発しやすい
eventが取得できない?
①API GatewayからLambdaにリクエストボディを投げる際は加工する処理が必要
event = json.loads(event['body'])
②Lambda プロキシ統合の使用にチェックが必要
リクエストボディ
devを起動
{"region": "ap-northeast-1","action": "start","app_env": "dev"}
devを停止
{"region": "ap-northeast-1","action": "stop","app_env": "dev"}
事前準備
EC2
- dev
IsDevEc2AutoStartStop - stg
IsStgEc2AutoStartStop
それぞれValueはtrueとする
AutoScalingGroup
- dev
IsDevAutoScalingGroupAutoStartStop - stg
IsStgAutoScalingGroupAutoStartStop
それぞれValueはtrueとする
Lambdaに設定するIAM ロールに設定するポリシー
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"ec2:StartInstances",
"ec2:StopInstances",
"ec2:DescribeTags",
"ec2:Describe*"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "cloudwatch:*",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"events:DisableRule",
"events:EnableRule",
"events:DescribeRule"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"autoscaling:UpdateAutoScalingGroup",
"autoscaling:Describe*"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "logs:CreateLogGroup",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
},
{
"Sid": "IAMPassRoleForCloudWatchEvents",
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::*:role/AWS_Events_Invoke_Targets"
}
]
}
API Gatewayに設定するロール
●ロール名
ApiGatewayCloudWatchLogs
●用途
API GatewayのログをCloudWatch Logsに出力するロール
●ポリシー(既存)
AmazonAPIGatewayPushToCloudWatchLogs
Lambda Python3.9
import json
import boto3
import botocore
import traceback
def lambda_handler(event: dict, context: object):
headers = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
try:
# Lambda直, API Gateway経由の2パターンがあるので調整
if 'body' in event.keys():
# API Gateway経由の場合はbodyキーに格納されているので変換
event = json.loads(event['body'])
if _validation(event):
region = event['region']
action = event['action']
app_env = event['app_env']
else:
message = 'validation error: 必須キーが抜けています'
return {
"statusCode": 422,
'body': json.dumps(message)
}
app_env = app_env.capitalize() # dev -> Dev
tag = 'Is' + app_env + 'Ec2AutoStartStop' # ex. IsDevEc2AutoStartStop | IsStgEc2AutoStartStop
# bot3インスタンス生成
client = boto3.client('ec2', region)
# タグで指定してEC2インスタンス情報を取得
responce = client.describe_instances(Filters=[{'Name': 'tag:' + tag, "Values": ['true']}])
target_instans_ids = []
for reservation in responce['Reservations']:
for instance in reservation['Instances']:
print('start instance')
print(instance['InstanceId'])
print(instance['State']['Name'])
print('end instance')
if action == 'start' and instance['State']['Name'] == 'stopped':
target_instans_ids.append(instance['InstanceId'])
elif action == 'stop' and instance['State']['Name'] == 'running':
target_instans_ids.append(instance['InstanceId'])
if not target_instans_ids:
message = 'There are no target_instans_ids. do nothing.'
return {
"statusCode": 404,
'headers': headers,
'body': json.dumps(message)
}
if action == 'start':
# EC2の起動
client.start_instances(InstanceIds=target_instans_ids)
# AutoScalig Groupの台数を変更
if _updateAutoScalingGroups(action, app_env, region) == False:
raise Exception
print('started instances.')
elif action == 'stop':
client.stop_instances(InstanceIds=target_instans_ids)
if _updateAutoScalingGroups(action, app_env, region) == False:
raise Exception
print('stopped instances.')
else:
print('Invalid action.')
message = 'Success'
return {
"statusCode": 200,
'headers': headers,
'body': json.dumps(message)
}
except:
message = traceback.format_exc()
return {
'statusCode': 500,
'headers': headers,
'body': json.dumps(message)
}
# バリデーション
def _validation(event: dict) -> bool:
if 'region' in event.keys() and 'action' in event.keys() and 'app_env' in event.keys():
return True
else:
return False
# 起動設定の更新
def _updateAutoScalingGroups(action: str, app_env: str, region: str) -> bool:
print('start _updateAutoScalingGroups()')
# 起動する場合の最小, 要求数
start_param = dict(MinSize=1, DesiredCapacity=1)
# 停止する場合の最小, 要求数
stop_param = dict(MinSize=0, DesiredCapacity=0)
autoscaling = boto3.client("autoscaling", region)
response = autoscaling.describe_auto_scaling_groups()
tag = 'Is' + app_env + 'AutoScalingGroupAutoStartStop' # ex. IsDevAutoScalingGroupAutoStartStop | IsStgAutoScalingGroupAutoStartStop
all_autoscaling_groups = response['AutoScalingGroups']
auto_scaling_names = []
auto_scaling_names = _getAutoScalingGroupNames(all_autoscaling_groups, tag)
if not auto_scaling_names:
print('There are no auto_scaling_names. do nothing')
return
try:
if action == 'start':
for i in range(len(auto_scaling_names)):
print('start auto_scaling_name')
print(auto_scaling_names[i])
print('end auto_scaling_name')
autoscaling.update_auto_scaling_group(AutoScalingGroupName=auto_scaling_names[i], **start_param)
elif action == 'stop':
for i in range(len(auto_scaling_names)):
print('start auto_scaling_name')
print(auto_scaling_names[i])
print('end auto_scaling_name')
autoscaling.update_auto_scaling_group(AutoScalingGroupName=auto_scaling_names[i], **stop_param)
else:
print('Invalid action.')
return True;
except:
print(traceback.format_exc())
return False;
# AutoScaling名取得
def _getAutoScalingGroupNames(all_autoscaling_groups: list, tag: str) -> list[str]:
print('start _getAutoScalingGroupNames()')
auto_scaling_names = []
for i in range(len(all_autoscaling_groups)):
all_tags = all_autoscaling_groups[i]['Tags']
for j in range(len(all_tags)):
if all_tags[j]['Key'] == tag and all_tags[j]['Value'] == 'true':
auto_scaling_names.append(all_autoscaling_groups[i]['AutoScalingGroupName'])
return auto_scaling_names
上記のLambdaを叩く時のスケジューラの関数
import json
import boto3
def lambda_handler(event, context):
headers = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
try:
# Lambda直, API Gateway経由の2パターンがあるので調整
if 'body' in event.keys():
# API Gateway経由の場合はbodyキーに格納されているので変換
event = json.loads(event['body'])
if _validation(event):
region = event['region']
action = event['action']
rules = event['rules']
else:
message = 'validation error: 必須キーが抜けています'
return {
"statusCode": 422,
'headers': headers,
'body': json.dumps(message)
}
client = boto3.client('events', region)
for i in range(len(rules)):
# 無効
if action == 'disable':
response = client.disable_rule(
Name = rules[i],
)
# 有効
elif action == 'enable':
response = client.enable_rule(
Name = rules[i],
)
else:
print('Invalid action.')
raise Exception
# TODO implement
return {
'statusCode': 200,
'headers': headers,
'body': json.dumps('Success')
}
except:
message = traceback.format_exc()
return {
'statusCode': 500,
'headers': headers,
'body': json.dumps(message)
}
# バリデーション
def _validation(event: dict) -> bool:
if 'region' in event.keys() and 'action' in event.keys() and 'rules' in event.keys():
return True
else:
return False




![Gunosy スコア計算[NOINDEX]](https://www.yuulinux.tokyo/contents/wp-content/uploads/2018/11/20171130190021-150x150.jpg)