自動停止EC2ホストを作る

Share on:

基本的に以下のチュートリアルをやってみた結果とかになりますが。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/start-stop-lambda-cloudwatch/

割と画面が合ってないし、解説が簡素なのでもうちょっと濃厚に解説を入れてきたいと思います。

スクショ多めでね。

IAM ポリシーおよびロールを作成する

とかいきなり言われてもなあ…って感じですが、まあこんな感じにしろと言っています。

 1{
 2  "Version": "2012-10-17",
 3  "Statement": [
 4    {
 5      "Effect": "Allow",
 6      "Action": [
 7        "logs:CreateLogGroup",
 8        "logs:CreateLogStream",
 9        "logs:PutLogEvents"
10      ],
11      "Resource": "arn:aws:logs:*:*:*"
12    },
13    {
14      "Effect": "Allow",
15      "Action": [
16        "ec2:Start*",
17        "ec2:Stop*"
18      ],
19      "Resource": "*"
20    }
21  ]
22}

これ、何にも考えずにコピペするでなく、よく見ればわかるけどログの注入とec2の開始/終了を許可する「ポリシー」である事は理解できると思います。これを作っただけでは何も起きません。そういう権限が出来ますよって事になります。

作り方ですが「マイセキュリティ資格情報」とかからでもいいけど、権限のあるユーザでログインして

https://console.aws.amazon.com/iam/home?region=ap-northeast-1#/policies

とかにジャンプしたらいけるんじゃないでしょうか?

こんな感じでコードをベタっとはればポリシーが出来ます。まあ便利っちゃ便利なんすよね。とりあえず名前を付けます。チュートリアルではこれといって指定はないですが、ここではEC2StartStopとか適当な名前にします。

ロールを作る

「ロール」というのは複数の「ポリシー」を関連付けるものです。EC2StartStopを作ったので、これを割り当てるんだけども、それ以外のものを割り当てる事もできるという事になりますね。今回はしません。単に↑で作ったポリシーを実行するだけのシンプルなロールです。

https://console.aws.amazon.com/iam/home?region=ap-northeast-1#/roles

「AWSサービス」のロールからlambdaを選びます

ここで、↑で設計したように先程作ったポリシーだけを当てます。

次の画面で出るタグはまあ適当にして(空でよい)、名前も適当にします。ここではEC2StartStopって同じ名前にしちゃいましたね。

うまくいけば作成されるでしょう。

EC2を立てる

ここでAWSの手順書では省略されてるんですが止める対象のインスタンスを上げます。VPCも何もかも適当でいいからEC2のインスタンスを1つ上げてください。OSも何でもok。ログインしないからキーペアもなしでokです。

これはスクショいらないよね?

lambda関数を作成する

ここからいよいよプログラムを書いていきます。

dashboardからlambdaを選ぶとこんな画面になりますね。

「関数の作成」ってのが右上にあるから押します。

続いて「一から作成」

続いて関数名に「StopSpeficiedEc2Instance」とか入力し、ランタイムはpython3.8を指定します。時期によってはpythonのバージョンがちょっと違ってたりするかもしれませんね。

続いて実行権限を指定します。ここ重要。先程作成したEC2StartStopを指定するわけですが、この権限以上の事はできないという事になりますね。つまりプログラムからEC2を開始/終了とログに送る以外はできないという事ですね。

するとこんな画面になりますが

下の方までめくると関数エディタみたいなのがあります。ここに以下のコードを投入します。

1import boto3
2region = 'us-west-1'
3instances = ['i-12345cb6de4f78g9h', 'i-08ce9b2d7eccf6d26']
4ec2 = boto3.client('ec2', region_name=region)
5
6def lambda_handler(event, context):
7    ec2.stop_instances(InstanceIds=instances)
8    print('stopped your instances: ' + str(instances))

めちゃくちゃ簡単なコードではありますが、何も考えずにコピペしてはいけませんw。

修正が必要です。まず作成したインスタンスのIDが必要なのでEC2からコピってきてください。

この場合は i-0f6361d406ce4e986

以下のように修正していきます。

1import boto3
2region = 'ap-northeast-1' # これと
3# instances = ['i-12345cb6de4f78g9h', 'i-08ce9b2d7eccf6d26']
4instances = ['i-0f6361d406ce4e986'] # これ
5ec2 = boto3.client('ec2', region_name=region)
6
7def lambda_handler(event, context):
8    ec2.stop_instances(InstanceIds=instances)
9    print('stopped your instances: ' + str(instances))

簡単な構文ですが、とりあえずinstancesに複数のインスタンスを書いて、ec2オブジェクトのstop_instancesメソッドに渡せばよさそうという事くらいはわかりますね。

そしたらかならず「Deploy」ボタンを押します。忘れがちになるやつです。

テスト

さて、この関数が正しいのか間違っているのか、とりあえずを実行する必要があります。実行できれば意図した通りにいくならば指定したインスタンスは停止するはずですから、とりあえずインスタンスが起動してるかくらいは確認しておきましょう。

起動させるには「トリガー」がどこかに必要で、それに関して今回は「テスト」がその役割を受けもつという事になるんですが、どっこい「テスト」を押すといきなりよくわからない画面になります。

これは、あらゆる複雑なイベントトリガーに対応しているのですが、今回は何にも考えずイベント名を指定して保存します。ここではstoptestとかいう名前にしました。 この辺の事をもっと掘り下げるといろいろ可能性がでると思いますが、とりあえず今回はテストコードを見ての通り2行(実質1行)で完結しているため、あまり意味がありません。ちなみに

1{
2  "key1": "value1",
3  "key2": "value2",
4  "key3": "value3"
5}

このkeyとvalueは

1def lambda_handler(event, context):

このevent引数に入ってきたりします。参考まで。

とりあえずテストを仕掛けてみて、指定したEC2インスタンスが停止していればとりあえずは成功です。失敗した場合ログを参考に関数を修正し、修正があった場合はまた必ず「Deploy」します。関数以前にポリシー的なpermission deniedとかなっている場合は振り出しに戻る…

なおチュートリアルはタイムアウトを3秒から10秒に変更しろと書いてありますので、そうした方がいいかも。止まるの遅かったりとかいうのの対応でしょうか?複数止める場合は特に

トリガーの作成

ここまで「テスト」を手で叩いでEC2が止まる事は確認できたのでもう8割がた出来ているといってもいいんですが、毎回「テスト」を手で叩いて止めていては話にならないので、これを起動する「トリガー」を作成します。

これはこれでまた場所が違っていて面倒くさいのですが、ダッシュボードからCloudWatchを開いて行います。

すると左ペインにイベント→ルールというのがあります

「ルールの作成」 で「スケジュール」を選びます。スケジュールは定時実行するタイプのもので、「イベントパターン」は、AWS内の何かのイベントがおきたらナニコレするとかそういう奴です。まあ今回は使いません。

で、今回は5分毎でいいんですけど、ためしにcron式で書いてみます。

cron式はちょっと異なってますけど、うまくいくと下の方に次の実行はいついつだって出てきます。UTCなのはどうにもならないようです。

適当にこのトリガーの名前を書いて保存します。ここではstopSpecifiedEc2と設定

そしたら適当にインスタンスを起動し、放置して停止していれば、とりあえずこのチュートリアルは終わりです。おつかれさまです!

しかしイマイチな点も結構ある

まず、インスタンスのIDをいちいち手打で指定するというのはイケていません。そもそも、EC2インスタンスなんてのは生えては消えるなんていう使い方をする事が結構あるのでその場合IDをおっかけられるようにしておきたいものです。まああと5分っていうのは流石に微妙だけど定時で止めるのはそれはそれでどうかというのもありますよね。このあたり、いろいろ可能性あると思うんですが、とりあえずは止められるようにしておかないと先に進めないと思うから、ここに書いてあるような事は何も見ずにやれるようにくらいまで練習してもよろしいのではないかと思われます。