できるだけシンプルな仕組みで簡単にEC2の自動起動・停止を実現したい!

アイキャッチ AWS EC2
141件のシェア(ちょっぴり話題の記事)

こんにちは、このすばアニメ新企画が決定してテンションが上がっている城内です。

はじめに

AWS上でシステムを構築していると、インフラ構築中やアプリ開発中などは、コスト削減のために使わないリソースは極力止めておきたいと考えるかと思います。
私もEC2で大きめのインスタンスを立てているときなどは、結構気になります。

先日も環境構築をしていて、夜や週末にEC2を止めておきたくなり、でも手動でやるのはなーと思い、軽くググってみました。

まあ、よくある要望なのでやり方はたくさん出てきたのですが、別に運用で使うわけでもないため、ササッとやりたいですし、そのために余計なリソースも使いたくないと考えました。

で、まずは以下の記事を参考に作ってみました。

ただ、上記の方法ですと、1インスタンスしか指定できなくて、複数のインスタンスを取り扱いたい自分にはフィットしませんでした。

で、次に弊社のブログから以下の記事をピックアップしてみました。

まあ、最初の記事でNode.jsだったのがPythonになっただけのようなものですが、とりあえず複数インスタンスは指定できました。

・・・えーと、確かに悪くないですし、要望は叶ったのですが、なんかもうちょっとこうもう一捻りというか、あぁーうぅー・・・(´ε`;)ウーン…

やってみた

やっぱりこういうのって、個性が出ますよねっ!
ってなわけで、結局自分なりにカスタマイズしてしまったので、公開しておきます。

使うリソース

今回使うリソースは以下になります。

  • Lambda
  • IAM Role
  • CloudWatch Events

設定

設定は先の記事を真似ているので、細かい部分はそれらを参照してくだい。

Lambda

まずは、Lambdaの設定をします。

「Blank Function」を選択し、トリガーの設定はスキップします。
名前は適当に付けてもらって、ランタイムは「Python 2.7」を選択します。

lambda_01

コードは以下になります。

import boto3

def lambda_handler(event, context):
    region = event['Region']
    instances = event['Instances']
    ec2 = boto3.client('ec2', region_name=region)
    if event['Action'] == 'start':
        ec2.start_instances(InstanceIds=instances)
        print 'started your instances: ' + ", ".join(instances)
    elif event['Action'] == 'stop':
        ec2.stop_instances(InstanceIds=instances)
        print 'stopped your instances: ' + ", ".join(instances)

先の記事と違うところはここになります。
Lambdaへのハードコーディングはなるべく避け、必要な値はCloudWatch Eventsから渡すようにしました。
なので、このファンクション一つで事足りるようになりました。

IAM Role

次に、IAM Roleを設定します。

「カスタムロールを作成」を選択し、以下のように設定します。

iam_01

ポリシードキュメントは以下になります。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "ec2:Start*",
        "ec2:Stop*"
      ],
      "Resource": "*"
    }
  ]
}

これでベースは出来上がりました。
あとはトリガーを設定するだけですが、トリガーは、起動・停止、実行したいタイミング、対象のインスタンスを自由に組み合わせて、必要なだけ設定すればOKです。

実際に設定してもらうと分かるかと思いますが、ある程度柔軟に設定できるようになっているはずです。

CloudWatch Events

最後に、CloudWatch Eventsの設定をします。

ルールの作成画面にて、以下のように設定します。
スケジュールは「毎週月曜の日本時間9時」に実行するように指定しています。

cw_01

ここでのポイントは、ターゲットの入力の設定です。
「定数(JSON テキスト)」を選択し、ActionRegionInstancesの項目を入れた以下のような値を設定します。

{"Action": "start", "Region": "ap-northeast-1", "Instances": ["i-xxxxxxxxxxxxxxxxx","i-yyyyyyyyyyyyyyyyyy","i-zzzzzzzzzzzzzzzzz"]}

上記は起動の時の設定ですが、停止の場合はActionの値を「stop」にしてください。

うまく設定できれば、以下のようにルールが作成されます。

cw_02

Lambdaの画面にもトリガーとして紐付けられます。

lambda_02

以上で完了です。
あとは必要なだけCloudWatch Eventsでルールを作成すればOKです。

さいごに

いかがでしたでしょうか?
先人たちの知恵を借りつつ、シンプルで簡単にできる方法を考えてみました。

ちょっとしたときにでも使ってもらえれば幸いです。

  • Fujiwara_y

    有用な記事をありがとうございます。インスタンスはTagで指定できると便利なのじゃないでしょうか。ec2クライアントのdescribe_tagsを使うと良さそうです。

    • 城内秀仁

      コメントありがとうございます!
      返信が遅くなりすみません。。

      私もタグを使えばさらに便利になりそうだなと思っていました。
      今回は元のコードから最低限の改修で実装したので、取り込みませんでしたが^^;
      有用なご指摘ありがとうございます!