AWS Data Pipelineを利用したAWSジョブスケジューラ

2015.07.03

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんばんは、城内です。 ついに先日AWS LambdaがTokyoリージョンに上陸しましたね。以下のまとめ記事、いいですね!

そんな中、今回はData Pipelineネタです。なぜいまLambdaのTokyoリージョン上陸を喜びつつもData Pipelineなのかは、この記事をご覧頂ければきっと分かってもらえるかと思います(笑)。

はじめに

今回何をやるのかというと、Data Pipelineをジョブスケジューラ代わりに使ってみたいと思います。 実行する処理は、定期的に不要なEC2インスタンスを停止するジョブです。開発用インスタンスの止め忘れなど、皆さんもよくあることかと思います。

事前準備

まず、Data Pipelineのロジック部分となるスクリプトとそれを格納するS3バケット、通知用のSNSトピックを作成します。

EC2インスタンス停止スクリプト

今回は以下のようなスクリプトを作成しました。 基本は、対象リージョンで起動しているすべてのEC2インスタンスを容赦なく停止していく仕様なのですが、除外の措置として、停止したくないEC2インスタンスに対し、「Production=True」タグを設定しておけば対象外となります。

stop-instances.sh

#!/bin/bash

targetRegion="ap-northeast-1"
myTagName="Production"
timeoutMins=5
topicArn="arn:aws:sns:ap-northeast-1:123456789012:dp-test"

export AWS_DEFAULT_REGION=$targetRegion

prodInstanceIds=$(echo $(aws ec2 describe-instances | jq '.Reservations[].Instances[] | select(.Tags[] | select(.Key == "'$myTagName'") | .Value == "True").InstanceId'))
myInstanceId=$(curl -s http://169.254.169.254/latest/meta-data/instance-id/)
nonStopInstanceIds="$myInstanceId $prodInstanceIds"

stopInstanceIds=
for runInstanceId in $(aws ec2 describe-instances | jq '.Reservations[].Instances[] | select(.State.Name == "running").InstanceId')
do
  runInstanceId=$(echo $runInstanceId | sed 's/\"//g')

  if [ $(echo $nonStopInstanceIds | grep -c $runInstanceId) -eq 0 ]; then
    aws ec2 stop-instances --instance-ids $runInstanceId

    if [ "$stopInstanceIds" == "" ]; then
      stopInstanceIds="$runInstanceId"
    else
      stopInstanceIds="${stopInstanceIds} $runInstanceId"
    fi
  fi
done

if [ "$stopInstanceIds" == "" ]; then
  exit 0
fi

notStopInstanceIds=$stopInstanceIds
for ((i=0; i < $timeoutMins; i++)); do
  sleep 60

  for checkInstanceId in $stopInstanceIds
  do
    result=$(aws ec2 describe-instance-status --instance-ids $checkInstanceId | jq '.InstanceStatuses[]')
    if [ "$result" == "" ]; then
      notStopInstanceIds=$(echo $notStopInstanceIds | sed "s/$checkInstanceId//")
    fi
  done

  if [ "$(echo $notStopInstanceIds | sed 's/ //g')" == "" ]; then
    break
  fi
done

stopInstanceIds=$(echo -e $(echo $stopInstanceIds | sed 's/ /\\n・/g'))
notStopInstanceIds=$(echo $notStopInstanceIds | sed 's/ /、/g')

message="以下のインスタンスを停止しました。
・$stopInstanceIds"

if [ "$notStopInstanceIds" != "" ]; then
  message="$message

※${notStopInstanceIds}のインスタンスは停止できませんでした。"
fi

aws sns publish --topic-arn $topicArn --message "$message" --subject "[Information] Job Scheduler has stopped EC2 instances."

exit 0

S3バケットの作成

以下のようにS3バケットを作成し、配下に上記のスクリプト格納用フォルダ(script)と、ついでにログ格納用のフォルダ(log)も作成します。

s3_01

そして、上記のスクリプトをscriptフォルダにアップロードしておきます。

s3_02

SNSトピックの作成

上記のスクリプトの中で、結果通知用にSNSを送信しているので、そのためのSNSトピックを作成します。ちなみに、今回はData Pipelineでの通知設定は省略しています。

sns_01

Data Pipelineセットアップ

では、さっそくData Pipelineの設定に入ります。

Create new pipeline

Data Pipelineのマネージメントコンソールを開き、[Create new pipeline]をクリックします。 以下の画面で、とりあえず赤枠の部分を設定しています。この後の画面で構成を設定するので、「Source」は「Build using Architect」を選択し、ログも事前に作成したS3バケットのフォルダに出力するようにします。

datapipeline_01

datapipeline_02

Edit in Architect

次に、構成を設定します。が、今回はShellCommandActivityを1つ作成するだけです。 以下のような感じで、とりあえず最低限の項目を設定します。

datapipeline_03

Schedulesは以下の通りです。

datapipeline_04

ResourcecsはEC2を使用します。

datapipeline_05

Preconditionsとして、jqのインストールを実行します。

datapipeline_06

Othersはデフォルトのままです。

datapipeline_07

ポリシーの変更

上記のData Pipelineをアクティブにする前に、スクリプトの実行でちゃんとEC2を停止できるよう、デフォルトのポリシー(DataPipelineDefaultResourceRole)を変更します。

DataPipelineDefaultResourceRole

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:*",
                "dynamodb:*",
                "ec2:*",
                "elasticmapreduce:Describe*",
                "elasticmapreduce:ListInstance*",
                "elasticmapreduce:AddJobFlowSteps",
                "rds:Describe*",
                "datapipeline:*",
                "cloudwatch:*",
                "redshift:DescribeClusters",
                "redshift:DescribeClusterSecurityGroups",
                "sdb:*",
                "sns:*",
                "sqs:*"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

動作確認

最後に、動作確認をしてみます。動作確認のために、以下のようテストインスタンスを3つ立ち上げます。

ec2_01

  • Test Server Stg ... Production=False
  • Test Server Prod ... Production=True
  • Test Server Dev ... Productionタグなし

作成したData Pipelineをアクティブにすると、まず実行環境となるEC2が立ち上がります。

datapipeline_08

ec2_02

そして、指定した時間になると、実行環境のEC2上でスクリプトが実行され、「Production=True」のタグがついていないEC2インスタンスが停止されます。

ec2_03

役目を終えた実行環境のEC2は、実行後に削除されます。

ec2_04

Data Pipelineの実行結果は以下の通りです。

datapipeline_09

ちゃんと結果通知メールも届いています。

email_01

さいごに

いかがでしょうか?Data Pipelineに少しでも興味を持って頂けたなら光栄です。

では、なぜLambdaフィーバー時にData Pipelineかと言えば、その理由は以下のスライドをご覧ください。 読み終えた時には、きっとData Pipelineを試してみたくなりますよ!

[slideshare id=42220749&doc=20141126aws-blackbelt-datapipeline-public-141201095140-conversion-gate01&w=640&h=320]