こんにちは。クラウドインテグレーション本部 インプリメンテーション部 DB/APPプロフェッショナルチームの竹永です。
まだ部署名を覚えきれていません。
最近は真面目な文章ばかり書いていたので、息抜きにネタ成分50%のインスタンスを作ってみたいと思います。
概要
- 1時間くらいでTerminateされるインスタンスを作ります
- インスタンス単体で動作するようにします
- インスタンスにAWSのアクセスキーを保存しません
- 起動してからSSHで手を出すのは無し
- 今のところAmazon Linuxだけ動作確認済み
とりあえずつくる
概要だけでは作り方がわからないので、とりあえず作ってみます。
IAM Roleをつくる
まずはAWS Management Consoleにログインして[IAM]をクリックします。
IAMの管理画面で[Create New Role]ボタンをクリックします。
Roleの名前を入力して[Next]ボタンを押します。
Role Typeは[Amazon EC2]を選択します。
Set PermissionsではIAM Roleに設定する権限を選びますが、今回は[Custom Policy]を選択して手動入力してみます。
名前はわかりやすいものを、ポリシーはひとまずTerminateだけ出来るように設定して、[Next]をクリックします。
今回は下記のポリシーを使いました。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:TerminateInstances",
"Resource": "*"
}
]
}
最後にReview画面が出てきますが、IAM Roleはいくら作っても無料です。
難しいことは考えずに[Create Role]ボタンをクリックしましょう。
EC2インスタンスをつくる
次に、EC2の管理画面を表示し、[Launch instance]ボタンで新しいインスタンスを作成します。
Amazon Linuxを選んでいただければ、ほとんどのパラメーターはお好みで大丈夫ですが、IAM roleとUser dataはお好み具合が少なくなります。
IAM roleは先ほど作成したものを指定します。
インスタンス作成後は変更できないので忘れたらダメです。
ユーザーデータにもスクリプトを仕込んでおきます。
インスタンス変更後も変更できますが、これが本体なので忘れたらダメです。
今回使用したスクリプトは下記のものになります。
Base64でエンコードされている箇所は、ちょこっと下の方で説明いたします。
#!/bin/sh
echo "IyEvYmluL3NoClVQVElNRT1gY2F0IC9wcm9jL3VwdGltZSB8IGF3ayAne3ByaW50ICQxICogMTAwMH0nYApSRUdJT049YGN1cmwgLXMgaHR0cDovLzE2OS4yNTQuMTY5LjI1NC8yMDE0LTAyLTI1L2R5bmFtaWMvaW5zdGFuY2UtaWRlbnRpdHkvZG9jdW1lbnQgfCBncmVwIHJlZ2lvbiB8IGF3ayAtRlwiICd7cHJpbnQgJDR9J2AKSU5TVEFOQ0VJRD1gY3VybCAtcyBodHRwOi8vMTY5LjI1NC4xNjkuMjU0LzIwMTQtMDItMjUvbWV0YS1kYXRhL2luc3RhbmNlLWlkYAppZiBbICR7VVBUSU1FfSAtZ3QgMzMwMDAwMCBdIDsgdGhlbgogIGF3cyBlYzIgdGVybWluYXRlLWluc3RhbmNlcyAtLXJlZ2lvbiAke1JFR0lPTn0gLS1pbnN0YW5jZS1pZHMgJHtJTlNUQU5DRUlEfQpmaQo=" | base64 -d > /tmp/self_terminate.sh
chmod +x /tmp/self_terminate.sh
echo "*/1 * * * * /tmp/self_terminate.sh" | crontab
あとは1時間分の料金を支払う覚悟をしてからインスタンスを起動すれば、自滅するインスタンスのできあがりです。
実際はタイムラグによる課金回避のために、生まれてから55分くらいで自滅しますが、あまり気にしないようにしましょう。
しくみ
Base64のなかみ
Base64はデコードするとただのシェルスクリプトです。シングルクォーテーションとかのエスケープが面倒くさくなってきたので、思い切ってBase64にしました。
#!/bin/sh
UPTIME=`cat /proc/uptime | awk '{print $1 * 1000}'`
REGION=`curl -s http://169.254.169.254/2014-02-25/dynamic/instance-identity/document | grep region | awk -F" '{print $4}'`
INSTANCEID=`curl -s http://169.254.169.254/2014-02-25/meta-data/instance-id`
if [ ${UPTIME} -gt 3300000 ] ; then
aws ec2 terminate-instances --region ${REGION} --instance-ids ${INSTANCEID}
fi
「S3からダウンロードすればいいのでは?」と思った方は正しいです。curl
やwget
やaws s3 cp
を使えば、一発ですし、簡単ですし、おすすめです。
しかし、僕がBase64の気分でした。base64
コマンドを使ってみたかったのです。
インスタンスのUptimeをもってくる
自滅するタイミングは/proc/uptime
で計測しています。
/proc/uptime
が返してくる時間が指定値以上になったら、自らをTerminateするコマンドを実行します。
今回は3300000ミリ秒(55分)を指定しました。
0を指定すれば、立ち上がって準備ができて1分ほどでTerminateするインスタンスができあがります。
AWSへのお布施にどうでしょうか。
なぞの curl -s http://169.254.169.254/
自滅するのに使用するaws ec2 terminate-instances
コマンドは、引数に--region
, --instance-ids
が必要です。
Terminateするために必要な情報は、IMDS(Instance Meta Data Service)から取得してきます。
取得した情報を組み合わせると下記のようなコマンドができあがります。
aws ec2 terminate-instances --region ap-northeast-1 --instance-ids i-xyz12345
-s
オプションはcurl
をSilent modeで実行させているだけです。
とても元気だったので静かになってもらいました。
アクセスキーは?
AWS CLIは、インスタンスにIAM Roleを指定するとアクセスキー等を指定しなくても動くようになります。
APIを自力で叩こうとすると、IAM Roleから一時的なアクセスキーを取得するだけでも一苦労ですが、AWS CLIのお陰で簡単に使えます。
IAM Roleを間違えると、Terminateし放題のインスタンスが完成します。
最後の一手間
最後に、上記で解説したスクリプトを、cron
で1分ごとに実行します。
インスタンスに負荷が掛かっているとスクリプトの実行に時間がかかりそうだったので、55分くらいでTerminateするようにしています。
余談
「インスタンスがいるリージョン名」を取得する箇所だけは、何故か苦労しました。
Availability Zoneは簡単に取得することが出来るのですが、後ろにくっついている"a"とか"b"とか"c"という1文字が少し厄介です。
AWK最強説。
ユースケースは?
正直に言うとジョークスクリプトの類です。1時間後には何も残っていないので、やたらとたちが悪いです。
Spot Instanceをいっぱい作ってバッチっぽい処理を動かすといいかもしれませんが、そのまま使うと1時間で中断されます。惜しい。
cron
で1時間や1日毎に、TerminateではなくAMIを作成すればバックアップには使える可能性があります。
ただ、自分でスクリプトを書いて自動バックアップ環境を構築するよりCloud Automatorを使ったほうが早いです。
ちなみにテストは行っていますが動作保証はしていません。
10分で自滅するように設定したら、10分3秒で自滅したことはご報告いたします。
まとめ
無駄な動きをする無駄に手の込んだ無駄なスクリプトを作るのは楽しいです。
「Base64の日報」を…思い出しました…。
…ごめんなさい、ごめんなさい…もうしません…。