AWS Fargate BlueGreenDeployment

はじめに

AWS FargateはContainerインスタンスの管理をAWSにお任せすることができるサービスです。

現状、ECS(LaunchType EC2)を使っているのですが、JenkinsからECSにBlueGreenDeployするときにecs-deployを使っています。
ecs-deployはaws cliとjqには依存していますがshellだけで書かれてるので持ち運びが便利なんですね。

ecs-deployはFargateに対応していないので対応させてみました。

https://github.com/uzresk/ecs-deploy.git

使い方

1. aws cliはFargateに対応しているバージョンをお使いください。

ちなみに私の環境はこちら

aws-cli/1.14.7 Python/2.7.12 Linux/4.9.62-21.56.amzn1.x86_64 botocore/1.8.11

2. コマンドはecs-deployと全く同じです

./ecs-deploy -c [cluster-name] -n [service-name] -i [registry-url]:[tag] -t 300 -r us-east-1

デフォルトのタイムアウトは90秒なのですが、終わらないことが何回かあったので少し長めにしておくのがおススメです。

実行結果

Using image name: xxxx.dkr.ecr.ap-northeast-1.amazonaws.com/xxxx:0.0.1-SNAPSHOT
Current task definition: arn:aws:ecs:us-east-1:xxxx:task-definition/xxxx:25
Current requires compatibilities FARGATE
New task definition: arn:aws:ecs:us-east-1:xxxx:task-definition/xxxx:26
Service updated successfully, new task definition running.
Waiting for service deployment to complete...
Service deployment successful.

変更点

Fargateが追加されたことによりrequiresCompatibilitiesの指定を引き継ぐようにしたのと、
cpu, memoryの設定も合わせて引き継ぐようにしました。
LaunchTypeがEC2の場合はcpu,memoryは設定されません。

[root@ip-10-0-0-100 ecs-deploy]# git diff
diff --git a/ecs-deploy b/ecs-deploy
index 637e793..8ad1cb1 100755
--- a/ecs-deploy
+++ b/ecs-deploy
@@ -261,11 +261,17 @@ function createNewTaskDefJson() {
     fi

     # Default JQ filter for new task definition
-    NEW_DEF_JQ_FILTER="family: .family, volumes: .volumes, containerDefinitions: .containerDefinitions"
+    NEW_DEF_JQ_FILTER="family: .family, volumes: .volumes, containerDefinitions: .containerDefinitions, requiresCompatibilities: .requiresCompatibilities"

     # Some options in task definition should only be included in new definition if present in
     # current definition. If found in current definition, append to JQ filter.
-    CONDITIONAL_OPTIONS=(networkMode taskRoleArn placementConstraints)
+    LAUNCH_TYPE=$(echo "$TASK_DEFINITION" | jq -r '.taskDefinition.requiresCompatibilities[0]')
+    echo "Current requires compatibilities $LAUNCH_TYPE"
+    if [ $LAUNCH_TYPE == FARGATE ]; then
+      CONDITIONAL_OPTIONS=(networkMode taskRoleArn executionRoleArn placementConstraints memory cpu)
+    else
+      CONDITIONAL_OPTIONS=(networkMode taskRoleArn executionRoleArn placementConstraints)
+    fi
     for i in "${CONDITIONAL_OPTIONS[@]}"; do
       re=".*${i}.*"
       if [[ "$DEF" =~ $re ]]; then

おわりに

もう少し動作確認したらプルリクエスト送ろうと思いますが、だいぶメンテされていないようなので多分マージされない気がします。。。

続きを読む

既存のDynamoDBのテーブルをjsonフォーマットに変換するワンライナー

はじめに

  • AWS cliでテーブル作っていたのですが、jsonで作っておくべきだった・・・。と大変後悔しました。
  • 既存のDynamoDBのテーブルからjsonを出力するスクリプトの記事を見つけたのですが、GlobalSecondaryIndex、LocalSecondaryIndexが無いテーブルの場合はエラーになってしまいますので少し改良したのでご紹介します。
  • このスクリプトをうまく利用することでテーブルの差分をみるのに使えたりするのでオススメです。

スクリプト

  • ここではDynamoDBLocalにあるAssetというテーブルをAsset.jsonというファイルに出力しています。
  • describe-tableでは余計なものがいっぱいついてくるので要素を削除しています。
aws dynamodb describe-table --table-name Asset --endpoint-url http://localhost:8000 |
jq '.Table' |
jq 'del(.TableArn)' |
jq 'del(.GlobalSecondaryIndexes[]?.ItemCount)' |
jq 'del(.GlobalSecondaryIndexes[]?.IndexStatus)' |
jq 'del(.GlobalSecondaryIndexes[]?.IndexArn)' |
jq 'del(.GlobalSecondaryIndexes[]?.IndexSizeBytes)' |
jq 'del(.GlobalSecondaryIndexes[]?.ProvisionedThroughput.NumberOfDecreasesToday)' |
jq 'del(.GlobalSecondaryIndexes[]?.ProvisionedThroughput.LastIncreaseDateTime)' |
jq 'del(.GlobalSecondaryIndexes[]?.ProvisionedThroughput.LastDecreaseDateTime)' |
jq 'del(.LocalSecondaryIndexes[]?.IndexStatus)' |
jq 'del(.LocalSecondaryIndexes[]?.IndexArn)' |
jq 'del(.LocalSecondaryIndexes[]?.ItemCount)' |
jq 'del(.LocalSecondaryIndexes[]?.IndexSizeBytes)' |
jq 'del(.LocalSecondaryIndexes[]?.ProvisionedThroughput.NumberOfDecreasesToday)' |
jq 'del(.LocalSecondaryIndexes[]?.ProvisionedThroughput.LastIncreaseDateTime)' |
jq 'del(.LocalSecondaryIndexes[]?.ProvisionedThroughput.LastDecreaseDateTime)' |
jq 'del(.ProvisionedThroughput.NumberOfDecreasesToday)' |
jq 'del(.ProvisionedThroughput.LastIncreaseDateTime)' |
jq 'del(.ProvisionedThroughput.LastDecreaseDateTime)' |
jq 'del(.TableSizeBytes)' |
jq 'del(.TableStatus)' |
jq 'del(.ItemCount)' |
jq 'del(.IndexArn)' |
jq 'del(.CreationDateTime)' > Asset.json

出力されたスクリプトを利用してcreate-tableする

aws dynamodb create-table --endpoint-url http://localhost:8000 --table-name Asset --cli-input-json file://Asset.json

続きを読む

AmazonAlexaのサンプルを動かしながら、じっくりと基本を学んでみよう

はじめに

Amazon Alexaってご存知でしょうか。
残念ながら現在は日本語には対応していませんが、EchoやTapなどのデバイスに喋りかけると、あらかじめ紐付けておいたスキルに応じて色々な処理を動かすことができます。

  • 「今日の東京の天気はどんな感じ?」
  • 「明日の東京は晴れですよ!」

というステートレスでオープンな簡単な応答もできますし、Alexaとの会話を通じて難しい応答を返すことも作りこみ次第では可能です。

  • 私「旅行に行きたいなぁ」
  • Alexa「どこに行きたいですか?」
  • 私「アジアがいいなぁ」
  • Alexa「アジアのどの辺ですか?」

みたいなやり取りから旅行プランをおすすめしてくれて、チケットを予約してくれる日も近そうです。

この「スキル」は自分で作って公開することもできますし、公開しないでクローズドに動かすこともできます。
今回は入門編ということでAlexaのサンプルを動かしながら、Alexaで出てくる用語や、少しソースの解説をしてみます。

私は少し遠回りしましたが1時間もあれば試すことができます。
サンプルをひとつ動かすだけで、「あれ。ちょっとしたことなら簡単にできるかも。」と思えてしまいますので是非お試しください。


Alexaを構成する登場人物たちを抑えよう

ドキュメントを読むにも登場人物を抑えないとはじまりません。

  • デバイス

    • Echo / Tap / dot / KindleFireTV / Amazonアプリなど色々ありますが、Echoなどは日本では技適が通ってませんのでAmazon.comで購入しても動かしてはいけません。
    • 今のところはiPhoneアプリや公式のシミュレータであるEchosimを使いましょう。
  • Alexa App

    • Alexaのスキルの検索、登録 / カードの表示 / 追加したスキルの設定ができます。
    • PCからでもスキルの追加・変更が可能。http://alexa.amazon.com/spa/index.html
    • アプリを入手するにはアメリカのAppleIDが必要で、ログインにはAmazon.comのアカウントが必要です。
  • Alexa Service

    • デバイスからのデータを受け取り、Lambdaイベントを発火するサービス
  • AWS Lambda

    • Alexa Serviceからデータを受け取り、解析して処理を行いレスポンスを返却します。
  • Amazon Developer Console

    • カスタムスキルを作る場合はDeveloper Consoleで追加しテストなどを行います。ログインにはAmazon.comのアカウントが必要です。
    • スキルの登録には審査が必要で、7日くらいかかるらしいです。
  • AVS(Alexa Voice Service)

    • 自分で作ったデバイスに組み込むことができるSDK。今回は直接関係ありません。

サンプルを動かしてみよう

  • HelloWorldのようなステートレスなものではつまらないので、SessionというAmazonが提供しているサンプルを動かしてみます。
  • このサンプルは自分の好きな色をAlexaに教えるとAlexaが記憶してくれて、「私の好きな色は何?」と聞くと先ほど記憶してくれた色を答えてくれるサンプルです。

環境を用意する

  • Java8とMavenをインストールしましょう(mvnwくらいサンプルに置いといてくれたらいいのに。。)

LambdaFunctionを作る

  • Githubからサンプルをダウンロードする
git clone https://github.com/amzn/alexa-skills-kit-java.git
  • パッケージングする
cd alexa-skills-kit-java/samples
mvn assembly:assembly -DdescriptorId=jar-with-dependencies package
  • target/alexa-skills-kit-1.3.0-jar-with-dependencies.jarができていることを確認する

  • ManagementConsole – Lambdaを開く。この時リージョンは必ず「バージニア北部」であることを確認する

  • LambdaFunctionをデプロイする(難しくないので割愛)

    • トリガーには「Alexa Skills Kit」を選択
    • Java8
    • Handler:session.SessionSpeechletRequestStreamHandler
    • Roleは初回の場合は「テンプレートから新しいRolwを作成」を選択し、適当な名前付けておきます。
  • デプロイが成功したら後で必要となるARNをコピーしておきましょう。

image

  • LambdaFunctionのテストをしたいところですが、DeveloperConsoleから行うのがおススメですのでここからは行いません。

Developer Console

  • [Alexa Skills Kit] – [Get Started]を選択
  • [Add New Skill]を選択し、SkillInformationにこんな感じで登録する

image

  • Interaction Modelに「IntentSchema」「CustomSlotType」「Sample Utterances」を登録する

    • Githubのサンプル内に入っているのでコピペしよう
  • Configuration
    • Endpointsは「AWS Lambda ARN (Amazon Resource Name)」を選択
    • North Americaを選択し、先ほどコピーしたARNを入力します。
  • Test
    • ここではLambdaFunctionのテストができます。
    • ためしに「alexa, open session」と入力してみましょう。
    • うまくレスポンスが返ってくればLambdaResponseにjsonが返却されるはずです。
    • 右下のListenというボタンを押すと実際にechoなどのデバイスから聞こえてくる音声が聞こえてくるはずです。

image

さぁここまでできればデバイスから呼べる準備が完了です。
なお、更改するには審査にパスする必要があり、DeveloperConsoleの内容を全部埋める必要があります。

スキルを追加する

  • スキルを追加するにはAlexaのポータルか、AlexaAppを利用して登録します。
  • 画面左の「Skills」をクリックし、画面右上の「YourSkill」を選択すると先ほどDeveloperConsoleで作成したSkillが表示されるはずです。

image

デバイスを用意する

  • 開発中はechosim.ioを利用すると良いでしょう。
  • Amazonアカウントでログインすることで使用できます。
  • 本物のデバイスでは「Alexa」と呼びかけるのですが、Echosimはボタンを押すことで「Alexa」と呼んだことと同じ意味になります。

image

  • ちなみに私だけかもしれませんがEchosimはMacだと快調に動くのですが、Windows10だとなぜか認識しないことがありました。また、スマホアプリでAVSで作られた無料のものがありますが、これもうまくいったりいかなかったりしました。
  • 色々試した結果、良い感じだったのはAmazonモバイルアプリでした。これのロケールをアメリカにすると音声検索でAlexaが利用できますよ。

しゃべってみましょう

こんな感じのやりとりができますのでやってみましょう。

  • 私「Alexa,open session」(Echo使っていない場合はAlexaは不要です)
  • Alexa「Hello. Welcome to the Alexa Skills Kit sample. Please tell me your favorite color by saying, my favorite color is blue」
  • 私「my color is red」
  • Alexa「I now know that your favorite color is red. You can ask me your favorite color by saying, what’s my favorite color?」
  • 私「whats my color」
  • Alexa「Your favorite color is red」

Alexa用語を覚えておこう

  • そんなに多くないので覚えるのはそんなに大変じゃありません。

Invocation Name

  • Developer Consoleで設定するSkillを特定する一意な名前。
  • Invocation Nameをsessionという名前にしておくと、「Alexa, tell session」でSkillを呼び出すことができます。
  • tell / ask / openなどのあとにInvocationNameを話すとLambdaFunction#onLaunchが呼ばれます
  • 今回のサンプルでは#getWelcomeResponseが呼ばれ、「Hello. Welcome to the Alexa Skills Kit sample. Please tell me your favorite color by saying, my favorite color is blue」を喋らせています。

Intent Schema

  • 説明が難しいですが、Alexaとのやりとりの枠組みを定義します。(そのままじゃん・・・)
  • やり取りの中でSlotを使う場合は合わせてそれを定義します。
  • 今回の場合はMyColorIsIntentとWhatsMyColorIntentというIntentが使われ、MyColorIsIntentではLIST_OF_COLORSというカスタムSlotが利用されることを示しています。このIntentで会話される内容はUtteranceに定義します。
{
  "intents": [
    {
      "slots": [
        {
          "name": "Color",
          "type": "LIST_OF_COLORS"
        }
      ],
      "intent": "MyColorIsIntent"
    },
    {
      "intent": "WhatsMyColorIntent"
    }
  ]
}

Utterance

  • 日本語では「発声」です。IntentとAlexaが認識できる文章を紐付ける役目を持ちます。
MyColorIsIntent  my color is {Color}
MyColorIsIntent  my favorite color is {Color}
WhatsMyColorIntent whats my color
WhatsMyColorIntent what is my color
WhatsMyColorIntent say my color
WhatsMyColorIntent tell me my color
WhatsMyColorIntent whats my favorite color
WhatsMyColorIntent what is my favorite color
WhatsMyColorIntent say my favorite color
WhatsMyColorIntent tell me my favorite color
WhatsMyColorIntent tell me what my favorite color is
  • 「whats my color」と発音するとIntentRequestのintentNameにWhatsMyColorIntentが入りますので、以下のコードのように分岐することでintentに対応する応答を実現することができます。
  • ここでは対応するintentが無い場合は例外を発声させていますが、「再度言ってください」みたいな流れにしてもよさそうですね
        if ("MyColorIsIntent".equals(intentName)) {
            return setColorInSession(intent, session);
        } else if ("WhatsMyColorIntent".equals(intentName)) {
            return getColorFromSession(intent, session);
        } else {
            throw new SpeechletException("Invalid Intent");
        }
  • {Color}というのはSlotを表します。Intent SchemaのNameに対応しており、slotの型はDeveloperConsoleで設定が必要です。

Slot

  • LIST_OF_COLORSに以下のように定義するとUtteranceで{Color}となっている部分が取り得る値を定義することができます。
green
blue
purple
red
orange
yellow

Buildin Intent/Slots

SSML(Speech Synthesis Markup Language)

  • 読み方とかしゃべる間隔などをマークアップで記載することができます。(TwilioのTwiMLとは違うマークアップのようです)
  • 強く読んだり、アルファベットを読み上げたりS3に挙げたmp3を再生することも可能です。
  • マークアップの書き方はSpeech Synthesis Markup Language (SSML) Referenceをどうぞ。
  • 例えば、リストを読み上げるときに一定の間隔をあける場合は以下のように書くことができます。
        String repromptText = "Please choose a category by saying, " +
                "books <break time="0.2s" /> " +
                "fashion <break time="0.2s" /> " +
                "movie <break time="0.2s" /> " +
                "kitchen";
  • どんな感じでしゃべるのかな~というのはDeveloperConsoleのVoiceSimulatorで試すことができます。結構遊べます。

image

Cards

  • 「Alexa, open session」なんて話した後に、スマホのAlexaAppを開いてみます。
  • そうするとやりとりした内容が表示されていると思います。これをCardと言います。

alexaapp.jpg

  • Cardに表示させるにはこんな感じで書くことで表示されます。
        SimpleCard card = new SimpleCard();
        card.setTitle("Session");
        card.setContent("表示したいコンテンツ");
  • Cardは3種類あって、テキストのみ表示する場合はSimple、画像などのイメージを使って表示したい場合はStandard、既存サイトのアカウントとリンクするときのみ使えるのがLinkAccountとなっています。
  • さらに詳しく理解したい場合はIncluding a Card in Your Skill’s Responseを読みましょう。

その他

他は一旦紹介だけしておきます。

Link Account

  • OAuth2.0(RFC6749RFC6750)を使ってアカウントをリンクすることができます。
  • 簡単に流れを説明するとこんな感じです。
    • AlexaAppなどでスキルをEnableにする
    • LinkAccountをクリックすることで認証させたいサイトのログイン画面が開く
    • ユーザがアプリの画面などでID/PWを入力する。
    • 認証をクリアしscopeを承諾すると、AccessTokenが保管される。
    • ここまでがリンクの仕組みで以降のやりとりは音声と一緒にAccessTokenが流れてくるのでこれをLambdaで取得後、認可&リソースにアクセスすることで実現します。
  • 「Authorization code grant」と「Implicit grant」に対応しています。どちらの方式にするか検討が必要ですが、通常はよりセキュアな「Authorization code grant」を選択します。
  • 「Authorization code grant」はcodeを取得し、client_id,secretを使ってAccessTokenを取得する仕組みとなります。client_id,secretの値はあらかじめDeveloperConsoleで登録しておく必要があります。
  • また、tokenの有効期限切れの場合の為にrefresh_tokenの仕組みがOAuthには定義されていますが、こちらはAlexaのドキュメントによればOptionalとなっているので利用するか、tokenの有効期限が切れたら再認証させるかについては決めておく必要があります。
  • Linking an Alexa User with a User in Your System

Alexa BestPractice


おわりに

どうでしたか?結構簡単に作れることがわかると思います。
英語でもかなり色々遊べますので触ってみてはどうでしょうか。

次回はいつになるかわかりませんが、LinkAccountについて書こうかと思います。

続きを読む

モニタリングサービス(Mackerel、Datadog、New Relic)入門!

はじめに

  • モニタリングサービスMackerelDataDogNewRelicについて簡単にまとめてみました。
  • サーバのリソース監視、ログ、プロセス監視ができれば良かったので、今回はAWSインテグレーション機能などについてはあっさりとしか触れてません。
  • どのサービスも、監視対象のサーバーを用意した状態で、15分あれば無料でサーバのリソースがモニタリングできるところまでいけます(そしてクレジットカードなどの登録は不要)ので、是非はじめてみてはどうでしょうか。

サービスの紹介

Mackerel(マカレル)

  • 「株式会社はてな」が提供しているサーバ管理・監視ツール
  • 監視/メトリクス

    • デフォルトで様々なメトリクスが取得されており、閾値を設定して監視することができる。(CPU,Network,Disk,Memory)
    • プロセスやログ監視などはサーバー上の設定ファイルに設定を追加することでとても簡単に実現できる。
    • プラグインを利用することでかなりの種類のミドルウェアのメトリクス可視化が可能
  • 通知

    • Email、Slack、HipChat、ChatWork、Lineなど幅広い通知先に対応
  • 料金

    • Standardで1ホスト1800円
  • Freeアカウント

    • Trialは14日でStandard相当の機能が利用可能。制約はあるが無料でも使い続けられる。
  • 気になった機能

    • http/httpsの外形監視が可能
    • AWSインテグレーション機能

      • MackerelのホストとしてAWSのサービスを登録できる。
      • 現在の対応サービスはEC2、ELB (CLB)、ALB、RDS、ElastiCache・Redshift。EC2だけではなくマネージドなサービスを監視できる。
  • 雑感

    • 日本語であることを差し引いてもマニュアルが親切で、試しているときに3つの中で一番躓かなかった
    • 設定がとてもシンプルでわかり易い(ログ監視、プロセス監視もDatadogみたいにpythonのスクリプト書かなくてもよい。)
    • 外形監視はMackerelしかない機能。
    • AWSインテグレーションは今日現在対応サービスがそんなにあるわけではないので、不足分はCloudWatchで補っていくのかな。

Datadog

  • Datadogが提供しているリソース管理・監視サービス
  • 監視/メトリクス

    • デフォルトで様々なメトリクスが取得されており、閾値などで監視が可能(CPU,Network,Disk,Memory)
    • プロセスの監視についてはサーバー上の設定ファイルに設定を追加し、実現する。
    • ログの監視は標準のログのフォーマット以外はカスタムのログのパーサをpythonで記載する必要がある。(後述)
    • HTTPの監視については外部からの監視ではなく、あくまでAgentからの監視のよう。
  • 通知

    • Email、HipChat、Pagerduty(インシデントとして登録)
    • 本文はカスタマイズ可能。日本語も使えました。
  • 料金

  • Freeアカウント

    • 14日間特に制限なしで利用可能(クレジットカードの登録不要)
  • 気になった機能

  • 雑感

    • マニュアルが揃っており、始めやすくUIも直観的。
    • インテグレーション機能が強烈
    • 異常値の検出機能など高度なモニタリングができ、今後の機能拡張も期待できそう
    • 日本語の情報源も多く、利用しているユーザも多そう。マニュアルも全部ではありませんが日本語で提供されている。

NewRelic Infrastructure

  • NewRelicが提供するモニタリングサービス

  • 監視/メトリクス

    • デフォルトで様々なメトリクスが取得されており、閾値で監視が可能(CPU,Network,Disk,Memory)
    • プロセスの監視もUIからできる。ログの監視についてはやり方が見つけられなかった。
  • プラン・料金

    • 30日間のFreeアカウントプランとEssential,Proという3つの体系
    • EssentialとProの違いはデータの保持期間(3日と13日)とEC2以外のモニタリングができるか否かのようです。
    • こちらのページを見て計算してみたのですが、インスタンスタイプや年払い、月払いで料金が異なるようです。
  • Freeアカウント

    • 14日間特に制限なしで利用可能(クレジットカードの登録不要)
  • 雑感

    • 製品ラインナップが多くて調べ始めたら混乱した。
    • Infrastructure単体で使うというよりAPMとセットで使うイメージがしっくりくる。サーバの監視はMackerelやDatadog、アプリケーションの監視としてピンポイントでAPMを導入するという形になる気がする。
    • Qiitaやブログの記事がDatadog,Mackerelと比べると少ない。販売代理店のページで翻訳されているマニュアルがある。

ためしてみる

Mackerel(マカレル)

セットアップ

  • ホストへのagentのインストールはすごく簡単

    • スタートガイドにURLがあるのでコピペします。
    • rpm,tar.gz,windows installerとか色々対応してます。
curl -fsSL https://mackerel.io/file/script/amznlinux/setup-all-yum.sh | MACKEREL_APIKEY='xxxxxxxxxxxxxxxxx' sh
  • 数秒後にホストの一覧を見てみると・・・

image

  • サービスとロールを設定してみる

    • サービスとは○○システムという単位
    • ロールというのはWEBサーバ、DBサーバというホストの役割を表すもの。
    • 今回はオンプレとAWSのホストをdemo-appというロールでまとめてみました。
  • CPU、メモリの状況などがロール単位にまとめてみることができます。

image

ログ監視

  • 今回の目的であるログ監視をやってみます。
  • ログ監視は公式サイトによるとプラグインを入れて設定するもののようです。

  • プラグインをインストールします

yum -y install mackerel-check-plugins
  • 設定を追加します
/etc/mackerel-agent/mackerel-agent.conf
[plugin.checks.test_log]
command = "check-log --file /home/ec2-user/test.log --pattern FATAL --return"
  • 設定を反映するためにエージェントを再起動します。
[root@ip-10-0-0-24 ec2-user]# service mackerel-agent restart
Stopping mackerel-agent:                                   [  OK  ]
Starting mackerel-agent:                                   [  OK  ]
[root@ip-10-0-0-24 ec2-user]#
  • FATALというメッセージを出してみましょう
echo "FATAL:message" >> /home/ec2-user/test.log
  • 正しく検知できました!(Alertは自動でCloseされるようです)

image

  • メモとか残せるのは気が利いていていいですね

image

プロセス監視

  • ログ監視と同じ感じで正規表現でプロセス名を指定します。
/etc/mackerel-agent/mackerel-agent.conf
[plugin.checks.check_demo_app]
command = "check-procs --pattern java8"
  • ちょっと待つとホストの表示画面の右側に現れます。

image

  • プロセスを切ってみると・・・ちゃんと検知します

image

  • プロセスを上げると自動でCloseされます

image

外形監視

  • warning,criticalにするレスポンスタイムや、アラートが発生している期間に一定の時間間隔で通知を再送する設定などかなり気が利いてる印象

image

  • 設定した内容は一覧で見ることができます。

image

  • サイトを停止して、ちょっと待つとアラートに引っかかります。復旧後自動でCloseされます。

image

Datadog

セットアップ

  • すごく簡単
  • Distributionとかツールを選ぶとスクリプトがでてくるのでコピペするだけです。

image

DD_API_KEY=xxxxxxxxxxxxxxxxxx bash -c "$(curl -L https://raw.githubusercontent.com/DataDog/dd-agent/master/packaging/datadog-agent/source/install_agent.sh)"
  • シンプルなホストの一覧。タグがつけられるのはどこも一緒

    • デフォルトのタイムゾーンをみて時間を表示してくれます。意外と嬉しい。

image

  • ホストを選択するとメトリクスをみれます

image

  • Metrics Explorerを使うとタグをつけたhostのメトリクスをまとめて見れたりします。ここはすごく柔軟でいいですね

image

プロセス監視

  • サンプルがあるのでコピーして使います
cp /etc/dd-agent/conf.d/process.yaml.example /etc/dd-agent/conf.d/process.yaml
  • sshとjavaのプロセスを監視してみます
/etc/dd-agent/conf.d/process.yaml
init_config:

instances:
- name: ssh
  search_string: ['ssh', 'sshd']

- name: demo-app
  search_string: ['java']
  • agentを再起動します
[root@ip-10-0-0-24 ec2-user]# service datadog-agent restart
Stopping Datadog Agent (using killproc on supervisord):    [  OK  ]
Starting Datadog Agent (using supervisord):                [  OK  ]
[root@ip-10-0-0-24 ec2-user]#
  • 以下のコマンドで取得できていることを確認します。
[root@ip-10-0-0-24 conf.d]# service datadog-agent info
====================
Collector (v 5.10.1)
====================
・・・・
  Checks
  ======

    process
    -------
      - instance #0 [OK]
      - instance #1 [OK]
      - Collected 12 metrics, 0 events & 2 service checks
  • Monitors -> Processを選択して監視を追加しましょう

    • メール通知するタイトルやメッセージは自由に変えられますし、日本語でも問題なく送信できました。

image

  • Javaのプロセスが死ぬとメールが飛んできて、画面もこんな感じになります

image

ログ監視

  • ログ監視を行うにはこちらを参照。
  • apacheのログとかアプリケーションのログのようなDatadog標準のフォーマットではないものについてはpythonでparseしてから送信する必要があるとのこと。
  • まずはこんなログをparseしてみます。
127.0.0.1 - - [31/Jan/2017:00:57:59 +0000] ERROR hogehogehoge
127.0.0.1 - - [31/Jan/2017:00:58:00 +0000] SUCCESS hogehogehoge
  • parserをpythonで書いて用意します。(見様見真似で書いたのでイケてるのかがわかりません)
/opt/datadog-agent/agent/checks/libs/test_log_parser.py
from time import strftime
import re
import time

def test_log_parser(log, line):

    regex = '([(\d\.)]+) - - \[(.*?)\] (.*?) (.*?)'
    parsed = list(re.match(regex, line).groups())

    event = {}
    event["aggregation_key"]  = "test.log-monitor"
    event["timestamp"] = int(time.time())
    event["msg_title"] = "Test log monitor / Log Level: " + parsed[2]
    event["msg_text"] = "message: " + parsed[3]

    if re.match('^ERROR$', parsed[2]):
        event["alert_type"] = "ERROR"
        event["event_type"] = "event.error"
    else:
        event["alert_type"] = "INFO"
        event["event_type"] = "event.info"

    return [event]
  • Datadogの設定に食べさせて、agentを再起動します。
/etc/dd-agent/datadog.conf
dogstreams: /var/log/test.log:/opt/datadog-agent/agent/checks/libs/test_log_parser.py:test_log_parser
[root@ip-10-0-0-24 libs]# service datadog-agent restart
Stopping Datadog Agent (using killproc on supervisord):    [  OK  ]
Starting Datadog Agent (using supervisord):                [  OK  ]
  • こんなログが出てればOK
/var/log/datadog/collector.log
2017-01-31 01:46:32 UTC | INFO | dd.collector | checks.collector(datadog.py:143) | Instantiating function-based dogstream
2017-01-31 01:46:32 UTC | INFO | dd.collector | checks.collector(datadog.py:150) | dogstream: parsing /var/log/test.log with <function test_log_parser at 0x7f7bb5bcc410> (requested /opt/datadog-agent/agent/checks/libs/test_log_parser.py:test_log_parser)
  • ログを流してあげるとEventのページに表示されます
echo "127.0.0.1 - - [31/Jan/2017:00:58:05 +0000] SUCCESS hogehogehoge5" >> /var/log/test.log
echo "127.0.0.1 - - [31/Jan/2017:00:57:59 +0000] ERROR hogehogehoge" >> /var/log/test.log

image

  • NewMonitor -> Eventから監視を設定します

画面上部にイベントが表示されていて、Select events to countの値を変更するとフィルタされた値が表示されています。

image

  • ERRORの時にちゃんとアラートが飛びました。

image


NewRelic Infrastructure

セットアップ

  • DataDog,Macherelと違って少しだけ手順を踏みます。

    • アクセスキーの登録
    • yumリポジトリの設定
    • yumでのインストール
  • 少し待って画面上部の「INFRASTRUCTURE」をクリックするとモニター画面が現れます。
    • タイムゾーンはデフォルトタイムゾーンで表示してくれます。残念ながらAlertsは対応がまだのようでUTC or PSTの表示になります。

image

  • Alertの設定

image

APM(蛇足)

ついでにAPMも試してみようと思ったのですが、今回使っているJavaのアプリケーションはSpringBootで作っておりますが、ApplicationServerのルートディレクトリがないものには対応していないようでした。残念。

公式ドキュメントを参考にすればイメージがつくかと思います。

続きを読む

AWS ECSでDockerコンテナ管理入門(基本的な使い方、Blue/Green Deployment、AutoScalingなどいろいろ試してみた)

はじめに

Dockerを本番環境で利用するに当たり、私レベルではDockerのクラスタを管理することはなかなか難しい訳です。凄くめんどくさそうだし。
ということでAWS ECS(EC2 Container Service)ですよ。

記事書くまでも無いかなと思ったんですけど意外と手順がWEBにない(気がしました)。ということで、今回は社内でハンズオンでもやろうかと思って細かく書いてみました。

こんな感じのシナリオをやってみたいと思います。

  1. Dockerのイメージを用意する
  2. ECSの使い方の基本
  3. コンテナのリリース
  4. Blue/Green Deployment
  5. AutoScaling/ScaleIn

前準備:Dockerのイメージを用意する

FROM uzresk/docker-oracle-jdk
MAINTAINER uzresk

ADD demo-1.0.jar /root/demo-1.0.jar
CMD java -jar /root/demo-1.0.jar
  • Docker build
[root@centos7 build_demo_ver1.0]# docker build -t uzresk/demo:ver1.0 /vagrant/build_demo_ver1.0
Sending build context to Docker daemon 33.11 MB
Step 1 : FROM uzresk/docker-oracle-jdk
 ---> df2f575c2a0d
Step 2 : MAINTAINER uzresk
 ---> Using cache
 ---> 1995a4e99748
Step 3 : ADD demo-1.0.jar /root/demo-1.0.jar
 ---> 705df0209779
Removing intermediate container cd9ef33d8812
Step 4 : CMD java -jar /root/demo-1.0.jar
 ---> Running in b7bd939a8b5a
 ---> add0783a851f
Removing intermediate container b7bd939a8b5a
Successfully built add0783a851f
  • 起動します

    • アプリケーションは8080で起動しているのでポートフォワードしておきます。
[root@centos7 build_demo_ver1.0]# docker run -itd -p 80:8080 --name demo uzresk/demo:ver1.0
92bda2419bf7285d78f12be5877ae3242b5b13ac14409b3c47d38e2d74a06464
  • ブラウザでこんな画面がでれば成功です。

image

  • Dockerhubにコミットしてpushしておきます。
[root@centos7 build_demo_ver1.0]# docker commit -m "update ver1.0" demo uzresk/demo:ver1.0
[root@centos7 build_demo_ver1.0]# docker push uzresk/demo:ver1.0

ECSの使い方の基本

AWS ECSとはなんなのか?

  • 今回は利用手順について書こうと思うので割愛しますが、AWS Black Belt ECSを読むのがよろしいかと思います。

構成する順番を抑えよう

  • こんな感じの順番で構成していきます。大事なので押さえておきましょう。
  1. クラスタの作成

    • クラスタを動かすためのEC2インスタンスの設定を行います。具体的にはインスタンスタイプ、インスタンス数、VPC、サブネットの設定になります。
  2. タスク定義

    • クラスタ上で動かすコンテナの情報を登録します。コンテナイメージのURLやCPU、メモリのハード/ソフト制限、アプリケーションで利用する環境変数の定義などを行います。
  3. ロードバランサの作成

    • クラスタの上位に位置するロードバランサの設定を行います。スケールアウトやスケールインしてもロードバランサはサービスを見つけ出し配下に組み込むことができます。
  4. サービスの作成

    • クラスタとサービスを結びつけるのがサービスの役割です。タスクの最少数やAutoScalingの設定を行ったりできます。
    • 1つのクラスタに複数サービスを登録することももちろん可能です。

それではさっそくクラスタの作成からやってみましょう。

クラスタの作成

image

image

  • 正常に作成されると「クラスターの表示」ボタンが押せるようになります。

image

タスク定義

  • 次はタスクの定義です。タスクでは

image

  • タスク定義名を入力し、「コンテナの追加」をクリックします。

image

image

  • 作成を押せばタスク定義の作成が完了します。

ELBの作成

  • ELBは以下の設定で作っておきましょう

    • ELB名:app-demo-lb
    • 種類:アプリケーションロードバランサ
    • 2つのAZそれぞれのSubnetを指定
    • セキュリティグループで80/HTTPを通すように設定
  • ターゲットグループは以下のようにクラスタで設定したインスタンスIDをそれぞれ登録してください。

image

サービスの作成

  • クラスターのTOPからdemo-clusterを選択し、サービスタブで「作成」

image

  • タスク定義とクラスタ名は自動で埋まりますので、サービス名とタスクの数を設定します。
  • 今回はAZにそれぞれコンテナを作りたいので2としました。

image

  • 画面の下の方にあるELBの追加を選択します。

image

  • ELB名は作成したもの、リスナーポートは80、ターゲットグループ名は作成したものを選択します。

image

image

  • 「作成」を押して、サービスの画面をみるとPENDINGになっています。

image

  • 少し経つとRUNNINGになっている事が確認できると思います。

image

  • ELBのエンドポイント/app/をブラウザで叩くと画面が表示されるはずです。

image

コンテナを落としてみるとどうなるのか

  • タスクの一覧から、タスクを一つ消してみましょう。

image

  • 数十秒後に見てみると別のタスクIDのインスタンスが表示されているはずです。

image

  • コンテナが起動する数十秒間の間はアプリケーションロードバランサが生きているタスクの方にうまくルーティングしてくれるのかな?と思ったら「502BadGateway」というエラーが画面に返ってきました。
  • ここはALBのヘルスチェックの閾値を短くすることである程度は短くできそうです。
  • ここをさらに短くするには、コンテナ自体を軽くすることと、すぐに起動できるアプリケーションを利用するしかなさそうですね。

コンテナのリリース

  • 新しいコンテナをリリースするには、タスク定義に新しいリビジョンを登録し、サービスを更新することで実現可能です。さっそくやってみましょう。

image

  • コンテナのバージョンを2.0にして、新しいリビジョンを登録します。

image

  • 追加されたリビジョンを選択し、アクション→サービスの更新を押します。

image

  • タスク定義に新しいリビジョンが指定されていることを確認して、「サービスの更新」

image

  • サービスの「デプロイ」タブを覗くと、今はVer1.0が2つ動いていることが確認できます。

image

  • コンテナを一つ落としてみましょう

image

image

  • 実行中の数がそれぞれ1になり、タスクの一覧からもそれぞれが動いていることがわかりますね。
    image

image


Blue/Green Deployment

  • Blue/GreenDeploymentでは新しいリビジョンのアプリ用に、新しいインスタンスを構築して入れ替える必要があります。
  • この為のパラメータがサービスのデプロイメントオプションにある最大率(maximumPercent)です。2台の時にこの値を200%にしておくと、4台まで同時に動かしておくことができることを意味します。
  • 4台のインスタンス上で動かすにはECSのインスタンス台数を事前に追加しておくか、AutoScalingさせておく必要があります。もしECSインスタンスが2台の状態で4つのコンテナを動かそうとすると以下のようなメッセージがでてしまいます。(ポートかぶってるから上がらないよ。ってことですね)

  • さっそくやってみます

service demo-service was unable to place a task because no container instance met all of its requirements. The closest matching container-instance xxxxxxxxxxxxxxxxxxxx is already using a port required by your task. For more information, see the Troubleshooting section.

image

image

  • この状態でサービスの更新画面でタスク定義を新しいリビジョンに指定して「サービスの更新」を押してみます。
  • おお。4台分のコンテナが起動しましたね。

image

  • ちょっと経つと(3分ほど?)、古いタスクから削除されていきます・・・・

image

  • 最期は新しいタスク定義しか残らなくなりました。自動ですよ。自動。便利ですねー。

image


AutoScaling/ScaleIn

  • 次はオートスケールとスケールインを試してみます。
  • 通常のオートスケールではインスタンスだけでしたが、インスタンス上で動くコンテナもスケールする必要があります。
  • 今回は2つのインスタンスで2つのコンテナで動いていたものを、負荷をかけることにより4つのインスタンス上に4つのコンテナにスケールアウトさせて、スケールインさせたいと思います。

サービスのAutoScaling設定

  • タスクの最大数を4にして、スケーリングポリシーの追加を押します。

image

  • スケールアウトポリシーの設定を行います。
  • CPU使用率の1分間の平均が20%超えた場合2タスクスケールアウトする設定にしました。

image

  • スケールインポリシーの設定を行います。

image

  • ポリシーが追加できたら「保存」を押しましょう

image

  • ポリシーが追加されていることを確認して、「サービスの更新」を押します。

image

  • これでサービスの設定はおしまいです。

ClusterのAutoScaling/ScaleInの設定

  • ECSインスタンスのオートスケールのポリシーは、EC2インスタンスのAutoScalingGroupの設定で行います。
  • 最大数を4にします。

image

  • Scaleout/ScaleInのポリシーを設定します。
  • サービスの設定と同じく、クラスタのCPU使用率が20%以上だと2台スケールアウトするように設定しました。

image

うごかしてみる

  • ECSインスタンス上でCPU使用率を強引に(openssl speed -multi 1)あげてみたのですがうまく動きませんでした。
  • ありがちですけどabで負荷をかけてみます。
  • abをインストール
sudo yum install -y httpd24-tools
  • 負荷をかける
ab -n 100000 -c 100 http://localhost/app/loginForm
  • CloudWatch Alerm(CPUが20%以上)があがる

image

  • サービスの必要数が4に変更される

image

  • インスタンスがオートスケールする

image

  • タスクが起動する

image

  • 負荷を解除する

  • CloudWatch Alerm(CPUが20%より小さい)があがる

image

  • 必要数が2に変更される

image

  • コンテナとインスタンスが2ずつに変わる

  • ここまでやって思ったんですが、インスタンス→コンテナの順に起動されたんですからコンテナ→インスタンスの順に落としていった方がよさそうですね。それはスケーリングポリシーのクールダウン時間で調整ができそうです。

ECSインスタンスの起動を待つのか?

  • ECSのインスタンスの起動を行った後にコンテナが起動されるので結局時間が掛かってしまいます。負荷の時間が予測されるのであればECSインスタンスを事前に起動しておいた方がECSのスケールアウトが高速にできそうです。
  • Dockerのメリットの一つである起動の高速化のメリットを享受するにはこのスケジューリングがキーになりそうですね。

どのインスタンスがスケールインするのか?


さいごに

ここまでコンテナ管理のハードルが下がると、今後はアプリケーションをコンテナにして配布するのが普通になってくると思います。
そうなるときのためにDockerについてしっかりと理解し、良い設計を心がけたいものですね

続きを読む

AWSでLinuxしか触ったことない人が、AWSでWindowsServerを利用するときに知っておかないといけないことまとめ

はじめに

  • AWSでLinuxばかりやってたんですがWindowsServerを触らないといけない機会が凄く増えててビビってます。
  • WindowsServer利用するときも、まぁ大体Linuxと一緒なんでしょ!?と思ってたら火傷しますのでしっかりと抑えておきましょう。
  • 他にもWindowsだと気をつけないといけない!なんてことがあればご指摘ください。

ライセンスはどうなってるのか?押さえておこう。

  • WindowsServerのライセンス

    • EC2の費用に含まれている。
    • OSにCALの料金が含まれているのでCALの購入は不要
  • WindowsServerのライセンス持ち込みについて
  • 以下の既存のマイクロソフトライセンスはAWS上に持ち込み可能。
    • 1サーバ1ライセンス、1プロセッサライセンス4コアまでの1インスタンスに対応
    • Exchange Server
    • SharePoint Server
    • SQLServer Enterpriseなど
  • Officeのライセンスについて
    • ハードウェア占有インスタンス、占有ホストで利用可能
  • その他ライセンスについて不明な点があればAWS と Microsoft に関するよくある質問 – ライセンシングを読んでおく。

サポート&トラブル

どのイメージを利用すればよいのか?

  • EC2の画面から「パブリックイメージ」「所有者:Amazonイメージ」「search:Windows_Server-2012-R2_RTM-」で検索するとたくさん出てくる。
  • 「search:Windows_Server-2012-R2_RTM-Japanese」で検索するとLocaleがJapaneseで設定済のものもあるのでこれを選んでおくと楽ですね。

EC2 Management Console 2016-10-07 14-33-05.png

  • 最新のパッチが当たったAMIを公開してくれており、10月5日現在だと6月以前のAMIは無くなっていました。どうしても元のAMIをとっておきたい場合はプライベートイメージとして保管しておく必要がありそう。(が、、、そういうケースはあるんだろうか)

AWS は、Microsoft の火曜パッチ(毎月第 2 火曜日)の 5 営業日以内に、更新されパッチが全面的に適用された Windows AMI を提供します。

  • 新しいAMIがリリースされた時や以前のAMIが非公開になった時に通知をAmazonSNSで受けることができるようです。Subscriptionの設定で以下のARNを設定すればよいようです。
arn:aws:sns:us-east-1:801119661308:ec2-windows-ami-update
arn:aws:sns:us-east-1:801119661308:ec2-windows-ami-private

インストールメディアは使えるのか?

  • 使える。
  • マネジメントコンソールでスナップショットを開いて以下の条件で検索
    • パブリックスナップショットを選択
    • 所有者:Amazonイメージ
    • 説明:Windows 2012 R2
  • あとはボリュームの作成してWindowsServerにAttachすれば利用できる

どうやってWindowsServerに接続するのか?

  • RDPで接続する。パスワードはManagementConsoleからパスワードの取得を行うことで取得できる。
  • インスタンス起動後すぐに取得できるわけではなく、「あとN分後に取得できます。」のメッセージが出てくる。
  • これは後述するEC2Configがパスワードの初期化を行っているから。

拡張ネットワーキングは有効にしておこう

インスタンスの自動復旧設定をしておこう

  • Windowsに限った話ではないが、AutoRecoveryは設定しておく。やっといて損しない。
  • AutoRecoveryはシステムステータスチェックが失敗した場合(ネットワークとか電源とかホスト側の問題でこちらではどうしようもない問題)に自動で復旧してくれる機能で無料で利用できる。
  • 利用条件
    • インスタンスタイプはC3、C4、M3、M4、R3、T2、および X1
    • VPC内で動作しEBS-Backedとなっていること
    • 占有インスタンスではないこと
  • 参考

AutoHealingの設定

  • これもWindowsに限った話ではないが1台構成でもAutoHealingの設定をしておくことを検討しておく。
  • AutoHealingとはAutoScalingGroupの起動数をmin:N,max:Nにしておくことで常にN台起動する状態を作ることを言います。
  • 詳しくは別記事にしますが簡単に触れておく。
  • AutoScalingGroupを利用する場合
    • トリガーはStateがRunningじゃなくなったとき。
    • PrivateIPが変わってしまうので上位にELBを挟むなどの考慮が必要。
    • CloudWatch→SNS→Lambda→AutoScalingGroupをUnHealthyにすることで細かい障害の検知などが可能になる。
  • OptsWorksを利用する場合
    • トリガーはOptsWorksAgentがOptsWorksに通信できなくなったとき。
    • PrivateIPを変更することなくAutoHealingが動かせるが、AutoScalingGroupのような細かい制御は無理

EC2Configの役割について知っておく

  • EC2ConfigはWindows版Cloud-initみたいなものです。EC2Configがやってくれる役割については認識しておこう。
  • AWSが提供するWindowsServerイメージを利用すると既にインストール済になっています。
    C:\Program Files\Amazon\Ec2ConfigService¥Ec2ConfigServiceSettings.exe
  • サービスも自動で起動しているので特に何かしておく必要はありません。
  • こんなことをやってくれます。
* 初回起動時のタスクには以下のものがあります。
    * 管理者アカウントに、ランダムに生成した暗号化パスワードを設定する
    * リモートデスクトップに使用されるホスト証明書を生成しインストールする
    * オペレーティングシステムパーティションを動的に拡張して、未使用の領域が含まれるようにします。
    * 指定されたユーザーデータ(および、インストールされていれば Cloud-Init)を実行します。
* EC2Config は、インスタンスが起動するたびに次のタスクを実行します。
    * 16 進数表記のプライベート IP アドレスと一致するようにコンピュータのホスト名を変更する(このタスクはデフォルトでは無効になっているので、このタスクを有効にしてインスタンスの起動時に実行する必要があります)。
    * key management server (KMS)を構成し、Windows アクティベーションのステータスを確認して、必要に応じて Windows のアクティベーションを行う。
    * すべての Amazon EBS ボリュームおよびインスタンスストアボリュームをマウントし、ボリューム名をドライブ文字にマップします。
    * イベントログエントリをコンソールに出力し、トラブルシューティングに役立てる(このタスクはデフォルトでは無効になっているので、このタスクを有効にしてインスタンスの起動時に実行する必要があります)。
    * コンソールに Windows の準備が完了した旨の通知を出力する
    * 複数の NIC がアタッチされているとき、プライマリネットワークアダプタにカスタムルートを追加して、IP アドレス 169.254.169.250、169.254.169.251、および 169.254.169.254 を有効にする。これらのアドレスは Windows ライセンス認証が使用し、またユーザーがインスタンスのメタデータにアクセスする際にも使用します。
* EC2Config は、ユーザーがログインするたびに以下のタスクを実行します。
    * デスクトップ背景に壁紙情報を表示する
  • 他の用途については以降で説明します。

AMIの作成方法は2パターンあることを知っておく

  1. マネージメントコンソールやCLIからAMIの作成を行う
  2. EC2ConfigからAMIを作成する
  • 所謂システムバックアップを取得する場合は1を利用すれば良い。
  • EC2ConfigからAMIを作成する理由は、展開用のイメージを作るときです。実行するとセキュリティ識別子(SID)、コンピュータ名、イベントログなど固有の情報が削除され、インスタンスが停止します。停止した状態でコンソールやCLIからイメージを作成すればインスタンス固有の情報が排除されたAMIの作成ができます。
  • 作成の方法についてはSysprep を使って標準の Amazon マシンイメージを作成します。を参考にしてください。

  • 参考

AWS Diagnostics for Microsoft Windows Serverは入れとけ

  • このツールを使うとWindowsServer上から様々な情報を収集し、AWSテクニカルサポートに問い合わせるときに情報を集めるのが非常に楽になるということと、既知の問題に引っかかっていないかを検査してくれるらしいです。素晴らしい。
  • いざサポートに問い合わせる必要が出た時にも慌てないようにダウンロードしておいておき、動くことも確認しておくこと!
  • 集められる情報
IP アドレスとルートテーブルなどのネットワーク情報
ドメインとコンピュータ名
ライセンスの状態、Key Management Server (KMS) の構成などのアクティベーション設定
現在の時刻と時間帯などの時間設定
インスタンス上にインストールされたドライバ
セキュリティグループのルールに沿った Windows ファイアウォールの設定
インストールされた更新
Windows が 1 週間以内にクラッシュした場合のミニダンプファイル
  • 分析ルール
アクティベーションステータスと KMS 設定のチェック
メタデータと KMS アクセスに対する適切なルートテーブルエントリのチェック
セキュリティグループルールと Windows ファイアウォールルールの比較
PV ドライバのバージョン確認(Redhat または Citrix)
RealTimesUniversal レジストリキーが設定されているかの確認
複数の NIC を使用している場合のデフォルトゲートウェイ設定
ミニダンプファイルのコードのバグチェック
  • 動かすのは非常に簡単で、こちらからダウンロードして、exeをクリックするだけです。credentialの入力を求められるますが、予めEC2にReadonlyのRoleを設定しておき利用すると良いでしょう。

10.0.0.117  2016-10-07 15-08-35.png

  • 「OpenReport」をクリックするとテキストでレポートが出力されます。Windowsがライセンスされてるか。SecurityGroupの設定とFirewallの設定が合致しているかなどです。
  • 収集されたデータは実行ディレクトリと同じディレクトリに出力されていました。
  • 10.0.0.117  2016-10-07 15-14-48.png

  • 参考

監視はどうやる?(Cloudwatch)

  • プロセス、パフォーマンス

    • パフォーマンスカウンタで取得したデータをCloudWatchにメトリクスとして登録することが出来ます。パフォーマンスカウンタを利用すると大体のデータは取れるのでpowershellでcloudwatchにput-metricsする必要は無いです。
    • ただし、すべてカスタムメトリクスになるのでガンガン登録するとそれだけコストがかかります。監視するものはカスタムメトリクスとして登録、後々みれれば良いものはパフォーマンスカウンタとして取得しておくよう選別しておこう。
  • ログ
    • イベントログ含め、任意のログデータをEC2Configを利用することでCloudWatchLogsに取り込むことが出来ます。
  • 監視

    • CloudWatchのカスタムメトリクス、CloudWatchLogsに取り込めればこちらのものですね。Cloudwatchの標準機能を使って通知まで実現出来そうですね。
  • パフォーマンスカウンタのデータや、ログをCloudWatch,CloudWatchLogsに取り込む手順は以下の通りです。

共通の設定(CloudWatch Logs の認証情報、リージョン、ロググループ、ログストリームを設定)

  • EC2インスタンスにCloudwatch,CloudwatchLogsにアクセスするためのロールを付与します。
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "cloudwatch:*",
        "logs:*"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}
  • EC2Configの設定を開きます。

C:¥Program Files¥Amazon¥Ec2ConfigService¥Ec2ConfigServiceSettings.exe

  • [Cloudwatch Logs] – [Enable CloudWatchLogs Integration]にチェックを入れます。

10.0.0.117  2016-10-07 15-27-36.png

  • 下記の設定ファイル内のリージョンを変更しておきます。今回は東京(ap-northeast-1)にしてあります。
  • ロールの設定が行われている場合は、AccessKey,SecretKeyは無視されるので空のままで良いです。

C:\Program Files\Amazon\Ec2ConfigService\Settings\AWS.EC2.Windows.CloudWatch.json

AWS.EC2.Windows.CloudWatch.json
            {
                "Id": "CloudWatchLogs",
                "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatchLogsOutput,AWS.EC2.Windows.CloudWatch",
                "Parameters": {
                    "AccessKey": "",
                    "SecretKey": "",
                    "Region": "ap-northeast-1",
                    "LogGroup": "Default-Log-Group",
                    "LogStream": "{instance_id}"
                }
            },
            {
                "Id": "CloudWatch",
                "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatch.CloudWatchOutputComponent,AWS.EC2.Windows.CloudWatch",
                "Parameters": 
                {
                    "AccessKey": "",
                    "SecretKey": "",
                    "Region": "ap-northeast-1",
                    "NameSpace": "Windows/Default"
                }
            }
  • ここまでで事前の設定はおしまいです。

イベントログをCloudWatchLogsでみえるようにしてみます

  • このあたりがイベントログの設定になります。
AWS.EC2.Windows.CloudWatch.json
{
    "EngineConfiguration": {
        "PollInterval": "00:00:15",
        "Components": [
            {
                "Id": "ApplicationEventLog",
                "FullName": "AWS.EC2.Windows.CloudWatch.EventLog.EventLogInputComponent,AWS.EC2.Windows.CloudWatch",
                "Parameters": {
                    "LogName": "Application",
                    "Levels": "1"
                }
            },
            {
                "Id": "SystemEventLog",
                "FullName": "AWS.EC2.Windows.CloudWatch.EventLog.EventLogInputComponent,AWS.EC2.Windows.CloudWatch",
                "Parameters": {
                    "LogName": "System",
                    "Levels": "7"
                }
            },
            {
                "Id": "SecurityEventLog",
                "FullName": "AWS.EC2.Windows.CloudWatch.EventLog.EventLogInputComponent,AWS.EC2.Windows.CloudWatch",
                "Parameters": {
                "LogName": "Security",
                "Levels": "7"
                }
            },
  • イベントログをCloudWatchLogsに出力するには、IdをFlows加えてあげれば良いです。今回はSecurityEventLogを出力するように追記してみました。
AWS.EC2.Windows.CloudWatch.json
        "Flows": {
            "Flows": 
            [
                "(ApplicationEventLog,SecurityEventLog,SystemEventLog),CloudWatchLogs"
            ]
        }
  • EC2Configを再起動して少し待つとCloudWatchLogsにログが出力されました。

CloudWatch Management Console 2016-10-07 16-52-29.png

パフォーマンスカウンタのデータをCloudWatchカスタムメトリクスに表示してみよう

  • この設定はAvailable MBytesをパフォーマンスカウンタから抽出してCloudWatchのカスタムメトリクスに名前空間Windows/Defaultの中にMemoryというメトリクスを追加しています。
AWS.EC2.Windows.CloudWatch.抜粋.json
            {
                "Id": "PerformanceCounter",
                "FullName": "AWS.EC2.Windows.CloudWatch.PerformanceCounterComponent.PerformanceCounterInputComponent,AWS.EC2.Windows.CloudWatch",
                "Parameters": {
                    "CategoryName": "Memory",
                    "CounterName": "Available MBytes",
                    "InstanceName": "",
                    "MetricName": "Memory",
                    "Unit": "Megabytes",
                    "DimensionName": "",
                    "DimensionValue": ""
                }
            },
・・・
            {
                "Id": "CloudWatch",
                "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatch.CloudWatchOutputComponent,AWS.EC2.Windows.CloudWatch",
                "Parameters": 
                {
                    "AccessKey": "",
                    "SecretKey": "",
                    "Region": "ap-northeast-1",
                    "NameSpace": "Windows/Default"
                }
            }
・・・
        "Flows": {
            "Flows": 
            [
                "(ApplicationEventLog,SecurityEventLog,SystemEventLog),CloudWatchLogs",
                "(PerformanceCounter),CloudWatch"
            ]
        }
  • これも設定後再起動すると、このようにメモリがカスタムメトリクスに表示できます。

CloudWatch Management Console 2016-10-07 17-00-16.png

  • いやー便利ですね。

CloudWatchのメトリクスデータの保管

  • CloudWatchのメトリクスは2週間経つと自動で消えてしまいます。
  • 2週間より大きい期間のデータの保管が必要な場合は、定期的にAPIを使ってローカルに落としておくなどの工夫が必要。

CloudWatchLogsの保管期間を決めておこう

  • CloudWatchLogsも勿論お金が掛かります。
  • CloudWatchLogsのログの保管期間はデフォルトで無制限なので変更しておきましょう。
  • 参考

RunCommandの活用検討及び利用準備はしておく。

  • RunCommandはWindows,Linux共にEC2にログインせずともコマンドが実行できる機能
  • Windowsの場合はEc2Configが入っているのでOS側にエージェントのインストールは不要。
  • Javaのアプリケーションを運用していた場合、事前に準備さえしておけばJavaのThreadDumpもOSにログインしないで実行することができるわけです。
デフォルトで利用できるRunCommand
AWS-JoinDirectoryServiceDomain to join an AWS Directory
AWS-RunPowerShellScript to run PowerShell commands or scripts
AWS-UpdateEC2Config to update the EC2Config service
AWS-ConfigureWindowsUpdate to configure Windows Update settings
AWS-InstallApplication to install, repair, or uninstall software using an MSI package
AWS-InstallPowerShellModule to install PowerShell modules
AWS-ConfigureCloudWatch to configure Amazon CloudWatch Logs to monitor applications and systems
AWS-ListWindowsInventory to collect information about an EC2 instance running in Windows.
AWS-FindWindowsUpdates to scan an instance and determines which updates are missing.
AWS-InstallMissingWindowsUpdates to install missing updates on your EC2 instance.
AWS-InstallSpecificWindowsUpdates to install one or more specific updates.
  • 事前に利用できないかは検討しておこう。利用しない場合でも動かせるように準備はしておいた方が良いと思う。
  • RunCommandが利用できる条件は「RunCommandの前提条件」を参照。

おわりに

  • どうでしょうか。結構色々ありますね。何かあったときに慌てないようにNATやロールの設定は予め考えておきたいですね。

続きを読む

AWSアカウント取得後、はやる気持ちをグッと堪えてまずやっておくこと

はじめに

  • 認証に必要な情報は不正利用されてしまうと、大事故(ものすごい請求額)に繋がります。
  • 事故がおきないようにどうするべきか。予兆をどう検知するか。おきてしまった時にどう追跡するのか。を考えておく必要があります。
  • AWSのサービスを早速バリバリ使ってみるぜ!という気持ちをぐっとこらえてやっておきたい設定をリストアップしました。
  • 新しいAWSアカウントを利用する機会があったので、この記事を書きながらやってみましたが長めにみても30分あれば設定は終わります。

ルートアカウントのMFAの有効化

  • rootアカウントは超強力なので絶対にMFAを有効にすること。
  • ハードウェアデバイスで実施し、金庫に保管するくらいの勢いが良いと思います。
  • ハードウェアデバイスは$20くらいで購入が可能です。参考:Multi-Factor Authentication
  • 最低でも仮想MFAを設定しておきましょう。私がいつも使っているのはIIJのSmartKeyです。他にもGoogleAuthenticatorなどもあります。

IAMパスワードポリシーの有効化

  • 所属する組織に合わせてパスワードポリシーを必ず設定すること。
  • ポリシーでは設定できませんが、アカウント作成時にMFAを必須にすることを運用ルールとしました。

cloudtrailの有効化

  • 証跡を残すために行う。全リージョンで必ず設定すること。
  • S3に保管されたログが改竄されていないことも保証できるので合わせて有効化しておくこと。
  1. s3にバケットを作成する(trailxxxx)
  2. プロパティからライフサイクルの設定を行う(底冗長化、Glacier,完全に削除どれにするかはお好みで。とりあえず90日で削除のポリシーとした)
  3. CloudTrailの設定
  4. 「すべてのリージョンに適用」「ログファイルの検証を有効化」
  5. S3のバケットを確認し、証跡が取得できていること。

IAMユーザの作成

  • コンソール用、API用は別に分けて作成する。
  • APIでアクセスキー・シークレットアクセスキーを利用する場合、本当に必要か?代替できないか?を確認すること(ロールを使ってSTSで認証情報を取得できないかなど。)
  • 付与するロールを最小限にしたグループの作成
  • ユーザの作成、およびグループへの所属
  • CloudTrailでの証跡取得が無意味になるのでユーザは最低必ず1人1アカウント発行すること。
  • パスワードの設定(次回ログイン時に再設定してもらうようにしてます)
  • MFAの設定

請求関連

設定

*「請求とコスト管理」から「電子メールでPDF版請求書を受け取る」「請求アラートを受け取る」にチェックして「設定の保存」

電子メールでPDF版請求書を受け取る

  • rootアカウントに紐づくメールアドレスにしか飛ばせないので、必要であれば関係者が受け取るメーリングリストに変えておく。

請求アラート(Billing Alert)を設定する

  • 今回はt2.small×2,Lambda,SWF,RDB,ELB,S3程度なので$100を下回るはず
  • 80$でアラートを設定しておきました。

1.「バージニア北部」のリージョンを選択し、CloudWatch – 請求を選択
2. アラームを作成する
3. 超過金額と通知先メールアドレスを設定すると、メールでのSubscriptionを求められるのでConfirmすることでアラートが設定できる。


TrustedAdvisorの通知設定

  • ビジネスサポート以上じゃないとすべてのチェックは利用できない。
  • ただし、TrustedAdvisorの指摘は守るべきことばかりだし、定期的に自力でチェックするのは大変なものが多くこれだけでもサポートにお金を払う価値がある。
  • どうしても守れないルールなどがあれば、必要に応じて除外設定を行い、常にすべてクリアにしておく状態に保つこと。知っていて無視することと知らないということは別物。
  • 通知先のアドレスはアカウントに紐付くメールアドレスのみ。

続きを読む

AWS SimpleWorkflowでLambdaを使って、Activityの運用から解放されたい!

はじめに

  • AWS SWFご存知でしょうか。大体の人が名前は知ってるけど触ったことがないという反応が返ってきます。(SWF使いどころたくさんあるんだけど、やっぱり流行らないのかなー(涙))
  • SWFとFlowFramework(Java or Ruby)というライブラリを利用することで簡単に(?)ワークフローを実現することができる凄いサービスなんです。
  • この記事はSWFのActivityにLambdaを使って幸せになろうぜという記事です。

  • Lambdaは人気があって記事もたくさんあるのですが、SWFは始めのとっつきにくさからか、周りに使ってる人が見つけられず、ネット上でも日本語の情報源が非常に少ないのです。なので少し普及に貢献してみようと思います。(普及に貢献したい人、一緒に勉強会でもしましょう)

SWFの基礎的な話

  • SWFの概要を理解するにはまずはこちらの資料をご覧ください。
  • この資料を見てわかるようにAWS SWFでは大きく4人の登場人物が出てきます。

Cacoo - SWF 2016-04-01 10-12-44.png

  • Client(Executor) ・・・ workflowをキックする人です。オンプレミス側からSWFのEndpointに接続してワークフローを起動します。
  • SWF・・・SWFはクライアントからの実行の要求を受付けワークフローのキューの管理をしてくれます。
  • Desider・・・SWFのキュー(ドメイン・タスクリスト)を監視しながらワークフローを進める人です。ただタスクを管理するだけで実際の処理は行いません。SWFのエンドポイントからつながるのであればEC2でもよいですし、オンプレミスのサーバを使っても構いません。
  • Activity・・・Desiderから振られた処理を実行する人です。ステートレスに実行します。ActivityもSWFのエンドポイントからつながるのであればEC2でもよいですし、オンプレミスのサーバを使っても構いません。
  • Activityにはステートレスで、処理時間がかかり負荷がかかるものが実装されるため、実際に運用していくとなるとActivityをスケールアウトしていく運用になると思います。

さて本題

  • SWFを中心とした疎結合なアーキテクチャなので、Activityをスケールアウトしていくことで負荷に対応していくことができます。
  • 自動スケールアウトするにはActivityのインスタンスをAutoScalingGroupに登録させればよいでしょう。それすら面倒ならElasticBeansTalkにお任せしましょう。それすらも面倒だ、もっと安く運用したいんだったらLamdaなんじゃないかなと思うわけです。
  • Lambdaを使ったアーキテクチャは以下のようになります。
  • Cacoo - SWF 2016-04-01 10-24-20.png
  • Activityの部分がLambdaになっただけですが、Activityの運用から解き放たれると思うとこんなに嬉しいことはありません。
  • 早速実装方法を見ていきます。(LambdaFunctionの登録は通常Lambdaを利用するときと変わらないので割愛します。)

シンプルに呼び出す

DesiderからLambdaを呼び出す方法

  • SWFに付属しているサンプルではLambdaFunctionへ呼びっぱなしですが、ここではLambdaを実行した結果を待つ形にしてみました。
    @Override
    public void hello(String name) throws Exception {

        task = new TryCatchFinally() {

            @Override
            protected void doTry() throws Throwable {
                ConfigHelper configHelper = ConfigHelper.createConfig();
                DecisionContextProvider decisionProvider =
                        new DecisionContextProviderImpl();

                DecisionContext decisionContext = decisionProvider.getDecisionContext();
                LambdaFunctionClient lambdaClient =
                        decisionContext.getLambdaFunctionClient();

                // lambdaの引数はjson
                Promise<String> val = lambdaClient.scheduleLambdaFunction(
                        configHelper.getSwfLambdaFunction(), """ + name + """, 30);
                // lambda functionの呼び出しが終わるまで待つ
                processResult(val);

            }

            @Override
            protected void doCatch(Throwable e) throws Throwable {
                logger.error("catch exception", e);
                // 例外処理
                throw e;
            }

            @Override
            protected void doFinally() throws Throwable {
                // noop
            }
        };
    }

    @Asynchronous
    private void processResult(Promise<String> lambdaClientResult) {
        System.out.println("ready[" + LocalTime.now() + "] lambda return value["
                + lambdaClientResult.get() + "]");
    }
}
  • scheduleLambdaFunctionの第一引数はLambdaFunction名、第二引数はLambdaFunctionへの引数(jsonのみ)、第三引数はtimeoutの時間になります。
  • LambdaFunctionを実行した結果がPromiseで取れますので、これをAsynchronousメソッドに渡すことでLambdaFunctionの実行を待って結果を出力することができます。

リトライ処理

自前のActivityの場合

  • 通常のActivityであればリトライするには以下のようにアノテーションをActivityに付与すれば簡単に実現できるわけです。
  • ちなみに以下の設定は5秒,10秒,20秒とリトライしてくれます。
@ExponentialRetry(initialRetryIntervalSeconds = 5, maximumAttempts = 3)
public String hello(String str);

LambdaFunctionをActivityにした場合

  • LambdaFunction側にアノテーションが使えないのでDesider側でなんとかする必要がありそうです。
  • ここで登場するのがExponentialRetryPolicyとRetryDecoratorです。
  • ExponentialRetryPolicyでポリシーを決めて、RetryDecorator経由LambdaFunctionClientのインスタンスを入手することで実現できます。
                long initialRetryIntervalSeconds = 5;
                int maximumAttempts = 5;
                List<Class<? extends Throwable>> exceptionsToRetry = new ArrayList<>();
                exceptionsToRetry.add(RuntimeException.class);
                ExponentialRetryPolicy retryPolicy =
                        new ExponentialRetryPolicy(initialRetryIntervalSeconds)
                                .withMaximumAttempts(maximumAttempts)
                                .withExceptionsToRetry(exceptionsToRetry);
                Decorator retryDecorator = new RetryDecorator(retryPolicy);
                LambdaFunctionClient decoratedLambdaClient =
                        retryDecorator.decorate(LambdaFunctionClient.class, lambdaClient);
  • わかれば簡単ですけど気づけないですよねー

300秒の壁

  • AWS Lambda の制限
  • ちょっと前に300秒までLambdaの実行時間が延びましたが300秒を超える処理はどうやって実現したらよいでしょうか。(いや、そのまえに300秒超える処理どうなの?は一旦置いておきましょう)
  • そういう場合は、処理を投げた後に結果をポーリングさせるようなアーキテクチャにすると幸せになります。
  • Desider側ではDecisionContextからWorkflowClockというのが取れまして、WorkflowClockからcreateTimerして得られたPromiseをdesiderのメソッドの引数に上げてあげれば良いです。
  • 以下の例はRdsのSnapshot取得のAPIを叩いた後、snapshotがavairableになるのを待って処理を動かすサンプルです。
  • Functorの引数にPromiseを渡すことでそこまで処理を待たせることができるのと、pargeRdsSnapshotAfterPoolingにtimerを渡している部分がポイントですね。
    @Asynchronous
    private Promise<String> pargeRdsSnapshotAfterPooling(Promise<String> createRdsSnapshotResult,
            Promise<?>... waitForPromises) {

        // 中略

        LambdaFunctionClient lambdaClient = decisionContext.getLambdaFunctionClient();
        Promise<String> getRdsSnapshotStatusResult =
                lambdaClient.scheduleLambdaFunction("getRdsSnapshotStatus", parameter, 60);

        return new Functor<String>(getRdsSnapshotStatusResult) {
            @Override
            protected Promise<String> doExecute() throws Throwable {
                String rdsSnapshotStatus =
                        CmpWorkflowUtils.getActivityResult(getRdsSnapshotStatusResult.get());
                if ("available".equals(rdsSnapshotStatus)) {
                    return pargeRdsSnapshot();
                }
                int retryPeriod = 10;
                Promise<Void> timer = clock.createTimer(retryPeriod);
                return pargeRdsSnapshotAfterPooling(createRdsSnapshotResult, timer);
            }
        };
    }

まとめ

  • ということでSWFのLambdaを使うとActivityの運用から解放されて幸せになれるかもね。という記事でした。
  • サンプルは以下に置いてあります。上記の他、LambdaをCronで実行するサンプルも作って見ました。
    https://github.com/uzresk/aws-swf-lambda-samples

続きを読む

毎回5分かけてたAWS Lambdaへのデプロイを20秒にしよう

AWS LambdaのデプロイをJenkinsで自動化しようぜ。という記事です。

はじめに

  • 今回も小ネタ。
  • はじめはHelloWorldで遊んでいても、複雑なものを作り始めると繰り返しFunctionの再登録をしたくなるわけですが、AWSのマネジメントコンソールからjarをアップロードしてFuctionの再登録する手間が面倒になってくるわけです。
  • また、気付いたら依存ライブラリが多くなってしまい5MBくらいのjarになったあたりからアップロードするまでの時間がかかりすぎて段々イライラしてきます。
  • ということでJenkinsを使ってLambdaFunctionを自動登録する方法をご紹介します。Jenkinsになれた人なら30分くらいあればできると思います。

処理の流れ

  1. BitBucketへのコミット
  2. BitBucketのweb hookでJenkinsのビルド起動
  3. ビルド(Jenkins)
  4. S3へのjarのアップロード(Jenkins)
  5. S3からLambdaFunctionの登録(Jenkins)

私の環境では上記のような感じで稼働していますが、webhookとかそんなに目新しい話でもないので4と5についてご紹介します。

前準備

  • S3へのファイルアップロードもS3からLambdaへのFunction登録もAWS上のJenkinsから行います。
  • S3とLambdaへのアクセスするときにアクセスキーとシークレットアクセスキーは使いません。
  • 代わりにInstanceProfileを利用しますので事前にJenkinsが稼働するEC2のインスタンスに対してS3とLambdaにアクセスできる権限をIAM Roleで付与しておいてください。

S3へのjarのアップロード

  • S3プラグインを使うことでビルド後にできたjarファイルをS3にアップロードしてくれます。
  • [Jenkinsの管理] – [システムの設定] – [Amazon S3 profile]に以下のように設定します。

システムの設定 [Jenkins] 2016-03-14 15-00-27.png

  • Jenkinsのビルド設定画面で[ビルド後の処理の追加] – [Publish artifacts to S3 bucket]をクリックして以下にならって設定します。

2.cmp-activity Config [Jenkins] 2016-03-14 15-21-11.png

  • これで設定は完了です。超簡単ですね。

S3からLambdaFunctionの登録

  • AWS Lambda Pluginを使用します。
  • S3に登録されたモジュールを取得してLambdaFunctionに登録してくれるプラグインです。
  • Jenkinsのビルド設置画面で[ビルド後の処理の追加] – [AWS Lambda Deployment]をクリックします。
  • 設定の内容はAWSのマネジメントコンソールでの設定と変わりませんが注意点はロール名でして、ARNで記載する必要があります。また、LambdaのVPN対応も行われていまして、[高度な設定]をクリックするとVPCとSecurityGroupを登録することができます。

2.cmp-activity Config [Jenkins] 2016-03-14 15-14-05.png

Lambda Functionが更新されているのか?

  • 実はマネジメントコンソールからだと更新されているかどうかがよくわかりません。
  • そういう場合はaws cliを使ってfunctionのLast Modifiedを見てあげるとか、Descriptionにビルド時間を入れてあげると良いと思います。
  • ちなみにLastModifiedは以下のようなコマンドでみることができます。
[ec2-user@ip-10-0-1-26 target]$ aws lambda get-function --function-name Ec2InstanceState --region ap-northeast-1 | jq
{
  "Code": {
    "RepositoryType": "S3",
    "Location": "https://xxxxxx"
  },
  "Configuration": {
    "FunctionName": "Ec2InstanceState",
    "MemorySize": 512,
    "CodeSize": 8802205,
    "FunctionArn": "arn:aws:lambda:ap-northeast-1:194851312534:function:Ec2InstanceState",
    "Handler": "jp.gr.java_conf.uzresk.cmp.activity.aws.ec2.Ec2InstanceActivity::xxxx",
    "Role": "arn:aws:iam::123456789012:role/LambdaFunction",
    "Timeout": 300,
    "LastModified": "2016-03-14T06:09:37.885+0000",
    "Runtime": "java8",
    "Description": "getting ec2 instance status"
  }
}

まとめ

  • 1 Function入れ替えるのに5分くらいかかっていたのが20秒で済むようになりました。
  • 私が使っているLambdaFunctionはせいぜい10個〜20個程度なのでいちいち設定すれば良いのですが、たくさんになった場合は再考が必要ですね。ということで小ネタでした。

続きを読む

AWS SES(送信)でトラブルを起こす前に気をつけておきたいこと

はじめに

  • AWS SES(simple email service)を使うときに監視したい項目と監視手段についてまとめてみました。
  • CloudWatchのカスタムメトリクスに登録するときのツールを用意しましたので参考にどうぞ – github/uzresk/cloudwatch-scripts
  • SESを使い始めるのは簡単ですが、1日の送信数、1秒あたりの送信数に制限があることと、信頼性の低いメールを送信し続けると利用停止になる可能性があります。そうなっては手遅れですのでCloudWatchなどを使って定期的に監視&アラートを設定しておきましょう。

SESとは?

  • SESとはSimple Email Serviceの略で、メールを送受信できるようにするためのマネージドサービスです。
  • 送信の場合、SMTPサーバとして使うこともできますし、aws cli/sdkを使ってメール送信することもできます。
  • 特に申請しなければ認証されたメールアドレスにしかメールを送信することはできません。(Sandbox状態)、不特定多数にメールを送信する場合はRequestProductionAccessにする必要があります。

認証

SESの制限

  • SESを使ってのメール送信では送信クォータと最大送信レートという二つの制限があります。この制限を超えてしまうとメールが送れなくなってしまいますので、送信制限を解除したり制限を超えていないかを監視しておく必要があります。
  • 送信クォータ・・・24時間当たりに送信できるEメールの最大数
  • 最大送信レート・・・Amazon SES が 1 秒あたりにアカウントから受け付けるEメールの最大数
  • 不足する場合は、制限の解除を行うことができます。→こちら
  • SESの制限についてはこちらにまとまっています。

送信クォータと最大送信レートをCloudwatchで監視する

[root@ip-10-0-10-184 cloudwatch_scripts]# crontab -l
*/5 * * * * /bin/bash /home/ec2-user/cloudwatch_scripts/ses_sending_limits.sh
  • メトリクスがうまく取得できていれば/var/log/messagesに以下のメッセージが表示されます。
Feb 22 02:00:03 ip-10-0-10-184 root: cloudwatch put-metrics-data SES SentLast24hours:29 MaxSendRate:14
  • 問題なく動けばCloudwatchカスタムメトリクスに登録されるのでダッシュボードへ保存とアラートの設定を行います。

バウンス

  • バウンス率とは簡単にいうとメールが届かなかった割合のことです。このバウンス率が多いとAWSから配信停止のお知らせ。なんてものが届いた結果メールが送れなくなる可能性があるので十分注意が必要です。
  • バウンス率は5%以下になっていることが望ましいとのことです。
  • バウンス率を計算する範囲というのは決まっておらず、get-send-statisticsで取得される値より大きい範囲が指定されることもあるとのことです。
  • また一時的なエラー(例えばメールボックスが一杯)や検証済みドメインに対してはバウンスとしてカウントされないとのことです。
  • ということでバウンス率も定期的にCloudWatchで監視し、送信数の3%くらいバウンスが溜まってきたらアラートを上げるような仕組みを入れておいたほうがよさそうです。

苦情

  • 苦情とは受取人がEメールの受け取りを希望していない場合に発生するもので、Eメールクライアントで “これはスパムです” などのボタンをクリックした、E メールプロバイダーに苦情を報告した、Amazon SES ディレクトリに通知した、またはその他の方法を使用した可能性のことを指します。
  • 苦情率とは送信数に対する割合で、1%以下となることが望まれるようです。
  • こちらも定期的な監視が必要になる事項です。

バウンス数、苦情数の取得とCloudWatchへの取り込み

  • aws cliのget-send-statisticsを使えば取得することができます。
  • CloudWatchのカスタムメトリクスとして定期的に取得するshを作りました。
  • cloudwatch-scripts/ses_statistics.shをcronに登録します。
  • get-send-statisticsは15分おきにデータを取得し2週間保持しますのでcronの間隔は15分間隔でよいでしょう。
[root@ip-10-0-10-184 cloudwatch_scripts]# crontab -l
*/15 * * * * /bin/bash /home/ec2-user/cloudwatch_scripts/ses_statistics.sh
[root@ip-10-0-10-184 cloudwatch_scripts]# 
  • メトリクスがうまく取得できていれば/var/log/messagesに以下のメッセージが表示されます。
Feb 22 02:00:04 ip-10-0-10-184 root: cloudwatch put-metrics-data SES Bounces:0 Complaints:0
  • 問題なく動けばCloudwatchカスタムメトリクスに登録されるのでダッシュボードへ保存とアラートの設定を行います。

バウンス、苦情数増加への対策

  • バウンスに関しては、バウンスが発生したメールアドレスには二度と送信しないように定期的なクリーニングを行うとよいでしょう。
  • バウンスの通知についてはこちら。バウンスが発生したときにSNS通知することなんかもできますね。
  • 苦情数の増加に関しての対策は難しいのですが、質の良いコンテンツを提供し続けることがベストな対策だと思われます。

参考

続きを読む