AWS Lambdaで、停止しているEC2インスタンスを起動させて、
立ち上がるのを待ってからコマンドを実行する、とした時に
詰まった点があったので備忘録として。
結論から
import boto3
def lambda_handler(event, context):
instance_id = '起動したいEC2インスタンスID'
ec2 = boto3.client('ec2')
ec2r = boto3.resource('ec2')
instance = ec2r.Instance(instance_id)
status_instance = ec2.describe_instances(InstanceIds=[instance_id])
if status_instance['Reservations'][0]['Instances'][0]['State']['Name'] == "running":
print('インスタンス起動済 ' + str(instance_id))
else:
print('インスタンス停止中 ' + str(instance_id))
# ここでインスタンス起動
instance.start()
print('インスタンス起動中... ' + str(instance_id))
# インスタンスの起動を待つ!
waiter = ec2.get_waiter('instance_status_ok')
waiter.wait(InstanceIds=[instance_id])
# コマンド実行
ssm = boto3.client('ssm')
r = ssm.send_command(
InstanceIds = [instance_id],
DocumentName = "AWS-RunShellScript",
Parameters = {
"commands": ["cd /xxx/www/yyy/", "bash a.sh >b.log 2>&1"]
}
)
.....
詰まったところ・詰まった時に使ったwait_until_running()
結果的には、waiterコマンドを使用してインスタンス起動を待ったのですが、
その前は、wait_until_running()を使用していました。
ec2 = boto3.resource('ec2')
instance = ec2.Instance('<インスタンスID>')
instance.start()
instance.wait_until_running()
ssm = boto3.client('ssm')
r = ssm.send_command(
......
このコードでもインスタンスがrunningになるまで待ってはいるようなのですが、
runningになった瞬間にコマンドが実行されます。
それで良さげなんですけど…
エラーになります。
エラーの内容は**「ssmコマンドが送信できませんでした。EC2インスタンスがコマンドを受け取ることができる状態ではありません。」**みたいな内容です。
##色々試した結果
ssm.send_commandの実行前に、
**time.sleep()**で10秒ほど待つと正常にコマンドが実行されます。
ただ、それだと根本の解決にならないので原因を調べてみました。
##多分これが理由
wait_until_running()では、あくまでrunningになるまで待っていて、
runningになった瞬間すぐはコマンドを実行できる状態ではないのではないか
というところに落ち着きました。
##waiterコマンド
前述の理由から、コマンドを実行できる状態まで待機をする方法を探したところ、waiterコマンドの instance_status_ok を見つけました。
wait_until_running()コマンド + time.sleep(10) の時は
コマンド実行完了まで40秒ほどで完了していましたが、
waiterコマンドの instance_status_ok では
statusが全てokになるまで待機するので実行時間は150秒前後になりました。
実行時間はかなり伸びてしまいますが、インスタンス起動後にコマンドを実行させる場合は後者の方が確実なのでそっちがいいかなと思います。
まとめ
インスタンスの起動を待つコマンドを検索すると、
wait_until_running() での解決方法がたくさん出てきます。
インスタンスを本当に起動させるだけであればそのコマンドで十分ですが、
その後に何かしら動作をさせたい場合は適切とは言えないかもしれません。
もし同じことで悩んだ人がいて、ここに辿り着いたとしたら、この記事が役に立つと嬉しいです。
waiterコマンドでも、引数が 'instance_status_ok' ではなく
'instance_running' だと wait_until_running() と同じになってしまうので、waiterコマンドで作りたい状況によって使い分けてあげることが大事です。